Merge pull request #18432 from Veykril/lw-yptzmuxyvxxt

fix: Fix the server not honoring diagnostic refresh support
diff --git a/Cargo.lock b/Cargo.lock
index 4d54b5a..f0e035c 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4029,6 +4029,7 @@
  "rustc_hir",
  "rustc_hir_pretty",
  "rustc_index",
+ "rustc_lint_defs",
  "rustc_macros",
  "rustc_query_system",
  "rustc_serialize",
@@ -4495,6 +4496,7 @@
 version = "0.0.0"
 dependencies = [
  "itertools",
+ "rustc_abi",
  "rustc_ast_ir",
  "rustc_data_structures",
  "rustc_hir",
@@ -4502,7 +4504,6 @@
  "rustc_macros",
  "rustc_middle",
  "rustc_span",
- "rustc_target",
  "tracing",
 ]
 
diff --git a/RELEASES.md b/RELEASES.md
index ac72a1d..40ddba6 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -68,15 +68,15 @@
 - [`impl Default for std::collections::vec_deque::Iter`](https://doc.rust-lang.org/nightly/std/collections/vec_deque/struct.Iter.html#impl-Default-for-Iter%3C'_,+T%3E)
 - [`impl Default for std::collections::vec_deque::IterMut`](https://doc.rust-lang.org/nightly/std/collections/vec_deque/struct.IterMut.html#impl-Default-for-IterMut%3C'_,+T%3E)
 - [`Rc<T>::new_uninit`](https://doc.rust-lang.org/nightly/std/rc/struct.Rc.html#method.new_uninit)
-- [`Rc<T>::assume_init`](https://doc.rust-lang.org/nightly/std/rc/struct.Rc.html#method.assume_init)
+- [`Rc<MaybeUninit<T>>::assume_init`](https://doc.rust-lang.org/nightly/std/rc/struct.Rc.html#method.assume_init)
 - [`Rc<[T]>::new_uninit_slice`](https://doc.rust-lang.org/nightly/std/rc/struct.Rc.html#method.new_uninit_slice)
 - [`Rc<[MaybeUninit<T>]>::assume_init`](https://doc.rust-lang.org/nightly/std/rc/struct.Rc.html#method.assume_init-1)
 - [`Arc<T>::new_uninit`](https://doc.rust-lang.org/nightly/std/sync/struct.Arc.html#method.new_uninit)
-- [`Arc<T>::assume_init`](https://doc.rust-lang.org/nightly/std/sync/struct.Arc.html#method.assume_init)
+- [`Arc<MaybeUninit<T>>::assume_init`](https://doc.rust-lang.org/nightly/std/sync/struct.Arc.html#method.assume_init)
 - [`Arc<[T]>::new_uninit_slice`](https://doc.rust-lang.org/nightly/std/sync/struct.Arc.html#method.new_uninit_slice)
 - [`Arc<[MaybeUninit<T>]>::assume_init`](https://doc.rust-lang.org/nightly/std/sync/struct.Arc.html#method.assume_init-1)
 - [`Box<T>::new_uninit`](https://doc.rust-lang.org/nightly/std/boxed/struct.Box.html#method.new_uninit)
-- [`Box<T>::assume_init`](https://doc.rust-lang.org/nightly/std/boxed/struct.Box.html#method.assume_init)
+- [`Box<MaybeUninit<T>>::assume_init`](https://doc.rust-lang.org/nightly/std/boxed/struct.Box.html#method.assume_init)
 - [`Box<[T]>::new_uninit_slice`](https://doc.rust-lang.org/nightly/std/boxed/struct.Box.html#method.new_uninit_slice)
 - [`Box<[MaybeUninit<T>]>::assume_init`](https://doc.rust-lang.org/nightly/std/boxed/struct.Box.html#method.assume_init-1)
 - [`core::arch::x86_64::_bextri_u64`](https://doc.rust-lang.org/stable/core/arch/x86_64/fn._bextri_u64.html)
diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs
index 0340d1b..141a15b 100644
--- a/compiler/rustc_abi/src/layout.rs
+++ b/compiler/rustc_abi/src/layout.rs
@@ -7,7 +7,7 @@
 
 use crate::{
     Abi, AbiAndPrefAlign, Align, FieldsShape, HasDataLayout, IndexSlice, IndexVec, Integer,
-    LayoutS, Niche, NonZeroUsize, Primitive, ReprOptions, Scalar, Size, StructKind, TagEncoding,
+    LayoutData, Niche, NonZeroUsize, Primitive, ReprOptions, Scalar, Size, StructKind, TagEncoding,
     Variants, WrappingRange,
 };
 
@@ -26,7 +26,7 @@
 where
     FieldIdx: Idx,
     VariantIdx: Idx,
-    F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug,
+    F: Deref<Target = &'a LayoutData<FieldIdx, VariantIdx>> + fmt::Debug,
 {
     let uninhabited = fields.iter().any(|f| f.abi.is_uninhabited());
     // We cannot ignore alignment; that might lead us to entirely discard a variant and
@@ -89,7 +89,7 @@
 }
 
 type LayoutCalculatorResult<FieldIdx, VariantIdx, F> =
-    Result<LayoutS<FieldIdx, VariantIdx>, LayoutCalculatorError<F>>;
+    Result<LayoutData<FieldIdx, VariantIdx>, LayoutCalculatorError<F>>;
 
 #[derive(Clone, Copy, Debug)]
 pub struct LayoutCalculator<Cx> {
@@ -105,7 +105,7 @@
         &self,
         a: Scalar,
         b: Scalar,
-    ) -> LayoutS<FieldIdx, VariantIdx> {
+    ) -> LayoutData<FieldIdx, VariantIdx> {
         let dl = self.cx.data_layout();
         let b_align = b.align(dl);
         let align = a.align(dl).max(b_align).max(dl.aggregate_align);
@@ -119,7 +119,7 @@
             .chain(Niche::from_scalar(dl, Size::ZERO, a))
             .max_by_key(|niche| niche.available(dl));
 
-        LayoutS {
+        LayoutData {
             variants: Variants::Single { index: VariantIdx::new(0) },
             fields: FieldsShape::Arbitrary {
                 offsets: [Size::ZERO, b_offset].into(),
@@ -138,7 +138,7 @@
         'a,
         FieldIdx: Idx,
         VariantIdx: Idx,
-        F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug + Copy,
+        F: Deref<Target = &'a LayoutData<FieldIdx, VariantIdx>> + fmt::Debug + Copy,
     >(
         &self,
         fields: &IndexSlice<FieldIdx, F>,
@@ -211,9 +211,9 @@
 
     pub fn layout_of_never_type<FieldIdx: Idx, VariantIdx: Idx>(
         &self,
-    ) -> LayoutS<FieldIdx, VariantIdx> {
+    ) -> LayoutData<FieldIdx, VariantIdx> {
         let dl = self.cx.data_layout();
-        LayoutS {
+        LayoutData {
             variants: Variants::Single { index: VariantIdx::new(0) },
             fields: FieldsShape::Primitive,
             abi: Abi::Uninhabited,
@@ -229,7 +229,7 @@
         'a,
         FieldIdx: Idx,
         VariantIdx: Idx,
-        F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug + Copy,
+        F: Deref<Target = &'a LayoutData<FieldIdx, VariantIdx>> + fmt::Debug + Copy,
     >(
         &self,
         repr: &ReprOptions,
@@ -292,7 +292,7 @@
         'a,
         FieldIdx: Idx,
         VariantIdx: Idx,
-        F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug + Copy,
+        F: Deref<Target = &'a LayoutData<FieldIdx, VariantIdx>> + fmt::Debug + Copy,
     >(
         &self,
         repr: &ReprOptions,
@@ -384,7 +384,7 @@
             return Err(LayoutCalculatorError::EmptyUnion);
         };
 
-        Ok(LayoutS {
+        Ok(LayoutData {
             variants: Variants::Single { index: only_variant_idx },
             fields: FieldsShape::Union(union_field_count),
             abi,
@@ -401,7 +401,7 @@
         'a,
         FieldIdx: Idx,
         VariantIdx: Idx,
-        F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug + Copy,
+        F: Deref<Target = &'a LayoutData<FieldIdx, VariantIdx>> + fmt::Debug + Copy,
     >(
         &self,
         repr: &ReprOptions,
@@ -501,7 +501,7 @@
         'a,
         FieldIdx: Idx,
         VariantIdx: Idx,
-        F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug + Copy,
+        F: Deref<Target = &'a LayoutData<FieldIdx, VariantIdx>> + fmt::Debug + Copy,
     >(
         &self,
         repr: &ReprOptions,
@@ -516,8 +516,8 @@
         // overall LayoutS. Store the overall LayoutS
         // and the variant LayoutSs here until then.
         struct TmpLayout<FieldIdx: Idx, VariantIdx: Idx> {
-            layout: LayoutS<FieldIdx, VariantIdx>,
-            variants: IndexVec<VariantIdx, LayoutS<FieldIdx, VariantIdx>>,
+            layout: LayoutData<FieldIdx, VariantIdx>,
+            variants: IndexVec<VariantIdx, LayoutData<FieldIdx, VariantIdx>>,
         }
 
         let dl = self.cx.data_layout();
@@ -649,7 +649,7 @@
                 Abi::Aggregate { sized: true }
             };
 
-            let layout = LayoutS {
+            let layout = LayoutData {
                 variants: Variants::Multiple {
                     tag: niche_scalar,
                     tag_encoding: TagEncoding::Niche {
@@ -958,7 +958,7 @@
 
         let largest_niche = Niche::from_scalar(dl, Size::ZERO, tag);
 
-        let tagged_layout = LayoutS {
+        let tagged_layout = LayoutData {
             variants: Variants::Multiple {
                 tag,
                 tag_encoding: TagEncoding::Direct,
@@ -1013,7 +1013,7 @@
         'a,
         FieldIdx: Idx,
         VariantIdx: Idx,
-        F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug + Copy,
+        F: Deref<Target = &'a LayoutData<FieldIdx, VariantIdx>> + fmt::Debug + Copy,
     >(
         &self,
         fields: &IndexSlice<FieldIdx, F>,
@@ -1341,7 +1341,7 @@
             unadjusted_abi_align
         };
 
-        Ok(LayoutS {
+        Ok(LayoutData {
             variants: Variants::Single { index: VariantIdx::new(0) },
             fields: FieldsShape::Arbitrary { offsets, memory_index },
             abi,
@@ -1357,10 +1357,10 @@
         'a,
         FieldIdx: Idx,
         VariantIdx: Idx,
-        F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug,
+        F: Deref<Target = &'a LayoutData<FieldIdx, VariantIdx>> + fmt::Debug,
     >(
         &self,
-        layout: &LayoutS<FieldIdx, VariantIdx>,
+        layout: &LayoutData<FieldIdx, VariantIdx>,
         fields: &IndexSlice<FieldIdx, F>,
     ) -> String {
         let dl = self.cx.data_layout();
diff --git a/compiler/rustc_abi/src/layout/ty.rs b/compiler/rustc_abi/src/layout/ty.rs
index c6812c4..e029e14 100644
--- a/compiler/rustc_abi/src/layout/ty.rs
+++ b/compiler/rustc_abi/src/layout/ty.rs
@@ -58,7 +58,7 @@
 }
 #[derive(Copy, Clone, PartialEq, Eq, Hash, HashStable_Generic)]
 #[rustc_pass_by_value]
-pub struct Layout<'a>(pub Interned<'a, LayoutS<FieldIdx, VariantIdx>>);
+pub struct Layout<'a>(pub Interned<'a, LayoutData<FieldIdx, VariantIdx>>);
 
 impl<'a> fmt::Debug for Layout<'a> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -68,8 +68,8 @@
 }
 
 impl<'a> Deref for Layout<'a> {
-    type Target = &'a LayoutS<FieldIdx, VariantIdx>;
-    fn deref(&self) -> &&'a LayoutS<FieldIdx, VariantIdx> {
+    type Target = &'a LayoutData<FieldIdx, VariantIdx>;
+    fn deref(&self) -> &&'a LayoutData<FieldIdx, VariantIdx> {
         &self.0.0
     }
 }
@@ -142,8 +142,8 @@
 }
 
 impl<'a, Ty> Deref for TyAndLayout<'a, Ty> {
-    type Target = &'a LayoutS<FieldIdx, VariantIdx>;
-    fn deref(&self) -> &&'a LayoutS<FieldIdx, VariantIdx> {
+    type Target = &'a LayoutData<FieldIdx, VariantIdx>;
+    fn deref(&self) -> &&'a LayoutData<FieldIdx, VariantIdx> {
         &self.layout.0.0
     }
 }
diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs
index 8e90130..b54efa4 100644
--- a/compiler/rustc_abi/src/lib.rs
+++ b/compiler/rustc_abi/src/lib.rs
@@ -1485,7 +1485,7 @@
         tag: Scalar,
         tag_encoding: TagEncoding<VariantIdx>,
         tag_field: usize,
-        variants: IndexVec<VariantIdx, LayoutS<FieldIdx, VariantIdx>>,
+        variants: IndexVec<VariantIdx, LayoutData<FieldIdx, VariantIdx>>,
     },
 }
 
@@ -1603,7 +1603,7 @@
 // NOTE: This struct is generic over the FieldIdx and VariantIdx for rust-analyzer usage.
 #[derive(PartialEq, Eq, Hash, Clone)]
 #[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
-pub struct LayoutS<FieldIdx: Idx, VariantIdx: Idx> {
+pub struct LayoutData<FieldIdx: Idx, VariantIdx: Idx> {
     /// Says where the fields are located within the layout.
     pub fields: FieldsShape<FieldIdx>,
 
@@ -1643,7 +1643,7 @@
     pub unadjusted_abi_align: Align,
 }
 
-impl<FieldIdx: Idx, VariantIdx: Idx> LayoutS<FieldIdx, VariantIdx> {
+impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
     /// Returns `true` if this is an aggregate type (including a ScalarPair!)
     pub fn is_aggregate(&self) -> bool {
         match self.abi {
@@ -1656,7 +1656,7 @@
         let largest_niche = Niche::from_scalar(cx, Size::ZERO, scalar);
         let size = scalar.size(cx);
         let align = scalar.align(cx);
-        LayoutS {
+        LayoutData {
             variants: Variants::Single { index: VariantIdx::new(0) },
             fields: FieldsShape::Primitive,
             abi: Abi::Scalar(scalar),
@@ -1669,7 +1669,7 @@
     }
 }
 
-impl<FieldIdx: Idx, VariantIdx: Idx> fmt::Debug for LayoutS<FieldIdx, VariantIdx>
+impl<FieldIdx: Idx, VariantIdx: Idx> fmt::Debug for LayoutData<FieldIdx, VariantIdx>
 where
     FieldsShape<FieldIdx>: fmt::Debug,
     Variants<FieldIdx, VariantIdx>: fmt::Debug,
@@ -1678,7 +1678,7 @@
         // This is how `Layout` used to print before it become
         // `Interned<LayoutS>`. We print it like this to avoid having to update
         // expected output in a lot of tests.
-        let LayoutS {
+        let LayoutData {
             size,
             align,
             abi,
@@ -1723,7 +1723,7 @@
     pub safe: Option<PointerKind>,
 }
 
-impl<FieldIdx: Idx, VariantIdx: Idx> LayoutS<FieldIdx, VariantIdx> {
+impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
     /// Returns `true` if the layout corresponds to an unsized type.
     #[inline]
     pub fn is_unsized(&self) -> bool {
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 02cb6f1..8e4f4c8 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -2697,7 +2697,7 @@
 }
 
 /// The polarity of a trait bound.
-#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug, Hash)]
 #[derive(HashStable_Generic)]
 pub enum BoundPolarity {
     /// `Type: Trait`
@@ -2719,7 +2719,7 @@
 }
 
 /// The constness of a trait bound.
-#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug, Hash)]
 #[derive(HashStable_Generic)]
 pub enum BoundConstness {
     /// `Type: Trait`
diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs
index b73412a..9311af2 100644
--- a/compiler/rustc_ast/src/attr/mod.rs
+++ b/compiler/rustc_ast/src/attr/mod.rs
@@ -223,7 +223,7 @@
         self.args.span().map_or(self.path.span, |args_span| self.path.span.to(args_span))
     }
 
-    fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>> {
+    pub fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>> {
         match &self.args {
             AttrArgs::Delimited(args) if args.delim == Delimiter::Parenthesis => {
                 MetaItemKind::list_from_tokens(args.tokens.clone())
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index 207ec71..eb71ec5 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -135,7 +135,7 @@
     /// or `ControlFlow<T>`.
     type Result: VisitorResult = ();
 
-    fn visit_ident(&mut self, _ident: Ident) -> Self::Result {
+    fn visit_ident(&mut self, _ident: &'ast Ident) -> Self::Result {
         Self::Result::output()
     }
     fn visit_foreign_item(&mut self, i: &'ast ForeignItem) -> Self::Result {
@@ -173,9 +173,6 @@
     fn visit_method_receiver_expr(&mut self, ex: &'ast Expr) -> Self::Result {
         self.visit_expr(ex)
     }
-    fn visit_expr_post(&mut self, _ex: &'ast Expr) -> Self::Result {
-        Self::Result::output()
-    }
     fn visit_ty(&mut self, t: &'ast Ty) -> Self::Result {
         walk_ty(self, t)
     }
@@ -317,12 +314,12 @@
 }
 
 pub fn walk_label<'a, V: Visitor<'a>>(visitor: &mut V, Label { ident }: &'a Label) -> V::Result {
-    visitor.visit_ident(*ident)
+    visitor.visit_ident(ident)
 }
 
 pub fn walk_lifetime<'a, V: Visitor<'a>>(visitor: &mut V, lifetime: &'a Lifetime) -> V::Result {
     let Lifetime { id: _, ident } = lifetime;
-    visitor.visit_ident(*ident)
+    visitor.visit_ident(ident)
 }
 
 pub fn walk_poly_trait_ref<'a, V>(visitor: &mut V, trait_ref: &'a PolyTraitRef) -> V::Result
@@ -429,7 +426,7 @@
             }) => {
                 try_visit!(walk_qself(visitor, qself));
                 try_visit!(visitor.visit_path(path, *id));
-                visit_opt!(visitor, visit_ident, *rename);
+                visit_opt!(visitor, visit_ident, rename);
                 visit_opt!(visitor, visit_block, body);
             }
             ItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => {
@@ -437,9 +434,9 @@
                 try_visit!(visitor.visit_path(prefix, *id));
                 if let Some(suffixes) = suffixes {
                     for (ident, rename) in suffixes {
-                        visitor.visit_ident(*ident);
+                        visitor.visit_ident(ident);
                         if let Some(rename) = rename {
-                            visitor.visit_ident(*rename);
+                            visitor.visit_ident(rename);
                         }
                     }
                 }
@@ -472,7 +469,7 @@
     let Variant { attrs, id: _, span: _, vis, ident, data, disr_expr, is_placeholder: _ } = variant;
     walk_list!(visitor, visit_attribute, attrs);
     try_visit!(visitor.visit_vis(vis));
-    try_visit!(visitor.visit_ident(*ident));
+    try_visit!(visitor.visit_ident(ident));
     try_visit!(visitor.visit_variant_data(data));
     visit_opt!(visitor, visit_variant_discr, disr_expr);
     V::Result::output()
@@ -481,7 +478,7 @@
 pub fn walk_expr_field<'a, V: Visitor<'a>>(visitor: &mut V, f: &'a ExprField) -> V::Result {
     let ExprField { attrs, id: _, span: _, ident, expr, is_shorthand: _, is_placeholder: _ } = f;
     walk_list!(visitor, visit_attribute, attrs);
-    try_visit!(visitor.visit_ident(*ident));
+    try_visit!(visitor.visit_ident(ident));
     try_visit!(visitor.visit_expr(expr));
     V::Result::output()
 }
@@ -489,7 +486,7 @@
 pub fn walk_pat_field<'a, V: Visitor<'a>>(visitor: &mut V, fp: &'a PatField) -> V::Result {
     let PatField { ident, pat, is_shorthand: _, attrs, id: _, span: _, is_placeholder: _ } = fp;
     walk_list!(visitor, visit_attribute, attrs);
-    try_visit!(visitor.visit_ident(*ident));
+    try_visit!(visitor.visit_ident(ident));
     try_visit!(visitor.visit_pat(pat));
     V::Result::output()
 }
@@ -564,7 +561,7 @@
     match kind {
         UseTreeKind::Simple(rename) => {
             // The extra IDs are handled during AST lowering.
-            visit_opt!(visitor, visit_ident, *rename);
+            visit_opt!(visitor, visit_ident, rename);
         }
         UseTreeKind::Glob => {}
         UseTreeKind::Nested { ref items, span: _ } => {
@@ -581,7 +578,7 @@
     segment: &'a PathSegment,
 ) -> V::Result {
     let PathSegment { ident, id: _, args } = segment;
-    try_visit!(visitor.visit_ident(*ident));
+    try_visit!(visitor.visit_ident(ident));
     visit_opt!(visitor, visit_generic_args, args);
     V::Result::output()
 }
@@ -627,7 +624,7 @@
     constraint: &'a AssocItemConstraint,
 ) -> V::Result {
     let AssocItemConstraint { id: _, ident, gen_args, kind, span: _ } = constraint;
-    try_visit!(visitor.visit_ident(*ident));
+    try_visit!(visitor.visit_ident(ident));
     visit_opt!(visitor, visit_generic_args, gen_args);
     match kind {
         AssocItemConstraintKind::Equality { term } => match term {
@@ -665,7 +662,7 @@
             try_visit!(visitor.visit_pat(subpattern));
         }
         PatKind::Ident(_bmode, ident, optional_subpattern) => {
-            try_visit!(visitor.visit_ident(*ident));
+            try_visit!(visitor.visit_ident(ident));
             visit_opt!(visitor, visit_pat, optional_subpattern);
         }
         PatKind::Lit(expression) => try_visit!(visitor.visit_expr(expression)),
@@ -751,7 +748,7 @@
     let GenericParam { id: _, ident, attrs, bounds, is_placeholder: _, kind, colon_span: _ } =
         param;
     walk_list!(visitor, visit_attribute, attrs);
-    try_visit!(visitor.visit_ident(*ident));
+    try_visit!(visitor.visit_ident(ident));
     walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound);
     match kind {
         GenericParamKind::Lifetime => (),
@@ -889,7 +886,7 @@
             }) => {
                 try_visit!(walk_qself(visitor, qself));
                 try_visit!(visitor.visit_path(path, *id));
-                visit_opt!(visitor, visit_ident, *rename);
+                visit_opt!(visitor, visit_ident, rename);
                 visit_opt!(visitor, visit_block, body);
             }
             AssocItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => {
@@ -897,9 +894,9 @@
                 try_visit!(visitor.visit_path(prefix, id));
                 if let Some(suffixes) = suffixes {
                     for (ident, rename) in suffixes {
-                        visitor.visit_ident(*ident);
+                        visitor.visit_ident(ident);
                         if let Some(rename) = rename {
-                            visitor.visit_ident(*rename);
+                            visitor.visit_ident(rename);
                         }
                     }
                 }
@@ -915,7 +912,7 @@
     item: &'a Item<impl WalkItemKind>,
     ctxt: AssocCtxt,
 ) -> V::Result {
-    let &Item { id: _, span: _, ident, ref vis, ref attrs, ref kind, tokens: _ } = item;
+    let Item { id: _, span: _, ident, vis, attrs, kind, tokens: _ } = item;
     walk_list!(visitor, visit_attribute, attrs);
     try_visit!(visitor.visit_vis(vis));
     try_visit!(visitor.visit_ident(ident));
@@ -935,7 +932,7 @@
     let FieldDef { attrs, id: _, span: _, vis, ident, ty, is_placeholder: _ } = field;
     walk_list!(visitor, visit_attribute, attrs);
     try_visit!(visitor.visit_vis(vis));
-    visit_opt!(visitor, visit_ident, *ident);
+    visit_opt!(visitor, visit_ident, ident);
     try_visit!(visitor.visit_ty(ty));
     V::Result::output()
 }
@@ -1017,7 +1014,7 @@
     for FormatArgument { kind, expr } in arguments.all_args() {
         match kind {
             FormatArgumentKind::Named(ident) | FormatArgumentKind::Captured(ident) => {
-                try_visit!(visitor.visit_ident(*ident))
+                try_visit!(visitor.visit_ident(ident))
             }
             FormatArgumentKind::Normal => {}
         }
@@ -1137,7 +1134,7 @@
         }
         ExprKind::Field(subexpression, ident) => {
             try_visit!(visitor.visit_expr(subexpression));
-            try_visit!(visitor.visit_ident(*ident));
+            try_visit!(visitor.visit_ident(ident));
         }
         ExprKind::Index(main_expression, index_expression, _span) => {
             try_visit!(visitor.visit_expr(main_expression));
@@ -1172,7 +1169,7 @@
         ExprKind::FormatArgs(f) => try_visit!(visitor.visit_format_args(f)),
         ExprKind::OffsetOf(container, fields) => {
             try_visit!(visitor.visit_ty(container));
-            walk_list!(visitor, visit_ident, fields.iter().copied());
+            walk_list!(visitor, visit_ident, fields.iter());
         }
         ExprKind::Yield(optional_expression) => {
             visit_opt!(visitor, visit_expr, optional_expression);
@@ -1185,7 +1182,7 @@
         ExprKind::Dummy => {}
     }
 
-    visitor.visit_expr_post(expression)
+    V::Result::output()
 }
 
 pub fn walk_param<'a, V: Visitor<'a>>(visitor: &mut V, param: &'a Param) -> V::Result {
diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs
index 88cdb2e..6585a7d 100644
--- a/compiler/rustc_ast_lowering/src/asm.rs
+++ b/compiler/rustc_ast_lowering/src/asm.rs
@@ -49,7 +49,7 @@
                     | asm::InlineAsmArch::RiscV64
                     | asm::InlineAsmArch::LoongArch64
             );
-            if !is_stable && !self.tcx.features().asm_experimental_arch {
+            if !is_stable && !self.tcx.features().asm_experimental_arch() {
                 feature_err(
                     &self.tcx.sess,
                     sym::asm_experimental_arch,
@@ -65,7 +65,7 @@
         {
             self.dcx().emit_err(AttSyntaxOnlyX86 { span: sp });
         }
-        if asm.options.contains(InlineAsmOptions::MAY_UNWIND) && !self.tcx.features().asm_unwind {
+        if asm.options.contains(InlineAsmOptions::MAY_UNWIND) && !self.tcx.features().asm_unwind() {
             feature_err(
                 &self.tcx.sess,
                 sym::asm_unwind,
@@ -237,7 +237,7 @@
                         }
                     }
                     InlineAsmOperand::Label { block } => {
-                        if !self.tcx.features().asm_goto {
+                        if !self.tcx.features().asm_goto() {
                             feature_err(
                                 sess,
                                 sym::asm_goto,
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index ae1e1b3..a1a16d0 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -575,7 +575,7 @@
         } else {
             // Either `body.is_none()` or `is_never_pattern` here.
             if !is_never_pattern {
-                if self.tcx.features().never_patterns {
+                if self.tcx.features().never_patterns() {
                     // If the feature is off we already emitted the error after parsing.
                     let suggestion = span.shrink_to_hi();
                     self.dcx().emit_err(MatchArmWithNoBody { span, suggestion });
@@ -717,7 +717,7 @@
         outer_hir_id: HirId,
         inner_hir_id: HirId,
     ) {
-        if self.tcx.features().async_fn_track_caller
+        if self.tcx.features().async_fn_track_caller()
             && let Some(attrs) = self.attrs.get(&outer_hir_id.local_id)
             && attrs.into_iter().any(|attr| attr.has_name(sym::track_caller))
         {
@@ -1572,7 +1572,7 @@
                 );
             }
             Some(hir::CoroutineKind::Coroutine(_)) => {
-                if !self.tcx.features().coroutines {
+                if !self.tcx.features().coroutines() {
                     rustc_session::parse::feature_err(
                         &self.tcx.sess,
                         sym::coroutines,
@@ -1584,7 +1584,7 @@
                 false
             }
             None => {
-                if !self.tcx.features().coroutines {
+                if !self.tcx.features().coroutines() {
                     rustc_session::parse::feature_err(
                         &self.tcx.sess,
                         sym::coroutines,
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index 7416a1e..97fa90d 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -57,7 +57,7 @@
         owner: NodeId,
         f: impl FnOnce(&mut LoweringContext<'_, 'hir>) -> hir::OwnerNode<'hir>,
     ) {
-        let mut lctx = LoweringContext::new(self.tcx, self.resolver, self.ast_index);
+        let mut lctx = LoweringContext::new(self.tcx, self.resolver);
         lctx.with_hir_id_owner(owner, |lctx| f(lctx));
 
         for (def_id, info) in lctx.children {
@@ -193,8 +193,6 @@
             ItemKind::Const(box ast::ConstItem { generics, ty, expr, .. }) => {
                 let (generics, (ty, body_id)) = self.lower_generics(
                     generics,
-                    Const::No,
-                    false,
                     id,
                     ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
                     |this| {
@@ -225,16 +223,9 @@
                     );
 
                     let itctx = ImplTraitContext::Universal;
-                    let (generics, decl) =
-                        this.lower_generics(generics, header.constness, false, id, itctx, |this| {
-                            this.lower_fn_decl(
-                                decl,
-                                id,
-                                *fn_sig_span,
-                                FnDeclKind::Fn,
-                                coroutine_kind,
-                            )
-                        });
+                    let (generics, decl) = this.lower_generics(generics, id, itctx, |this| {
+                        this.lower_fn_decl(decl, id, *fn_sig_span, FnDeclKind::Fn, coroutine_kind)
+                    });
                     let sig = hir::FnSig {
                         decl,
                         header: this.lower_fn_header(*header, hir::Safety::Safe),
@@ -269,8 +260,6 @@
                 add_ty_alias_where_clause(&mut generics, *where_clauses, true);
                 let (generics, ty) = self.lower_generics(
                     &generics,
-                    Const::No,
-                    false,
                     id,
                     ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
                     |this| match ty {
@@ -294,8 +283,6 @@
             ItemKind::Enum(enum_definition, generics) => {
                 let (generics, variants) = self.lower_generics(
                     generics,
-                    Const::No,
-                    false,
                     id,
                     ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
                     |this| {
@@ -309,8 +296,6 @@
             ItemKind::Struct(struct_def, generics) => {
                 let (generics, struct_def) = self.lower_generics(
                     generics,
-                    Const::No,
-                    false,
                     id,
                     ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
                     |this| this.lower_variant_data(hir_id, struct_def),
@@ -320,8 +305,6 @@
             ItemKind::Union(vdata, generics) => {
                 let (generics, vdata) = self.lower_generics(
                     generics,
-                    Const::No,
-                    false,
                     id,
                     ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
                     |this| this.lower_variant_data(hir_id, vdata),
@@ -353,7 +336,7 @@
                 // parent lifetime.
                 let itctx = ImplTraitContext::Universal;
                 let (generics, (trait_ref, lowered_ty)) =
-                    self.lower_generics(ast_generics, Const::No, false, id, itctx, |this| {
+                    self.lower_generics(ast_generics, id, itctx, |this| {
                         let modifiers = TraitBoundModifiers {
                             constness: BoundConstness::Never,
                             asyncness: BoundAsyncness::Normal,
@@ -405,8 +388,6 @@
             ItemKind::Trait(box Trait { is_auto, safety, generics, bounds, items }) => {
                 let (generics, (safety, items, bounds)) = self.lower_generics(
                     generics,
-                    Const::No,
-                    false,
                     id,
                     ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
                     |this| {
@@ -426,8 +407,6 @@
             ItemKind::TraitAlias(generics, bounds) => {
                 let (generics, bounds) = self.lower_generics(
                     generics,
-                    Const::No,
-                    false,
                     id,
                     ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
                     |this| {
@@ -604,50 +583,23 @@
         ctxt: AssocCtxt,
         parent_hir: &'hir hir::OwnerInfo<'hir>,
     ) -> hir::OwnerNode<'hir> {
-        // Evaluate with the lifetimes in `params` in-scope.
-        // This is used to track which lifetimes have already been defined,
-        // and which need to be replicated when lowering an async fn.
-
         let parent_item = parent_hir.node().expect_item();
-        let constness = match parent_item.kind {
+        match parent_item.kind {
             hir::ItemKind::Impl(impl_) => {
                 self.is_in_trait_impl = impl_.of_trait.is_some();
-                // N.B. the impl should always lower to methods that have `const host: bool` params if the trait
-                // is const. It doesn't matter whether the `impl` itself is const. Disallowing const fn from
-                // calling non-const impls are done through associated types.
-                if let Some(def_id) = impl_.of_trait.and_then(|tr| tr.trait_def_id()) {
-                    if let Some(local_def) = def_id.as_local() {
-                        match &self.ast_index[local_def] {
-                            AstOwner::Item(ast::Item { attrs, .. }) => attrs
-                                .iter()
-                                .find(|attr| attr.has_name(sym::const_trait))
-                                .map_or(Const::No, |attr| Const::Yes(attr.span)),
-                            _ => Const::No,
-                        }
-                    } else if self.tcx.is_const_trait(def_id) {
-                        // FIXME(effects) span
-                        Const::Yes(self.tcx.def_ident_span(def_id).unwrap())
-                    } else {
-                        Const::No
-                    }
-                } else {
-                    Const::No
-                }
             }
-            hir::ItemKind::Trait(_, _, _, _, _) => parent_hir
-                .attrs
-                .get(parent_item.hir_id().local_id)
-                .iter()
-                .find(|attr| attr.has_name(sym::const_trait))
-                .map_or(Const::No, |attr| Const::Yes(attr.span)),
+            hir::ItemKind::Trait(_, _, _, _, _) => {}
             kind => {
                 span_bug!(item.span, "assoc item has unexpected kind of parent: {}", kind.descr())
             }
-        };
+        }
 
+        // Evaluate with the lifetimes in `params` in-scope.
+        // This is used to track which lifetimes have already been defined,
+        // and which need to be replicated when lowering an async fn.
         match ctxt {
-            AssocCtxt::Trait => hir::OwnerNode::TraitItem(self.lower_trait_item(item, constness)),
-            AssocCtxt::Impl => hir::OwnerNode::ImplItem(self.lower_impl_item(item, constness)),
+            AssocCtxt::Trait => hir::OwnerNode::TraitItem(self.lower_trait_item(item)),
+            AssocCtxt::Impl => hir::OwnerNode::ImplItem(self.lower_impl_item(item)),
         }
     }
 
@@ -663,7 +615,7 @@
                     let fdec = &sig.decl;
                     let itctx = ImplTraitContext::Universal;
                     let (generics, (decl, fn_args)) =
-                        self.lower_generics(generics, Const::No, false, i.id, itctx, |this| {
+                        self.lower_generics(generics, i.id, itctx, |this| {
                             (
                                 // Disallow `impl Trait` in foreign items.
                                 this.lower_fn_decl(
@@ -775,11 +727,7 @@
         }
     }
 
-    fn lower_trait_item(
-        &mut self,
-        i: &AssocItem,
-        trait_constness: Const,
-    ) -> &'hir hir::TraitItem<'hir> {
+    fn lower_trait_item(&mut self, i: &AssocItem) -> &'hir hir::TraitItem<'hir> {
         let hir_id = self.lower_node_id(i.id);
         self.lower_attrs(hir_id, &i.attrs);
         let trait_item_def_id = hir_id.expect_owner();
@@ -788,8 +736,6 @@
             AssocItemKind::Const(box ConstItem { generics, ty, expr, .. }) => {
                 let (generics, kind) = self.lower_generics(
                     generics,
-                    Const::No,
-                    false,
                     i.id,
                     ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
                     |this| {
@@ -810,7 +756,6 @@
                     i.id,
                     FnDeclKind::Trait,
                     sig.header.coroutine_kind,
-                    trait_constness,
                 );
                 (generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Required(names)), false)
             }
@@ -829,7 +774,6 @@
                     i.id,
                     FnDeclKind::Trait,
                     sig.header.coroutine_kind,
-                    trait_constness,
                 );
                 (generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Provided(body_id)), true)
             }
@@ -838,8 +782,6 @@
                 add_ty_alias_where_clause(&mut generics, *where_clauses, false);
                 let (generics, kind) = self.lower_generics(
                     &generics,
-                    Const::No,
-                    false,
                     i.id,
                     ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
                     |this| {
@@ -912,11 +854,7 @@
         self.expr(span, hir::ExprKind::Err(guar))
     }
 
-    fn lower_impl_item(
-        &mut self,
-        i: &AssocItem,
-        constness_of_trait: Const,
-    ) -> &'hir hir::ImplItem<'hir> {
+    fn lower_impl_item(&mut self, i: &AssocItem) -> &'hir hir::ImplItem<'hir> {
         // Since `default impl` is not yet implemented, this is always true in impls.
         let has_value = true;
         let (defaultness, _) = self.lower_defaultness(i.kind.defaultness(), has_value);
@@ -926,8 +864,6 @@
         let (generics, kind) = match &i.kind {
             AssocItemKind::Const(box ConstItem { generics, ty, expr, .. }) => self.lower_generics(
                 generics,
-                Const::No,
-                false,
                 i.id,
                 ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
                 |this| {
@@ -953,7 +889,6 @@
                     i.id,
                     if self.is_in_trait_impl { FnDeclKind::Impl } else { FnDeclKind::Inherent },
                     sig.header.coroutine_kind,
-                    constness_of_trait,
                 );
 
                 (generics, hir::ImplItemKind::Fn(sig, body_id))
@@ -963,8 +898,6 @@
                 add_ty_alias_where_clause(&mut generics, *where_clauses, false);
                 self.lower_generics(
                     &generics,
-                    Const::No,
-                    false,
                     i.id,
                     ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
                     |this| match ty {
@@ -1370,18 +1303,12 @@
         id: NodeId,
         kind: FnDeclKind,
         coroutine_kind: Option<CoroutineKind>,
-        parent_constness: Const,
     ) -> (&'hir hir::Generics<'hir>, hir::FnSig<'hir>) {
         let header = self.lower_fn_header(sig.header, hir::Safety::Safe);
-        // Don't pass along the user-provided constness of trait associated functions; we don't want to
-        // synthesize a host effect param for them. We reject `const` on them during AST validation.
-        let constness =
-            if kind == FnDeclKind::Inherent { sig.header.constness } else { parent_constness };
         let itctx = ImplTraitContext::Universal;
-        let (generics, decl) =
-            self.lower_generics(generics, constness, kind == FnDeclKind::Impl, id, itctx, |this| {
-                this.lower_fn_decl(&sig.decl, id, sig.span, kind, coroutine_kind)
-            });
+        let (generics, decl) = self.lower_generics(generics, id, itctx, |this| {
+            this.lower_fn_decl(&sig.decl, id, sig.span, kind, coroutine_kind)
+        });
         (generics, hir::FnSig { header, decl, span: self.lower_span(sig.span) })
     }
 
@@ -1460,8 +1387,6 @@
     fn lower_generics<T>(
         &mut self,
         generics: &Generics,
-        constness: Const,
-        force_append_constness: bool,
         parent_node_id: NodeId,
         itctx: ImplTraitContext,
         f: impl FnOnce(&mut Self) -> T,
@@ -1512,7 +1437,7 @@
                     continue;
                 }
                 let is_param = *is_param.get_or_insert_with(compute_is_param);
-                if !is_param && !self.tcx.features().more_maybe_bounds {
+                if !is_param && !self.tcx.features().more_maybe_bounds() {
                     self.tcx
                         .sess
                         .create_feature_err(
@@ -1524,30 +1449,6 @@
             }
         }
 
-        // Desugar `~const` bound in generics into an additional `const host: bool` param
-        // if the effects feature is enabled. This needs to be done before we lower where
-        // clauses since where clauses need to bind to the DefId of the host param
-        let host_param_parts = if let Const::Yes(span) = constness
-            // if this comes from implementing a `const` trait, we must force constness to be appended
-            // to the impl item, no matter whether effects is enabled.
-            && (self.tcx.features().effects || force_append_constness)
-        {
-            let span = self.lower_span(span);
-            let param_node_id = self.next_node_id();
-            let hir_id = self.next_id();
-            let def_id = self.create_def(
-                self.local_def_id(parent_node_id),
-                param_node_id,
-                sym::host,
-                DefKind::ConstParam,
-                span,
-            );
-            self.host_param_id = Some(def_id);
-            Some((span, hir_id, def_id))
-        } else {
-            None
-        };
-
         let mut predicates: SmallVec<[hir::WherePredicate<'hir>; 4]> = SmallVec::new();
         predicates.extend(generics.params.iter().filter_map(|param| {
             self.lower_generic_bound_predicate(
@@ -1595,74 +1496,6 @@
         let impl_trait_bounds = std::mem::take(&mut self.impl_trait_bounds);
         predicates.extend(impl_trait_bounds.into_iter());
 
-        if let Some((span, hir_id, def_id)) = host_param_parts {
-            let const_node_id = self.next_node_id();
-            let anon_const_did =
-                self.create_def(def_id, const_node_id, kw::Empty, DefKind::AnonConst, span);
-
-            let const_id = self.next_id();
-            let const_expr_id = self.next_id();
-            let bool_id = self.next_id();
-
-            self.children.push((def_id, hir::MaybeOwner::NonOwner(hir_id)));
-            self.children.push((anon_const_did, hir::MaybeOwner::NonOwner(const_id)));
-
-            let const_body = self.lower_body(|this| {
-                (&[], hir::Expr {
-                    hir_id: const_expr_id,
-                    kind: hir::ExprKind::Lit(
-                        this.arena.alloc(hir::Lit { node: LitKind::Bool(true), span }),
-                    ),
-                    span,
-                })
-            });
-
-            let default_ac = self.arena.alloc(hir::AnonConst {
-                def_id: anon_const_did,
-                hir_id: const_id,
-                body: const_body,
-                span,
-            });
-            let default_ct = self.arena.alloc(hir::ConstArg {
-                hir_id: self.next_id(),
-                kind: hir::ConstArgKind::Anon(default_ac),
-                is_desugared_from_effects: false,
-            });
-            let param = hir::GenericParam {
-                def_id,
-                hir_id,
-                name: hir::ParamName::Plain(Ident { name: sym::host, span }),
-                span,
-                kind: hir::GenericParamKind::Const {
-                    ty: self.arena.alloc(self.ty(
-                        span,
-                        hir::TyKind::Path(hir::QPath::Resolved(
-                            None,
-                            self.arena.alloc(hir::Path {
-                                res: Res::PrimTy(hir::PrimTy::Bool),
-                                span,
-                                segments: self.arena.alloc_from_iter([hir::PathSegment {
-                                    ident: Ident { name: sym::bool, span },
-                                    hir_id: bool_id,
-                                    res: Res::PrimTy(hir::PrimTy::Bool),
-                                    args: None,
-                                    infer_args: false,
-                                }]),
-                            }),
-                        )),
-                    )),
-                    default: Some(default_ct),
-                    is_host_effect: true,
-                    synthetic: true,
-                },
-                colon_span: None,
-                pure_wrt_drop: false,
-                source: hir::GenericParamSource::Generics,
-            };
-
-            params.push(param);
-        }
-
         let lowered_generics = self.arena.alloc(hir::Generics {
             params: self.arena.alloc_from_iter(params),
             predicates: self.arena.alloc_from_iter(predicates),
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 4d8d22e..34b8137 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -154,17 +154,10 @@
     /// defined on the TAIT, so we have type Foo<'a1> = ... and we establish a mapping in this
     /// field from the original parameter 'a to the new parameter 'a1.
     generics_def_id_map: Vec<LocalDefIdMap<LocalDefId>>,
-
-    host_param_id: Option<LocalDefId>,
-    ast_index: &'a IndexSlice<LocalDefId, AstOwner<'a>>,
 }
 
 impl<'a, 'hir> LoweringContext<'a, 'hir> {
-    fn new(
-        tcx: TyCtxt<'hir>,
-        resolver: &'a mut ResolverAstLowering,
-        ast_index: &'a IndexSlice<LocalDefId, AstOwner<'a>>,
-    ) -> Self {
+    fn new(tcx: TyCtxt<'hir>, resolver: &'a mut ResolverAstLowering) -> Self {
         Self {
             // Pseudo-globals.
             tcx,
@@ -193,7 +186,7 @@
             impl_trait_defs: Vec::new(),
             impl_trait_bounds: Vec::new(),
             allow_try_trait: [sym::try_trait_v2, sym::yeet_desugar_details].into(),
-            allow_gen_future: if tcx.features().async_fn_track_caller {
+            allow_gen_future: if tcx.features().async_fn_track_caller() {
                 [sym::gen_future, sym::closure_track_caller].into()
             } else {
                 [sym::gen_future].into()
@@ -204,8 +197,6 @@
             // interact with `gen`/`async gen` blocks
             allow_async_iterator: [sym::gen_future, sym::async_iterator].into(),
             generics_def_id_map: Default::default(),
-            host_param_id: None,
-            ast_index,
         }
     }
 
@@ -1035,7 +1026,7 @@
                                 span: data.inputs_span,
                             })
                         };
-                        if !self.tcx.features().return_type_notation
+                        if !self.tcx.features().return_type_notation()
                             && self.tcx.sess.is_nightly_build()
                         {
                             add_feature_diagnostics(
@@ -1160,7 +1151,7 @@
             ast::GenericArg::Lifetime(lt) => GenericArg::Lifetime(self.lower_lifetime(lt)),
             ast::GenericArg::Type(ty) => {
                 match &ty.kind {
-                    TyKind::Infer if self.tcx.features().generic_arg_infer => {
+                    TyKind::Infer if self.tcx.features().generic_arg_infer() => {
                         return GenericArg::Infer(hir::InferArg {
                             hir_id: self.lower_node_id(ty.id),
                             span: self.lower_span(ty.span),
@@ -1500,7 +1491,7 @@
         // is enabled. We don't check the span of the edition, since this is done
         // on a per-opaque basis to account for nested opaques.
         let always_capture_in_scope = match origin {
-            _ if self.tcx.features().lifetime_capture_rules_2024 => true,
+            _ if self.tcx.features().lifetime_capture_rules_2024() => true,
             hir::OpaqueTyOrigin::TyAlias { .. } => true,
             hir::OpaqueTyOrigin::FnReturn { in_trait_or_impl, .. } => in_trait_or_impl.is_some(),
             hir::OpaqueTyOrigin::AsyncFn { .. } => {
@@ -1519,7 +1510,7 @@
         // Feature gate for RPITIT + use<..>
         match origin {
             rustc_hir::OpaqueTyOrigin::FnReturn { in_trait_or_impl: Some(_), .. } => {
-                if !self.tcx.features().precise_capturing_in_traits
+                if !self.tcx.features().precise_capturing_in_traits()
                     && let Some(span) = bounds.iter().find_map(|bound| match *bound {
                         ast::GenericBound::Use(_, span) => Some(span),
                         _ => None,
@@ -1956,7 +1947,7 @@
 
         hir::GenericBound::Trait(hir::PolyTraitRef {
             bound_generic_params: &[],
-            modifiers: hir::TraitBoundModifier::None,
+            modifiers: hir::TraitBoundModifiers::NONE,
             trait_ref: hir::TraitRef {
                 path: self.make_lang_item_path(trait_lang_item, opaque_ty_span, Some(bound_args)),
                 hir_ref_id: self.next_id(),
@@ -2054,11 +2045,7 @@
         param: &GenericParam,
         source: hir::GenericParamSource,
     ) -> hir::GenericParam<'hir> {
-        let (name, kind) = self.lower_generic_param_kind(
-            param,
-            source,
-            attr::contains_name(&param.attrs, sym::rustc_runtime),
-        );
+        let (name, kind) = self.lower_generic_param_kind(param, source);
 
         let hir_id = self.lower_node_id(param.id);
         self.lower_attrs(hir_id, &param.attrs);
@@ -2078,7 +2065,6 @@
         &mut self,
         param: &GenericParam,
         source: hir::GenericParamSource,
-        is_host_effect: bool,
     ) -> (hir::ParamName, hir::GenericParamKind<'hir>) {
         match &param.kind {
             GenericParamKind::Lifetime => {
@@ -2144,7 +2130,7 @@
 
                 (
                     hir::ParamName::Plain(self.lower_ident(param.ident)),
-                    hir::GenericParamKind::Const { ty, default, is_host_effect, synthetic: false },
+                    hir::GenericParamKind::Const { ty, default, synthetic: false },
                 )
             }
         }
@@ -2270,7 +2256,7 @@
     fn lower_array_length(&mut self, c: &AnonConst) -> hir::ArrayLen<'hir> {
         match c.value.kind {
             ExprKind::Underscore => {
-                if self.tcx.features().generic_arg_infer {
+                if self.tcx.features().generic_arg_infer() {
                     hir::ArrayLen::Infer(hir::InferArg {
                         hir_id: self.lower_node_id(c.id),
                         span: self.lower_span(c.value.span),
@@ -2445,22 +2431,8 @@
     fn lower_trait_bound_modifiers(
         &mut self,
         modifiers: TraitBoundModifiers,
-    ) -> hir::TraitBoundModifier {
-        // Invalid modifier combinations will cause an error during AST validation.
-        // Arbitrarily pick a placeholder for them to make compilation proceed.
-        match (modifiers.constness, modifiers.polarity) {
-            (BoundConstness::Never, BoundPolarity::Positive) => hir::TraitBoundModifier::None,
-            (_, BoundPolarity::Maybe(_)) => hir::TraitBoundModifier::Maybe,
-            (BoundConstness::Never, BoundPolarity::Negative(_)) => {
-                if self.tcx.features().negative_bounds {
-                    hir::TraitBoundModifier::Negative
-                } else {
-                    hir::TraitBoundModifier::None
-                }
-            }
-            (BoundConstness::Always(_), _) => hir::TraitBoundModifier::Const,
-            (BoundConstness::Maybe(_), _) => hir::TraitBoundModifier::MaybeConst,
-        }
+    ) -> hir::TraitBoundModifiers {
+        hir::TraitBoundModifiers { constness: modifiers.constness, polarity: modifiers.polarity }
     }
 
     // Helper methods for building HIR.
@@ -2626,7 +2598,7 @@
                     Res::Def(DefKind::Trait | DefKind::TraitAlias, _) => {
                         let principal = hir::PolyTraitRef {
                             bound_generic_params: &[],
-                            modifiers: hir::TraitBoundModifier::None,
+                            modifiers: hir::TraitBoundModifiers::NONE,
                             trait_ref: hir::TraitRef { path, hir_ref_id: hir_id },
                             span: self.lower_span(span),
                         };
diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs
index e60488f..6a0f03c 100644
--- a/compiler/rustc_ast_lowering/src/path.rs
+++ b/compiler/rustc_ast_lowering/src/path.rs
@@ -34,7 +34,10 @@
         modifiers: Option<ast::TraitBoundModifiers>,
     ) -> hir::QPath<'hir> {
         let qself_position = qself.as_ref().map(|q| q.position);
-        let qself = qself.as_ref().map(|q| self.lower_ty(&q.ty, itctx));
+        let qself = qself
+            .as_ref()
+            // Reject cases like `<impl Trait>::Assoc` and `<impl Trait as Trait>::Assoc`.
+            .map(|q| self.lower_ty(&q.ty, ImplTraitContext::Disallowed(ImplTraitPosition::Path)));
 
         let partial_res =
             self.resolver.get_partial_res(id).unwrap_or_else(|| PartialRes::new(Res::Err));
@@ -75,6 +78,16 @@
             None
         };
 
+        // Only permit `impl Trait` in the final segment. E.g., we permit `Option<impl Trait>`,
+        // `option::Option<T>::Xyz<impl Trait>` and reject `option::Option<impl Trait>::Xyz`.
+        let itctx = |i| {
+            if i + 1 == p.segments.len() {
+                itctx
+            } else {
+                ImplTraitContext::Disallowed(ImplTraitPosition::Path)
+            }
+        };
+
         let path_span_lo = p.span.shrink_to_lo();
         let proj_start = p.segments.len() - unresolved_segments;
         let path = self.arena.alloc(hir::Path {
@@ -121,7 +134,7 @@
                         segment,
                         param_mode,
                         generic_args_mode,
-                        itctx,
+                        itctx(i),
                         bound_modifier_allowed_features.clone(),
                     )
                 },
@@ -185,7 +198,7 @@
                 segment,
                 param_mode,
                 generic_args_mode,
-                itctx,
+                itctx(i),
                 None,
             ));
             let qpath = hir::QPath::TypeRelative(ty, hir_segment);
@@ -268,7 +281,7 @@
                                 span: data.inputs_span,
                             })
                         };
-                        if !self.tcx.features().return_type_notation
+                        if !self.tcx.features().return_type_notation()
                             && self.tcx.sess.is_nightly_build()
                         {
                             add_feature_diagnostics(
@@ -496,7 +509,7 @@
             // //      disallowed --^^^^^^^^^^        allowed --^^^^^^^^^^
             // ```
             FnRetTy::Ty(ty) if matches!(itctx, ImplTraitContext::OpaqueTy { .. }) => {
-                if self.tcx.features().impl_trait_in_fn_trait_return {
+                if self.tcx.features().impl_trait_in_fn_trait_return() {
                     self.lower_ty(ty, itctx)
                 } else {
                     self.lower_ty(
diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl
index 92acaaa..d81fd53 100644
--- a/compiler/rustc_ast_passes/messages.ftl
+++ b/compiler/rustc_ast_passes/messages.ftl
@@ -146,8 +146,6 @@
 
 ast_passes_generic_default_trailing = generic parameters with a default must be trailing
 
-ast_passes_impl_trait_path = `impl Trait` is not allowed in path parameters
-
 ast_passes_incompatible_features = `{$f1}` and `{$f2}` are incompatible, using them at the same time is not allowed
     .help = remove one of these features
 
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index 20a4f21..0a4f86d 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -80,10 +80,6 @@
 
     disallow_tilde_const: Option<TildeConstReason>,
 
-    /// Used to ban `impl Trait` in path projections like `<impl Iterator>::Item`
-    /// or `Foo::Bar<impl Trait>`
-    is_impl_trait_banned: bool,
-
     /// Used to ban explicit safety on foreign items when the extern block is not marked as unsafe.
     extern_mod_safety: Option<Safety>,
 
@@ -123,12 +119,6 @@
         self.extern_mod_safety = old;
     }
 
-    fn with_banned_impl_trait(&mut self, f: impl FnOnce(&mut Self)) {
-        let old = mem::replace(&mut self.is_impl_trait_banned, true);
-        f(self);
-        self.is_impl_trait_banned = old;
-    }
-
     fn with_tilde_const(
         &mut self,
         disallowed: Option<TildeConstReason>,
@@ -213,43 +203,12 @@
                 .with_tilde_const(Some(TildeConstReason::TraitObject), |this| {
                     visit::walk_ty(this, t)
                 }),
-            TyKind::Path(qself, path) => {
-                // We allow these:
-                //  - `Option<impl Trait>`
-                //  - `option::Option<impl Trait>`
-                //  - `option::Option<T>::Foo<impl Trait>`
-                //
-                // But not these:
-                //  - `<impl Trait>::Foo`
-                //  - `option::Option<impl Trait>::Foo`.
-                //
-                // To implement this, we disallow `impl Trait` from `qself`
-                // (for cases like `<impl Trait>::Foo>`)
-                // but we allow `impl Trait` in `GenericArgs`
-                // iff there are no more PathSegments.
-                if let Some(qself) = qself {
-                    // `impl Trait` in `qself` is always illegal
-                    self.with_banned_impl_trait(|this| this.visit_ty(&qself.ty));
-                }
-
-                // Note that there should be a call to visit_path here,
-                // so if any logic is added to process `Path`s a call to it should be
-                // added both in visit_path and here. This code mirrors visit::walk_path.
-                for (i, segment) in path.segments.iter().enumerate() {
-                    // Allow `impl Trait` iff we're on the final path segment
-                    if i == path.segments.len() - 1 {
-                        self.visit_path_segment(segment);
-                    } else {
-                        self.with_banned_impl_trait(|this| this.visit_path_segment(segment));
-                    }
-                }
-            }
             _ => visit::walk_ty(self, t),
         }
     }
 
     fn visit_struct_field_def(&mut self, field: &'a FieldDef) {
-        if let Some(ident) = field.ident
+        if let Some(ref ident) = field.ident
             && ident.name == kw::Underscore
         {
             self.visit_vis(&field.vis);
@@ -295,7 +254,8 @@
             return;
         };
 
-        let make_impl_const_sugg = if self.features.const_trait_impl
+        let const_trait_impl = self.features.const_trait_impl();
+        let make_impl_const_sugg = if const_trait_impl
             && let TraitOrTraitImpl::TraitImpl {
                 constness: Const::No,
                 polarity: ImplPolarity::Positive,
@@ -308,13 +268,12 @@
             None
         };
 
-        let make_trait_const_sugg = if self.features.const_trait_impl
-            && let TraitOrTraitImpl::Trait { span, constness: None } = parent
-        {
-            Some(span.shrink_to_lo())
-        } else {
-            None
-        };
+        let make_trait_const_sugg =
+            if const_trait_impl && let TraitOrTraitImpl::Trait { span, constness: None } = parent {
+                Some(span.shrink_to_lo())
+            } else {
+                None
+            };
 
         let parent_constness = parent.constness();
         self.dcx().emit_err(errors::TraitFnConst {
@@ -737,10 +696,6 @@
                 }
             }
             TyKind::ImplTrait(_, bounds) => {
-                if self.is_impl_trait_banned {
-                    self.dcx().emit_err(errors::ImplTraitPath { span: ty.span });
-                }
-
                 if let Some(outer_impl_trait_sp) = self.outer_impl_trait {
                     self.dcx().emit_err(errors::NestedImplTrait {
                         span: ty.span,
@@ -899,7 +854,7 @@
                     }
 
                     this.visit_vis(&item.vis);
-                    this.visit_ident(item.ident);
+                    this.visit_ident(&item.ident);
                     let disallowed = matches!(constness, Const::No)
                         .then(|| TildeConstReason::TraitImpl { span: item.span });
                     this.with_tilde_const(disallowed, |this| this.visit_generics(generics));
@@ -953,7 +908,7 @@
                     }
 
                     this.visit_vis(&item.vis);
-                    this.visit_ident(item.ident);
+                    this.visit_ident(&item.ident);
                     this.with_tilde_const(
                         Some(TildeConstReason::Impl { span: item.span }),
                         |this| this.visit_generics(generics),
@@ -991,7 +946,7 @@
                 }
 
                 self.visit_vis(&item.vis);
-                self.visit_ident(item.ident);
+                self.visit_ident(&item.ident);
                 let kind =
                     FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, generics, body.as_deref());
                 self.visit_fn(kind, item.span, item.id);
@@ -1058,7 +1013,7 @@
                     // Equivalent of `visit::walk_item` for `ItemKind::Trait` that inserts a bound
                     // context for the supertraits.
                     this.visit_vis(&item.vis);
-                    this.visit_ident(item.ident);
+                    this.visit_ident(&item.ident);
                     let disallowed = is_const_trait
                         .is_none()
                         .then(|| TildeConstReason::Trait { span: item.span });
@@ -1085,7 +1040,7 @@
             ItemKind::Struct(vdata, generics) => match vdata {
                 VariantData::Struct { fields, .. } => {
                     self.visit_vis(&item.vis);
-                    self.visit_ident(item.ident);
+                    self.visit_ident(&item.ident);
                     self.visit_generics(generics);
                     // Permit `Anon{Struct,Union}` as field type.
                     walk_list!(self, visit_struct_field_def, fields);
@@ -1101,7 +1056,7 @@
                 match vdata {
                     VariantData::Struct { fields, .. } => {
                         self.visit_vis(&item.vis);
-                        self.visit_ident(item.ident);
+                        self.visit_ident(&item.ident);
                         self.visit_generics(generics);
                         // Permit `Anon{Struct,Union}` as field type.
                         walk_list!(self, visit_struct_field_def, fields);
@@ -1145,7 +1100,7 @@
                 }
                 self.check_type_no_bounds(bounds, "this context");
 
-                if self.features.lazy_type_alias {
+                if self.features.lazy_type_alias() {
                     if let Err(err) = self.check_type_alias_where_clause_location(ty_alias) {
                         self.dcx().emit_err(err);
                     }
@@ -1286,7 +1241,7 @@
             GenericBound::Trait(trait_ref) => {
                 match (ctxt, trait_ref.modifiers.constness, trait_ref.modifiers.polarity) {
                     (BoundKind::SuperTraits, BoundConstness::Never, BoundPolarity::Maybe(_))
-                        if !self.features.more_maybe_bounds =>
+                        if !self.features.more_maybe_bounds() =>
                     {
                         self.sess
                             .create_feature_err(
@@ -1299,7 +1254,7 @@
                             .emit();
                     }
                     (BoundKind::TraitObject, BoundConstness::Never, BoundPolarity::Maybe(_))
-                        if !self.features.more_maybe_bounds =>
+                        if !self.features.more_maybe_bounds() =>
                     {
                         self.sess
                             .create_feature_err(
@@ -1521,7 +1476,7 @@
                     || matches!(sig.header.constness, Const::Yes(_)) =>
             {
                 self.visit_vis(&item.vis);
-                self.visit_ident(item.ident);
+                self.visit_ident(&item.ident);
                 let kind = FnKind::Fn(
                     FnCtxt::Assoc(ctxt),
                     item.ident,
@@ -1729,7 +1684,6 @@
         has_proc_macro_decls: false,
         outer_impl_trait: None,
         disallow_tilde_const: Some(TildeConstReason::Item),
-        is_impl_trait_banned: false,
         extern_mod_safety: None,
         lint_buffer: lints,
     };
diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs
index 4ca1acd..8c3ac98 100644
--- a/compiler/rustc_ast_passes/src/errors.rs
+++ b/compiler/rustc_ast_passes/src/errors.rs
@@ -419,13 +419,6 @@
 }
 
 #[derive(Diagnostic)]
-#[diag(ast_passes_impl_trait_path, code = E0667)]
-pub(crate) struct ImplTraitPath {
-    #[primary_span]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
 #[diag(ast_passes_nested_impl_trait, code = E0666)]
 pub(crate) struct NestedImplTrait {
     #[primary_span]
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index f2773dc..d646150 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -15,13 +15,13 @@
 /// The common case.
 macro_rules! gate {
     ($visitor:expr, $feature:ident, $span:expr, $explain:expr) => {{
-        if !$visitor.features.$feature && !$span.allows_unstable(sym::$feature) {
+        if !$visitor.features.$feature() && !$span.allows_unstable(sym::$feature) {
             #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
             feature_err(&$visitor.sess, sym::$feature, $span, $explain).emit();
         }
     }};
     ($visitor:expr, $feature:ident, $span:expr, $explain:expr, $help:expr) => {{
-        if !$visitor.features.$feature && !$span.allows_unstable(sym::$feature) {
+        if !$visitor.features.$feature() && !$span.allows_unstable(sym::$feature) {
             // FIXME: make this translatable
             #[allow(rustc::diagnostic_outside_of_impl)]
             #[allow(rustc::untranslatable_diagnostic)]
@@ -43,7 +43,7 @@
 /// The case involving a multispan.
 macro_rules! gate_multi {
     ($visitor:expr, $feature:ident, $spans:expr, $explain:expr) => {{
-        if !$visitor.features.$feature {
+        if !$visitor.features.$feature() {
             let spans: Vec<_> =
                 $spans.filter(|span| !span.allows_unstable(sym::$feature)).collect();
             if !spans.is_empty() {
@@ -56,7 +56,7 @@
 /// The legacy case.
 macro_rules! gate_legacy {
     ($visitor:expr, $feature:ident, $span:expr, $explain:expr) => {{
-        if !$visitor.features.$feature && !$span.allows_unstable(sym::$feature) {
+        if !$visitor.features.$feature() && !$span.allows_unstable(sym::$feature) {
             feature_warn(&$visitor.sess, sym::$feature, $span, $explain);
         }
     }};
@@ -150,7 +150,7 @@
 
         // FIXME(non_lifetime_binders): Const bound params are pretty broken.
         // Let's keep users from using this feature accidentally.
-        if self.features.non_lifetime_binders {
+        if self.features.non_lifetime_binders() {
             let const_param_spans: Vec<_> = params
                 .iter()
                 .filter_map(|param| match param.kind {
@@ -210,7 +210,7 @@
         }
 
         // Emit errors for non-staged-api crates.
-        if !self.features.staged_api {
+        if !self.features.staged_api() {
             if attr.has_name(sym::unstable)
                 || attr.has_name(sym::stable)
                 || attr.has_name(sym::rustc_const_unstable)
@@ -470,7 +470,7 @@
             // Limit `min_specialization` to only specializing functions.
             gate_alt!(
                 &self,
-                self.features.specialization || (is_fn && self.features.min_specialization),
+                self.features.specialization() || (is_fn && self.features.min_specialization()),
                 sym::specialization,
                 i.span,
                 "specialization is unstable"
@@ -548,7 +548,7 @@
     gate_all!(return_type_notation, "return type notation is experimental");
     gate_all!(pin_ergonomics, "pinned reference syntax is experimental");
 
-    if !visitor.features.never_patterns {
+    if !visitor.features.never_patterns() {
         if let Some(spans) = spans.get(&sym::never_patterns) {
             for &span in spans {
                 if span.allows_unstable(sym::never_patterns) {
@@ -572,7 +572,7 @@
         }
     }
 
-    if !visitor.features.negative_bounds {
+    if !visitor.features.negative_bounds() {
         for &span in spans.get(&sym::negative_bounds).iter().copied().flatten() {
             sess.dcx().emit_err(errors::NegativeBoundUnsupported { span });
         }
@@ -600,59 +600,61 @@
 }
 
 fn maybe_stage_features(sess: &Session, features: &Features, krate: &ast::Crate) {
-    // checks if `#![feature]` has been used to enable any lang feature
-    // does not check the same for lib features unless there's at least one
-    // declared lang feature
-    if !sess.opts.unstable_features.is_nightly_build() {
-        if features.declared_features.is_empty() {
-            return;
-        }
-        for attr in krate.attrs.iter().filter(|attr| attr.has_name(sym::feature)) {
-            let mut err = errors::FeatureOnNonNightly {
-                span: attr.span,
-                channel: option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)"),
-                stable_features: vec![],
-                sugg: None,
-            };
-
-            let mut all_stable = true;
-            for ident in
-                attr.meta_item_list().into_iter().flatten().flat_map(|nested| nested.ident())
-            {
-                let name = ident.name;
-                let stable_since = features
-                    .declared_lang_features
-                    .iter()
-                    .flat_map(|&(feature, _, since)| if feature == name { since } else { None })
-                    .next();
-                if let Some(since) = stable_since {
-                    err.stable_features.push(errors::StableFeature { name, since });
-                } else {
-                    all_stable = false;
-                }
-            }
-            if all_stable {
-                err.sugg = Some(attr.span);
-            }
-            sess.dcx().emit_err(err);
-        }
+    // checks if `#![feature]` has been used to enable any feature.
+    if sess.opts.unstable_features.is_nightly_build() {
+        return;
     }
+    if features.enabled_features().is_empty() {
+        return;
+    }
+    let mut errored = false;
+    for attr in krate.attrs.iter().filter(|attr| attr.has_name(sym::feature)) {
+        // `feature(...)` used on non-nightly. This is definitely an error.
+        let mut err = errors::FeatureOnNonNightly {
+            span: attr.span,
+            channel: option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)"),
+            stable_features: vec![],
+            sugg: None,
+        };
+
+        let mut all_stable = true;
+        for ident in attr.meta_item_list().into_iter().flatten().flat_map(|nested| nested.ident()) {
+            let name = ident.name;
+            let stable_since = features
+                .enabled_lang_features()
+                .iter()
+                .find(|feat| feat.gate_name == name)
+                .map(|feat| feat.stable_since)
+                .flatten();
+            if let Some(since) = stable_since {
+                err.stable_features.push(errors::StableFeature { name, since });
+            } else {
+                all_stable = false;
+            }
+        }
+        if all_stable {
+            err.sugg = Some(attr.span);
+        }
+        sess.dcx().emit_err(err);
+        errored = true;
+    }
+    // Just make sure we actually error if anything is listed in `enabled_features`.
+    assert!(errored);
 }
 
 fn check_incompatible_features(sess: &Session, features: &Features) {
-    let declared_features = features
-        .declared_lang_features
-        .iter()
-        .copied()
-        .map(|(name, span, _)| (name, span))
-        .chain(features.declared_lib_features.iter().copied());
+    let enabled_lang_features =
+        features.enabled_lang_features().iter().map(|feat| (feat.gate_name, feat.attr_sp));
+    let enabled_lib_features =
+        features.enabled_lib_features().iter().map(|feat| (feat.gate_name, feat.attr_sp));
+    let enabled_features = enabled_lang_features.chain(enabled_lib_features);
 
     for (f1, f2) in rustc_feature::INCOMPATIBLE_FEATURES
         .iter()
-        .filter(|&&(f1, f2)| features.active(f1) && features.active(f2))
+        .filter(|(f1, f2)| features.enabled(*f1) && features.enabled(*f2))
     {
-        if let Some((f1_name, f1_span)) = declared_features.clone().find(|(name, _)| name == f1) {
-            if let Some((f2_name, f2_span)) = declared_features.clone().find(|(name, _)| name == f2)
+        if let Some((f1_name, f1_span)) = enabled_features.clone().find(|(name, _)| name == f1) {
+            if let Some((f2_name, f2_span)) = enabled_features.clone().find(|(name, _)| name == f2)
             {
                 let spans = vec![f1_span, f2_span];
                 sess.dcx().emit_err(errors::IncompatibleFeatures {
@@ -671,10 +673,11 @@
     }
 
     // Ban GCE with the new solver, because it does not implement GCE correctly.
-    if let Some(&(_, gce_span, _)) = features
-        .declared_lang_features
+    if let Some(gce_span) = features
+        .enabled_lang_features()
         .iter()
-        .find(|&&(feat, _, _)| feat == sym::generic_const_exprs)
+        .find(|feat| feat.gate_name == sym::generic_const_exprs)
+        .map(|feat| feat.attr_sp)
     {
         sess.dcx().emit_err(errors::IncompatibleFeatures {
             spans: vec![gce_span],
diff --git a/compiler/rustc_ast_passes/src/node_count.rs b/compiler/rustc_ast_passes/src/node_count.rs
index e22e99f..9e7204d 100644
--- a/compiler/rustc_ast_passes/src/node_count.rs
+++ b/compiler/rustc_ast_passes/src/node_count.rs
@@ -16,7 +16,7 @@
 }
 
 impl<'ast> Visitor<'ast> for NodeCounter {
-    fn visit_ident(&mut self, _ident: Ident) {
+    fn visit_ident(&mut self, _ident: &Ident) {
         self.count += 1;
     }
     fn visit_foreign_item(&mut self, i: &ForeignItem) {
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index 2cdec21..1e18f07 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -627,6 +627,13 @@
 
     fn print_attr_item(&mut self, item: &ast::AttrItem, span: Span) {
         self.ibox(0);
+        match item.unsafety {
+            ast::Safety::Unsafe(_) => {
+                self.word("unsafe");
+                self.popen();
+            }
+            ast::Safety::Default | ast::Safety::Safe(_) => {}
+        }
         match &item.args {
             AttrArgs::Delimited(DelimArgs { dspan: _, delim, tokens }) => self.print_mac_common(
                 Some(MacHeader::Path(&item.path)),
@@ -655,6 +662,10 @@
                 self.word(token_str);
             }
         }
+        match item.unsafety {
+            ast::Safety::Unsafe(_) => self.pclose(),
+            ast::Safety::Default | ast::Safety::Safe(_) => {}
+        }
         self.end();
     }
 
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
index 8217b6d..8279c66 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
@@ -38,7 +38,6 @@
                 self.print_fn_full(sig, ident, generics, vis, *defaultness, body.as_deref(), attrs);
             }
             ast::ForeignItemKind::Static(box ast::StaticItem { ty, mutability, expr, safety }) => {
-                self.print_safety(*safety);
                 self.print_item_const(
                     ident,
                     Some(*mutability),
@@ -46,6 +45,7 @@
                     ty,
                     expr.as_deref(),
                     vis,
+                    *safety,
                     ast::Defaultness::Final,
                 )
             }
@@ -84,10 +84,12 @@
         ty: &ast::Ty,
         body: Option<&ast::Expr>,
         vis: &ast::Visibility,
+        safety: ast::Safety,
         defaultness: ast::Defaultness,
     ) {
         self.head("");
         self.print_visibility(vis);
+        self.print_safety(safety);
         self.print_defaultness(defaultness);
         let leading = match mutbl {
             None => "const",
@@ -181,6 +183,7 @@
                     ty,
                     body.as_deref(),
                     &item.vis,
+                    ast::Safety::Default,
                     ast::Defaultness::Final,
                 );
             }
@@ -192,6 +195,7 @@
                     ty,
                     expr.as_deref(),
                     &item.vis,
+                    ast::Safety::Default,
                     *defaultness,
                 );
             }
@@ -549,6 +553,7 @@
                     ty,
                     expr.as_deref(),
                     vis,
+                    ast::Safety::Default,
                     *defaultness,
                 );
             }
diff --git a/compiler/rustc_attr/messages.ftl b/compiler/rustc_attr/messages.ftl
index adabf18..235ab75 100644
--- a/compiler/rustc_attr/messages.ftl
+++ b/compiler/rustc_attr/messages.ftl
@@ -91,6 +91,9 @@
 attr_rustc_allowed_unstable_pairing =
     `rustc_allowed_through_unstable_modules` attribute must be paired with a `stable` attribute
 
+attr_rustc_const_stable_indirect_pairing =
+    `const_stable_indirect` attribute does not make sense on `rustc_const_stable` function, its behavior is already implied
+
 attr_rustc_promotable_pairing =
     `rustc_promotable` attribute must be paired with either a `rustc_const_unstable` or a `rustc_const_stable` attribute
 
diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs
index bbb1749..6af75bc 100644
--- a/compiler/rustc_attr/src/builtin.rs
+++ b/compiler/rustc_attr/src/builtin.rs
@@ -16,9 +16,9 @@
 use rustc_session::lint::builtin::UNEXPECTED_CFGS;
 use rustc_session::parse::feature_err;
 use rustc_session::{RustcVersion, Session};
-use rustc_span::Span;
 use rustc_span::hygiene::Transparency;
 use rustc_span::symbol::{Symbol, kw, sym};
+use rustc_span::{DUMMY_SP, Span};
 
 use crate::fluent_generated;
 use crate::session_diagnostics::{self, IncorrectReprFormatGenericCause};
@@ -92,7 +92,11 @@
 #[derive(HashStable_Generic)]
 pub struct ConstStability {
     pub level: StabilityLevel,
-    pub feature: Symbol,
+    /// This can be `None` for functions that do not have an explicit const feature.
+    /// We still track them for recursive const stability checks.
+    pub feature: Option<Symbol>,
+    /// This is true iff the `const_stable_indirect` attribute is present.
+    pub const_stable_indirect: bool,
     /// whether the function has a `#[rustc_promotable]` attribute
     pub promotable: bool,
 }
@@ -268,17 +272,23 @@
 
 /// Collects stability info from `rustc_const_stable`/`rustc_const_unstable`/`rustc_promotable`
 /// attributes in `attrs`. Returns `None` if no stability attributes are found.
+///
+/// `is_const_fn` indicates whether this is a function marked as `const`. It will always
+/// be false for intrinsics in an `extern` block!
 pub fn find_const_stability(
     sess: &Session,
     attrs: &[Attribute],
     item_sp: Span,
+    is_const_fn: bool,
 ) -> Option<(ConstStability, Span)> {
     let mut const_stab: Option<(ConstStability, Span)> = None;
     let mut promotable = false;
+    let mut const_stable_indirect = None;
 
     for attr in attrs {
         match attr.name_or_empty() {
             sym::rustc_promotable => promotable = true,
+            sym::rustc_const_stable_indirect => const_stable_indirect = Some(attr.span),
             sym::rustc_const_unstable => {
                 if const_stab.is_some() {
                     sess.dcx()
@@ -287,8 +297,15 @@
                 }
 
                 if let Some((feature, level)) = parse_unstability(sess, attr) {
-                    const_stab =
-                        Some((ConstStability { level, feature, promotable: false }, attr.span));
+                    const_stab = Some((
+                        ConstStability {
+                            level,
+                            feature: Some(feature),
+                            const_stable_indirect: false,
+                            promotable: false,
+                        },
+                        attr.span,
+                    ));
                 }
             }
             sym::rustc_const_stable => {
@@ -298,15 +315,22 @@
                     break;
                 }
                 if let Some((feature, level)) = parse_stability(sess, attr) {
-                    const_stab =
-                        Some((ConstStability { level, feature, promotable: false }, attr.span));
+                    const_stab = Some((
+                        ConstStability {
+                            level,
+                            feature: Some(feature),
+                            const_stable_indirect: false,
+                            promotable: false,
+                        },
+                        attr.span,
+                    ));
                 }
             }
             _ => {}
         }
     }
 
-    // Merge the const-unstable info into the stability info
+    // Merge promotable and not_exposed_on_stable into stability info
     if promotable {
         match &mut const_stab {
             Some((stab, _)) => stab.promotable = promotable,
@@ -317,6 +341,46 @@
             }
         }
     }
+    if const_stable_indirect.is_some() {
+        match &mut const_stab {
+            Some((stab, _)) => {
+                if stab.is_const_unstable() {
+                    stab.const_stable_indirect = true;
+                } else {
+                    _ = sess.dcx().emit_err(session_diagnostics::RustcConstStableIndirectPairing {
+                        span: item_sp,
+                    })
+                }
+            }
+            _ => {
+                // We ignore the `#[rustc_const_stable_indirect]` here, it should be picked up by
+                // the `default_const_unstable` logic.
+            }
+        }
+    }
+    // Make sure if `const_stable_indirect` is present, that is recorded. Also make sure all `const
+    // fn` get *some* marker, since we are a staged_api crate and therefore will do recursive const
+    // stability checks for them. We need to do this because the default for whether an unmarked
+    // function enforces recursive stability differs between staged-api crates and force-unmarked
+    // crates: in force-unmarked crates, only functions *explicitly* marked `const_stable_indirect`
+    // enforce recursive stability. Therefore when `lookup_const_stability` is `None`, we have to
+    // assume the function does not have recursive stability. All functions that *do* have recursive
+    // stability must explicitly record this, and so that's what we do for all `const fn` in a
+    // staged_api crate.
+    if (is_const_fn || const_stable_indirect.is_some()) && const_stab.is_none() {
+        let c = ConstStability {
+            feature: None,
+            const_stable_indirect: const_stable_indirect.is_some(),
+            promotable: false,
+            level: StabilityLevel::Unstable {
+                reason: UnstableReason::Default,
+                issue: None,
+                is_soft: false,
+                implied_by: None,
+            },
+        };
+        const_stab = Some((c, const_stable_indirect.unwrap_or(DUMMY_SP)));
+    }
 
     const_stab
 }
@@ -619,11 +683,11 @@
                 // we can't use `try_gate_cfg` as symbols don't differentiate between `r#true`
                 // and `true`, and we want to keep the former working without feature gate
                 gate_cfg(
-                    &((
+                    &(
                         if *b { kw::True } else { kw::False },
                         sym::cfg_boolean_literals,
-                        |features: &Features| features.cfg_boolean_literals,
-                    )),
+                        |features: &Features| features.cfg_boolean_literals(),
+                    ),
                     cfg.span(),
                     sess,
                     features,
@@ -711,7 +775,7 @@
                 }
                 sym::target => {
                     if let Some(features) = features
-                        && !features.cfg_target_compact
+                        && !features.cfg_target_compact()
                     {
                         feature_err(
                             sess,
@@ -831,7 +895,7 @@
     attrs: &[Attribute],
 ) -> Option<(Deprecation, Span)> {
     let mut depr: Option<(Deprecation, Span)> = None;
-    let is_rustc = features.staged_api;
+    let is_rustc = features.staged_api();
 
     'outer: for attr in attrs {
         if !attr.has_name(sym::deprecated) {
@@ -891,7 +955,7 @@
                                 }
                             }
                             sym::suggestion => {
-                                if !features.deprecated_suggestion {
+                                if !features.deprecated_suggestion() {
                                     sess.dcx().emit_err(
                                         session_diagnostics::DeprecatedItemSuggestion {
                                             span: mi.span,
@@ -909,7 +973,7 @@
                                 sess.dcx().emit_err(session_diagnostics::UnknownMetaItem {
                                     span: meta.span(),
                                     item: pprust::path_to_string(&mi.path),
-                                    expected: if features.deprecated_suggestion {
+                                    expected: if features.deprecated_suggestion() {
                                         &["since", "note", "suggestion"]
                                     } else {
                                         &["since", "note"]
diff --git a/compiler/rustc_attr/src/session_diagnostics.rs b/compiler/rustc_attr/src/session_diagnostics.rs
index 626840a..9d08a9f 100644
--- a/compiler/rustc_attr/src/session_diagnostics.rs
+++ b/compiler/rustc_attr/src/session_diagnostics.rs
@@ -319,6 +319,13 @@
 }
 
 #[derive(Diagnostic)]
+#[diag(attr_rustc_const_stable_indirect_pairing)]
+pub(crate) struct RustcConstStableIndirectPairing {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
 #[diag(attr_rustc_allowed_unstable_pairing, code = E0789)]
 pub(crate) struct RustcAllowedUnstablePairing {
     #[primary_span]
diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
index 2437a43..2fa7523 100644
--- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
@@ -65,6 +65,7 @@
             UniverseInfoInner::RelateTys { expected, found } => {
                 let err = mbcx.infcx.err_ctxt().report_mismatched_types(
                     &cause,
+                    mbcx.param_env,
                     expected,
                     found,
                     TypeError::RegionsPlaceholderMismatch,
@@ -480,12 +481,11 @@
         .try_report_from_nll()
         .or_else(|| {
             if let SubregionOrigin::Subtype(trace) = cause {
-                Some(
-                    infcx.err_ctxt().report_and_explain_type_error(
-                        *trace,
-                        TypeError::RegionsPlaceholderMismatch,
-                    ),
-                )
+                Some(infcx.err_ctxt().report_and_explain_type_error(
+                    *trace,
+                    infcx.tcx.param_env(generic_param_scope),
+                    TypeError::RegionsPlaceholderMismatch,
+                ))
             } else {
                 None
             }
diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index a5f3298..3158517 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -959,13 +959,9 @@
                         None
                     }
                 }
-                hir::ExprKind::MethodCall(_, _, args, span) => {
-                    if let Some(def_id) = typeck_results.type_dependent_def_id(*hir_id) {
-                        Some((def_id, *span, *args))
-                    } else {
-                        None
-                    }
-                }
+                hir::ExprKind::MethodCall(_, _, args, span) => typeck_results
+                    .type_dependent_def_id(*hir_id)
+                    .map(|def_id| (def_id, *span, *args)),
                 _ => None,
             }
         };
diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
index a16c193..abce982 100644
--- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
+++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
@@ -360,6 +360,7 @@
                 .err_ctxt()
                 .report_mismatched_types(
                     &ObligationCause::misc(definition_span, def_id),
+                    param_env,
                     opaque_ty,
                     definition_ty,
                     err,
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index 7b60a63..a544d88 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -1035,7 +1035,7 @@
 
     fn unsized_feature_enabled(&self) -> bool {
         let features = self.tcx().features();
-        features.unsized_locals || features.unsized_fn_params
+        features.unsized_locals() || features.unsized_fn_params()
     }
 
     /// Equate the inferred type and the annotated type for user type annotations
diff --git a/compiler/rustc_builtin_macros/src/assert.rs b/compiler/rustc_builtin_macros/src/assert.rs
index 7144935..599b180 100644
--- a/compiler/rustc_builtin_macros/src/assert.rs
+++ b/compiler/rustc_builtin_macros/src/assert.rs
@@ -69,7 +69,7 @@
     // If `generic_assert` is enabled, generates rich captured outputs
     //
     // FIXME(c410-f3r) See https://github.com/rust-lang/rust/issues/96949
-    else if cx.ecfg.features.generic_assert {
+    else if cx.ecfg.features.generic_assert() {
         context::Context::new(cx, call_site_span).build(cond_expr, panic_path())
     }
     // If `generic_assert` is not enabled, only outputs a literal "assertion failed: ..."
diff --git a/compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs b/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs
similarity index 95%
rename from compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs
rename to compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs
index 731945f..53e938e 100644
--- a/compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs
@@ -19,7 +19,7 @@
     ($span:expr, $($part:ident)::*) => { vec![$(Ident::new(sym::$part, $span),)*] }
 }
 
-pub(crate) fn expand_deriving_smart_ptr(
+pub(crate) fn expand_deriving_coerce_pointee(
     cx: &ExtCtxt<'_>,
     span: Span,
     _mitem: &MetaItem,
@@ -41,7 +41,7 @@
             cx.dcx()
                 .struct_span_err(
                     span,
-                    "`SmartPointer` can only be derived on `struct`s with `#[repr(transparent)]`",
+                    "`CoercePointee` can only be derived on `struct`s with `#[repr(transparent)]`",
                 )
                 .emit();
             return;
@@ -54,7 +54,7 @@
             cx.dcx()
                 .struct_span_err(
                     span,
-                    "`SmartPointer` can only be derived on `struct`s with at least one field",
+                    "`CoercePointee` can only be derived on `struct`s with at least one field",
                 )
                 .emit();
             return;
@@ -64,7 +64,7 @@
         cx.dcx()
             .struct_span_err(
                 span,
-                "`SmartPointer` can only be derived on `struct`s with `#[repr(transparent)]`",
+                "`CoercePointee` can only be derived on `struct`s with `#[repr(transparent)]`",
             )
             .emit();
         return;
@@ -94,10 +94,10 @@
         .collect();
 
     let pointee_param_idx = if type_params.is_empty() {
-        // `#[derive(SmartPointer)]` requires at least one generic type on the target `struct`
+        // `#[derive(CoercePointee)]` requires at least one generic type on the target `struct`
         cx.dcx().struct_span_err(
             span,
-            "`SmartPointer` can only be derived on `struct`s that are generic over at least one type",
+            "`CoercePointee` can only be derived on `struct`s that are generic over at least one type",
         ).emit();
         return;
     } else if type_params.len() == 1 {
@@ -113,7 +113,7 @@
             (None, _) => {
                 cx.dcx().struct_span_err(
                     span,
-                    "exactly one generic type parameter must be marked as #[pointee] to derive SmartPointer traits",
+                    "exactly one generic type parameter must be marked as #[pointee] to derive CoercePointee traits",
                 ).emit();
                 return;
             }
@@ -121,7 +121,7 @@
                 cx.dcx()
                     .struct_span_err(
                         vec![one, another],
-                        "only one type parameter can be marked as `#[pointee]` when deriving SmartPointer traits",
+                        "only one type parameter can be marked as `#[pointee]` when deriving CoercePointee traits",
                     )
                     .emit();
                 return;
@@ -185,7 +185,7 @@
                 .struct_span_err(
                     pointee_ty_ident.span,
                     format!(
-                        "`derive(SmartPointer)` requires {} to be marked `?Sized`",
+                        "`derive(CoercePointee)` requires {} to be marked `?Sized`",
                         pointee_ty_ident.name
                     ),
                 )
@@ -195,7 +195,7 @@
         let arg = GenericArg::Type(s_ty.clone());
         let unsize = cx.path_all(span, true, path!(span, core::marker::Unsize), vec![arg]);
         pointee.bounds.push(cx.trait_bound(unsize, false));
-        // Drop `#[pointee]` attribute since it should not be recognized outside `derive(SmartPointer)`
+        // Drop `#[pointee]` attribute since it should not be recognized outside `derive(CoercePointee)`
         pointee.attrs.retain(|attr| !attr.has_name(sym::pointee));
     }
 
diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs
index 652e6f7..d4befd1 100644
--- a/compiler/rustc_builtin_macros/src/deriving/default.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/default.rs
@@ -222,7 +222,7 @@
         rustc_ast::visit::walk_attribute(self, attr);
     }
     fn visit_variant(&mut self, v: &'a rustc_ast::Variant) {
-        self.visit_ident(v.ident);
+        self.visit_ident(&v.ident);
         self.visit_vis(&v.vis);
         self.visit_variant_data(&v.data);
         visit_opt!(self, visit_anon_const, &v.disr_expr);
diff --git a/compiler/rustc_builtin_macros/src/deriving/mod.rs b/compiler/rustc_builtin_macros/src/deriving/mod.rs
index e884c0e..681fbd1 100644
--- a/compiler/rustc_builtin_macros/src/deriving/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/mod.rs
@@ -22,12 +22,12 @@
 
 pub(crate) mod bounds;
 pub(crate) mod clone;
+pub(crate) mod coerce_pointee;
 pub(crate) mod debug;
 pub(crate) mod decodable;
 pub(crate) mod default;
 pub(crate) mod encodable;
 pub(crate) mod hash;
-pub(crate) mod smart_ptr;
 
 #[path = "cmp/eq.rs"]
 pub(crate) mod eq;
diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs
index 377d7f5..9eee921 100644
--- a/compiler/rustc_builtin_macros/src/lib.rs
+++ b/compiler/rustc_builtin_macros/src/lib.rs
@@ -133,7 +133,7 @@
         PartialOrd: partial_ord::expand_deriving_partial_ord,
         RustcDecodable: decodable::expand_deriving_rustc_decodable,
         RustcEncodable: encodable::expand_deriving_rustc_encodable,
-        SmartPointer: smart_ptr::expand_deriving_smart_ptr,
+        CoercePointee: coerce_pointee::expand_deriving_coerce_pointee,
     }
 
     let client = proc_macro::bridge::client::Client::expand1(proc_macro::quote);
diff --git a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs
index d6603af..707c36d 100644
--- a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs
+++ b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs
@@ -313,14 +313,23 @@
             match m {
                 ProcMacro::Derive(cd) => {
                     cx.resolver.declare_proc_macro(cd.id);
-                    cx.expr_call(span, proc_macro_ty_method_path(cx, custom_derive), thin_vec![
-                        cx.expr_str(span, cd.trait_name),
-                        cx.expr_array_ref(
-                            span,
-                            cd.attrs.iter().map(|&s| cx.expr_str(span, s)).collect::<ThinVec<_>>(),
-                        ),
-                        local_path(cx, cd.function_name),
-                    ])
+                    // The call needs to use `harness_span` so that the const stability checker
+                    // accepts it.
+                    cx.expr_call(
+                        harness_span,
+                        proc_macro_ty_method_path(cx, custom_derive),
+                        thin_vec![
+                            cx.expr_str(span, cd.trait_name),
+                            cx.expr_array_ref(
+                                span,
+                                cd.attrs
+                                    .iter()
+                                    .map(|&s| cx.expr_str(span, s))
+                                    .collect::<ThinVec<_>>(),
+                            ),
+                            local_path(cx, cd.function_name),
+                        ],
+                    )
                 }
                 ProcMacro::Attr(ca) | ProcMacro::Bang(ca) => {
                     cx.resolver.declare_proc_macro(ca.id);
@@ -330,7 +339,9 @@
                         ProcMacro::Derive(_) => unreachable!(),
                     };
 
-                    cx.expr_call(span, proc_macro_ty_method_path(cx, ident), thin_vec![
+                    // The call needs to use `harness_span` so that the const stability checker
+                    // accepts it.
+                    cx.expr_call(harness_span, proc_macro_ty_method_path(cx, ident), thin_vec![
                         cx.expr_str(span, ca.function_name.name),
                         local_path(cx, ca.function_name),
                     ])
diff --git a/compiler/rustc_codegen_cranelift/example/mini_core.rs b/compiler/rustc_codegen_cranelift/example/mini_core.rs
index 9fc0318..42c7f5f 100644
--- a/compiler/rustc_codegen_cranelift/example/mini_core.rs
+++ b/compiler/rustc_codegen_cranelift/example/mini_core.rs
@@ -47,12 +47,12 @@
 impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<*mut U> for *mut T {}
 impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Box<U>> for Box<T> {}
 
-#[lang = "receiver"]
-pub trait Receiver {}
+#[lang = "legacy_receiver"]
+pub trait LegacyReceiver {}
 
-impl<T: ?Sized> Receiver for &T {}
-impl<T: ?Sized> Receiver for &mut T {}
-impl<T: ?Sized> Receiver for Box<T> {}
+impl<T: ?Sized> LegacyReceiver for &T {}
+impl<T: ?Sized> LegacyReceiver for &mut T {}
+impl<T: ?Sized> LegacyReceiver for Box<T> {}
 
 #[lang = "copy"]
 pub unsafe trait Copy {}
diff --git a/compiler/rustc_codegen_cranelift/patches/0027-stdlib-128bit-atomic-operations.patch b/compiler/rustc_codegen_cranelift/patches/0027-stdlib-128bit-atomic-operations.patch
index 6469288..3c81b04 100644
--- a/compiler/rustc_codegen_cranelift/patches/0027-stdlib-128bit-atomic-operations.patch
+++ b/compiler/rustc_codegen_cranelift/patches/0027-stdlib-128bit-atomic-operations.patch
@@ -38,7 +38,7 @@
 index d9de37e..8293fce 100644
 --- a/library/core/src/sync/atomic.rs
 +++ b/library/core/src/sync/atomic.rs
-@@ -2996,42 +2996,6 @@ atomic_int! {
+@@ -2996,44 +2996,6 @@ atomic_int! {
      8,
      u64 AtomicU64
  }
@@ -52,7 +52,8 @@
 -    unstable(feature = "integer_atomics", issue = "99069"),
 -    unstable(feature = "integer_atomics", issue = "99069"),
 -    unstable(feature = "integer_atomics", issue = "99069"),
--    rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
+-    rustc_const_unstable(feature = "integer_atomics", issue = "99069"),
+-    rustc_const_unstable(feature = "integer_atomics", issue = "99069"),
 -    cfg_attr(not(test), rustc_diagnostic_item = "AtomicI128"),
 -    "i128",
 -    "#![feature(integer_atomics)]\n\n",
@@ -70,7 +71,8 @@
 -    unstable(feature = "integer_atomics", issue = "99069"),
 -    unstable(feature = "integer_atomics", issue = "99069"),
 -    unstable(feature = "integer_atomics", issue = "99069"),
--    rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
+-    rustc_const_unstable(feature = "integer_atomics", issue = "99069"),
+-    rustc_const_unstable(feature = "integer_atomics", issue = "99069"),
 -    cfg_attr(not(test), rustc_diagnostic_item = "AtomicU128"),
 -    "u128",
 -    "#![feature(integer_atomics)]\n\n",
diff --git a/compiler/rustc_codegen_cranelift/src/abi/comments.rs b/compiler/rustc_codegen_cranelift/src/abi/comments.rs
index a318cae..daea789 100644
--- a/compiler/rustc_codegen_cranelift/src/abi/comments.rs
+++ b/compiler/rustc_codegen_cranelift/src/abi/comments.rs
@@ -79,7 +79,7 @@
         return;
     }
     let TyAndLayout { ty, layout } = place.layout();
-    let rustc_target::abi::LayoutS { size, align, .. } = layout.0.0;
+    let rustc_abi::LayoutData { size, align, .. } = layout.0.0;
 
     let (kind, extra) = place.debug_comment();
 
diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs
index f0b78e5..79d7692 100644
--- a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs
@@ -210,7 +210,6 @@
         type_names::push_generic_params(
             tcx,
             tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), args),
-            enclosing_fn_def_id,
             &mut name,
         );
 
diff --git a/compiler/rustc_codegen_gcc/example/mini_core.rs b/compiler/rustc_codegen_gcc/example/mini_core.rs
index f47bfda..0576b64 100644
--- a/compiler/rustc_codegen_gcc/example/mini_core.rs
+++ b/compiler/rustc_codegen_gcc/example/mini_core.rs
@@ -44,12 +44,12 @@
 impl<T: ?Sized+Unsize<U>, U: ?Sized> DispatchFromDyn<*mut U> for *mut T {}
 impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Box<U, ()>> for Box<T, ()> {}
 
-#[lang = "receiver"]
-pub trait Receiver {}
+#[lang = "legacy_receiver"]
+pub trait LegacyReceiver {}
 
-impl<T: ?Sized> Receiver for &T {}
-impl<T: ?Sized> Receiver for &mut T {}
-impl<T: ?Sized, A: Allocator> Receiver for Box<T, A> {}
+impl<T: ?Sized> LegacyReceiver for &T {}
+impl<T: ?Sized> LegacyReceiver for &mut T {}
+impl<T: ?Sized, A: Allocator> LegacyReceiver for Box<T, A> {}
 
 #[lang = "copy"]
 pub unsafe trait Copy {}
diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs
index b611f9b..7c52cba 100644
--- a/compiler/rustc_codegen_gcc/src/builder.rs
+++ b/compiler/rustc_codegen_gcc/src/builder.rs
@@ -30,7 +30,7 @@
 use rustc_span::Span;
 use rustc_span::def_id::DefId;
 use rustc_target::abi::call::FnAbi;
-use rustc_target::spec::{HasTargetSpec, HasWasmCAbiOpt, Target, WasmCAbi};
+use rustc_target::spec::{HasTargetSpec, HasWasmCAbiOpt, HasX86AbiOpt, Target, WasmCAbi, X86Abi};
 
 use crate::common::{SignType, TypeReflection, type_is_pointer};
 use crate::context::CodegenCx;
@@ -1725,16 +1725,6 @@
     fn fptosi_sat(&mut self, val: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> {
         self.fptoint_sat(true, val, dest_ty)
     }
-
-    fn instrprof_increment(
-        &mut self,
-        _fn_name: RValue<'gcc>,
-        _hash: RValue<'gcc>,
-        _num_counters: RValue<'gcc>,
-        _index: RValue<'gcc>,
-    ) {
-        unimplemented!();
-    }
 }
 
 impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
@@ -2347,6 +2337,12 @@
     }
 }
 
+impl<'tcx> HasX86AbiOpt for Builder<'_, '_, 'tcx> {
+    fn x86_abi_opt(&self) -> X86Abi {
+        self.cx.x86_abi_opt()
+    }
+}
+
 pub trait ToGccComp {
     fn to_gcc_comparison(&self) -> ComparisonOp;
 }
diff --git a/compiler/rustc_codegen_gcc/src/callee.rs b/compiler/rustc_codegen_gcc/src/callee.rs
index 9ad2e90..65972a0 100644
--- a/compiler/rustc_codegen_gcc/src/callee.rs
+++ b/compiler/rustc_codegen_gcc/src/callee.rs
@@ -98,8 +98,7 @@
         // whether we are sharing generics or not. The important thing here is
         // that the visibility we apply to the declaration is the same one that
         // has been applied to the definition (wherever that definition may be).
-        let is_generic =
-            instance.args.non_erasable_generics(tcx, instance.def_id()).next().is_some();
+        let is_generic = instance.args.non_erasable_generics().next().is_some();
 
         if is_generic {
             // This is a monomorphization. Its expected visibility depends
diff --git a/compiler/rustc_codegen_gcc/src/context.rs b/compiler/rustc_codegen_gcc/src/context.rs
index 7cb49bf..707b359 100644
--- a/compiler/rustc_codegen_gcc/src/context.rs
+++ b/compiler/rustc_codegen_gcc/src/context.rs
@@ -19,7 +19,9 @@
 use rustc_span::source_map::respan;
 use rustc_span::{DUMMY_SP, Span};
 use rustc_target::abi::{HasDataLayout, PointeeInfo, Size, TargetDataLayout, VariantIdx};
-use rustc_target::spec::{HasTargetSpec, HasWasmCAbiOpt, Target, TlsModel, WasmCAbi};
+use rustc_target::spec::{
+    HasTargetSpec, HasWasmCAbiOpt, HasX86AbiOpt, Target, TlsModel, WasmCAbi, X86Abi,
+};
 
 use crate::callee::get_fn;
 use crate::common::SignType;
@@ -538,6 +540,12 @@
     }
 }
 
+impl<'gcc, 'tcx> HasX86AbiOpt for CodegenCx<'gcc, 'tcx> {
+    fn x86_abi_opt(&self) -> X86Abi {
+        X86Abi { regparm: self.tcx.sess.opts.unstable_opts.regparm }
+    }
+}
+
 impl<'gcc, 'tcx> LayoutOfHelpers<'tcx> for CodegenCx<'gcc, 'tcx> {
     #[inline]
     fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! {
diff --git a/compiler/rustc_codegen_gcc/src/type_of.rs b/compiler/rustc_codegen_gcc/src/type_of.rs
index 183e9dd..db874af 100644
--- a/compiler/rustc_codegen_gcc/src/type_of.rs
+++ b/compiler/rustc_codegen_gcc/src/type_of.rs
@@ -197,7 +197,7 @@
     /// `[T]` becomes `T`, while `str` and `Trait` turn into `i8` - this
     /// is useful for indexing slices, as `&[T]`'s data pointer is `T*`.
     /// If the type is an unsized struct, the regular layout is generated,
-    /// with the inner-most trailing unsized field using the "minimal unit"
+    /// with the innermost trailing unsized field using the "minimal unit"
     /// of that field's type - this is useful for taking the address of
     /// that field and ensuring the struct has the right alignment.
     fn gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc> {
diff --git a/compiler/rustc_codegen_llvm/src/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs
index 89f5305..55ee6dc 100644
--- a/compiler/rustc_codegen_llvm/src/allocator.rs
+++ b/compiler/rustc_codegen_llvm/src/allocator.rs
@@ -77,20 +77,14 @@
         // __rust_alloc_error_handler_should_panic
         let name = OomStrategy::SYMBOL;
         let ll_g = llvm::LLVMRustGetOrInsertGlobal(llmod, name.as_ptr().cast(), name.len(), i8);
-        llvm::LLVMRustSetVisibility(
-            ll_g,
-            llvm::Visibility::from_generic(tcx.sess.default_visibility()),
-        );
+        llvm::set_visibility(ll_g, llvm::Visibility::from_generic(tcx.sess.default_visibility()));
         let val = tcx.sess.opts.unstable_opts.oom.should_panic();
         let llval = llvm::LLVMConstInt(i8, val as u64, False);
         llvm::LLVMSetInitializer(ll_g, llval);
 
         let name = NO_ALLOC_SHIM_IS_UNSTABLE;
         let ll_g = llvm::LLVMRustGetOrInsertGlobal(llmod, name.as_ptr().cast(), name.len(), i8);
-        llvm::LLVMRustSetVisibility(
-            ll_g,
-            llvm::Visibility::from_generic(tcx.sess.default_visibility()),
-        );
+        llvm::set_visibility(ll_g, llvm::Visibility::from_generic(tcx.sess.default_visibility()));
         let llval = llvm::LLVMConstInt(i8, 0, False);
         llvm::LLVMSetInitializer(ll_g, llval);
     }
@@ -134,10 +128,7 @@
             None
         };
 
-        llvm::LLVMRustSetVisibility(
-            llfn,
-            llvm::Visibility::from_generic(tcx.sess.default_visibility()),
-        );
+        llvm::set_visibility(llfn, llvm::Visibility::from_generic(tcx.sess.default_visibility()));
 
         if tcx.sess.must_emit_unwind_tables() {
             let uwtable =
@@ -151,7 +142,7 @@
             // -> ! DIFlagNoReturn
             attributes::apply_to_llfn(callee, llvm::AttributePlace::Function, &[no_return]);
         }
-        llvm::LLVMRustSetVisibility(callee, llvm::Visibility::Hidden);
+        llvm::set_visibility(callee, llvm::Visibility::Hidden);
 
         let llbb = llvm::LLVMAppendBasicBlockInContext(llcx, llfn, c"entry".as_ptr());
 
diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs
index afdd2b5..bf77fc5 100644
--- a/compiler/rustc_codegen_llvm/src/back/write.rs
+++ b/compiler/rustc_codegen_llvm/src/back/write.rs
@@ -1043,7 +1043,7 @@
 
             let section = bitcode_section_name(cgcx);
             llvm::LLVMSetSection(llglobal, section.as_ptr().cast());
-            llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage);
+            llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage);
             llvm::LLVMSetGlobalConstant(llglobal, llvm::True);
 
             let llconst = common::bytes_in_context(llcx, cmdline.as_bytes());
@@ -1061,7 +1061,7 @@
                 c".llvmcmd"
             };
             llvm::LLVMSetSection(llglobal, section.as_ptr());
-            llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage);
+            llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage);
         } else {
             // We need custom section flags, so emit module-level inline assembly.
             let section_flags = if cgcx.is_pe_coff { "n" } else { "e" };
@@ -1096,7 +1096,7 @@
         let ptr_ty = Type::ptr_llcx(llcx);
         let globals = base::iter_globals(llmod)
             .filter(|&val| {
-                llvm::LLVMRustGetLinkage(val) == llvm::Linkage::ExternalLinkage
+                llvm::get_linkage(val) == llvm::Linkage::ExternalLinkage
                     && llvm::LLVMIsDeclaration(val) == 0
             })
             .filter_map(|val| {
@@ -1115,7 +1115,7 @@
         for (imp_name, val) in globals {
             let imp = llvm::LLVMAddGlobal(llmod, ptr_ty, imp_name.as_ptr());
             llvm::LLVMSetInitializer(imp, val);
-            llvm::LLVMRustSetLinkage(imp, llvm::Linkage::ExternalLinkage);
+            llvm::set_linkage(imp, llvm::Linkage::ExternalLinkage);
         }
     }
 
diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs
index dbf5298..8702532 100644
--- a/compiler/rustc_codegen_llvm/src/builder.rs
+++ b/compiler/rustc_codegen_llvm/src/builder.rs
@@ -1165,39 +1165,6 @@
         self.call_lifetime_intrinsic("llvm.lifetime.end.p0i8", ptr, size);
     }
 
-    fn instrprof_increment(
-        &mut self,
-        fn_name: &'ll Value,
-        hash: &'ll Value,
-        num_counters: &'ll Value,
-        index: &'ll Value,
-    ) {
-        debug!(
-            "instrprof_increment() with args ({:?}, {:?}, {:?}, {:?})",
-            fn_name, hash, num_counters, index
-        );
-
-        let llfn = unsafe { llvm::LLVMRustGetInstrProfIncrementIntrinsic(self.cx().llmod) };
-        let llty = self.cx.type_func(
-            &[self.cx.type_ptr(), self.cx.type_i64(), self.cx.type_i32(), self.cx.type_i32()],
-            self.cx.type_void(),
-        );
-        let args = &[fn_name, hash, num_counters, index];
-        let args = self.check_call("call", llty, llfn, args);
-
-        unsafe {
-            let _ = llvm::LLVMRustBuildCall(
-                self.llbuilder,
-                llty,
-                llfn,
-                args.as_ptr() as *const &llvm::Value,
-                args.len() as c_uint,
-                [].as_ptr(),
-                0 as c_uint,
-            );
-        }
-    }
-
     fn call(
         &mut self,
         llty: &'ll Type,
@@ -1667,6 +1634,18 @@
         kcfi_bundle
     }
 
+    /// Emits a call to `llvm.instrprof.increment`. Used by coverage instrumentation.
+    #[instrument(level = "debug", skip(self))]
+    pub(crate) fn instrprof_increment(
+        &mut self,
+        fn_name: &'ll Value,
+        hash: &'ll Value,
+        num_counters: &'ll Value,
+        index: &'ll Value,
+    ) {
+        self.call_intrinsic("llvm.instrprof.increment", &[fn_name, hash, num_counters, index]);
+    }
+
     /// Emits a call to `llvm.instrprof.mcdc.parameters`.
     ///
     /// This doesn't produce any code directly, but is used as input by
@@ -1676,40 +1655,21 @@
     ///
     /// [`CodeGenPGO::emitMCDCParameters`]:
     ///     https://github.com/rust-lang/llvm-project/blob/5399a24/clang/lib/CodeGen/CodeGenPGO.cpp#L1124
+    #[instrument(level = "debug", skip(self))]
     pub(crate) fn mcdc_parameters(
         &mut self,
         fn_name: &'ll Value,
         hash: &'ll Value,
         bitmap_bits: &'ll Value,
     ) {
-        debug!("mcdc_parameters() with args ({:?}, {:?}, {:?})", fn_name, hash, bitmap_bits);
-
         assert!(
             crate::llvm_util::get_version() >= (19, 0, 0),
             "MCDC intrinsics require LLVM 19 or later"
         );
-
-        let llfn = unsafe { llvm::LLVMRustGetInstrProfMCDCParametersIntrinsic(self.cx().llmod) };
-        let llty = self.cx.type_func(
-            &[self.cx.type_ptr(), self.cx.type_i64(), self.cx.type_i32()],
-            self.cx.type_void(),
-        );
-        let args = &[fn_name, hash, bitmap_bits];
-        let args = self.check_call("call", llty, llfn, args);
-
-        unsafe {
-            let _ = llvm::LLVMRustBuildCall(
-                self.llbuilder,
-                llty,
-                llfn,
-                args.as_ptr() as *const &llvm::Value,
-                args.len() as c_uint,
-                [].as_ptr(),
-                0 as c_uint,
-            );
-        }
+        self.call_intrinsic("llvm.instrprof.mcdc.parameters", &[fn_name, hash, bitmap_bits]);
     }
 
+    #[instrument(level = "debug", skip(self))]
     pub(crate) fn mcdc_tvbitmap_update(
         &mut self,
         fn_name: &'ll Value,
@@ -1717,39 +1677,21 @@
         bitmap_index: &'ll Value,
         mcdc_temp: &'ll Value,
     ) {
-        debug!(
-            "mcdc_tvbitmap_update() with args ({:?}, {:?}, {:?}, {:?})",
-            fn_name, hash, bitmap_index, mcdc_temp
-        );
         assert!(
             crate::llvm_util::get_version() >= (19, 0, 0),
             "MCDC intrinsics require LLVM 19 or later"
         );
-
-        let llfn =
-            unsafe { llvm::LLVMRustGetInstrProfMCDCTVBitmapUpdateIntrinsic(self.cx().llmod) };
-        let llty = self.cx.type_func(
-            &[self.cx.type_ptr(), self.cx.type_i64(), self.cx.type_i32(), self.cx.type_ptr()],
-            self.cx.type_void(),
-        );
         let args = &[fn_name, hash, bitmap_index, mcdc_temp];
-        let args = self.check_call("call", llty, llfn, args);
-        unsafe {
-            let _ = llvm::LLVMRustBuildCall(
-                self.llbuilder,
-                llty,
-                llfn,
-                args.as_ptr() as *const &llvm::Value,
-                args.len() as c_uint,
-                [].as_ptr(),
-                0 as c_uint,
-            );
-        }
+        self.call_intrinsic("llvm.instrprof.mcdc.tvbitmap.update", args);
+    }
+
+    #[instrument(level = "debug", skip(self))]
+    pub(crate) fn mcdc_condbitmap_reset(&mut self, mcdc_temp: &'ll Value) {
         self.store(self.const_i32(0), mcdc_temp, self.tcx.data_layout.i32_align.abi);
     }
 
+    #[instrument(level = "debug", skip(self))]
     pub(crate) fn mcdc_condbitmap_update(&mut self, cond_index: &'ll Value, mcdc_temp: &'ll Value) {
-        debug!("mcdc_condbitmap_update() with args ({:?}, {:?})", cond_index, mcdc_temp);
         assert!(
             crate::llvm_util::get_version() >= (19, 0, 0),
             "MCDC intrinsics require LLVM 19 or later"
diff --git a/compiler/rustc_codegen_llvm/src/callee.rs b/compiler/rustc_codegen_llvm/src/callee.rs
index 206a706..25037b9 100644
--- a/compiler/rustc_codegen_llvm/src/callee.rs
+++ b/compiler/rustc_codegen_llvm/src/callee.rs
@@ -95,11 +95,10 @@
         // whether we are sharing generics or not. The important thing here is
         // that the visibility we apply to the declaration is the same one that
         // has been applied to the definition (wherever that definition may be).
-        unsafe {
-            llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::ExternalLinkage);
 
-            let is_generic =
-                instance.args.non_erasable_generics(tcx, instance.def_id()).next().is_some();
+        llvm::set_linkage(llfn, llvm::Linkage::ExternalLinkage);
+        unsafe {
+            let is_generic = instance.args.non_erasable_generics().next().is_some();
 
             let is_hidden = if is_generic {
                 // This is a monomorphization of a generic function.
@@ -136,7 +135,7 @@
                         || !cx.tcx.is_reachable_non_generic(instance_def_id))
             };
             if is_hidden {
-                llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden);
+                llvm::set_visibility(llfn, llvm::Visibility::Hidden);
             }
 
             // MinGW: For backward compatibility we rely on the linker to decide whether it
diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs
index 0ced37b5..ff47eb9 100644
--- a/compiler/rustc_codegen_llvm/src/common.rs
+++ b/compiler/rustc_codegen_llvm/src/common.rs
@@ -219,8 +219,8 @@
                     llvm::LLVMSetInitializer(g, sc);
                     llvm::LLVMSetGlobalConstant(g, True);
                     llvm::LLVMSetUnnamedAddress(g, llvm::UnnamedAddr::Global);
-                    llvm::LLVMRustSetLinkage(g, llvm::Linkage::InternalLinkage);
                 }
+                llvm::set_linkage(g, llvm::Linkage::InternalLinkage);
                 (s.to_owned(), g)
             })
             .1;
diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs
index 33a85ad..1e3abcf 100644
--- a/compiler/rustc_codegen_llvm/src/consts.rs
+++ b/compiler/rustc_codegen_llvm/src/consts.rs
@@ -172,29 +172,27 @@
     if let Some(linkage) = attrs.import_linkage {
         debug!("get_static: sym={} linkage={:?}", sym, linkage);
 
-        unsafe {
-            // Declare a symbol `foo` with the desired linkage.
-            let g1 = cx.declare_global(sym, cx.type_i8());
-            llvm::LLVMRustSetLinkage(g1, base::linkage_to_llvm(linkage));
+        // Declare a symbol `foo` with the desired linkage.
+        let g1 = cx.declare_global(sym, cx.type_i8());
+        llvm::set_linkage(g1, base::linkage_to_llvm(linkage));
 
-            // Declare an internal global `extern_with_linkage_foo` which
-            // is initialized with the address of `foo`. If `foo` is
-            // discarded during linking (for example, if `foo` has weak
-            // linkage and there are no definitions), then
-            // `extern_with_linkage_foo` will instead be initialized to
-            // zero.
-            let mut real_name = "_rust_extern_with_linkage_".to_string();
-            real_name.push_str(sym);
-            let g2 = cx.define_global(&real_name, llty).unwrap_or_else(|| {
-                cx.sess().dcx().emit_fatal(SymbolAlreadyDefined {
-                    span: cx.tcx.def_span(def_id),
-                    symbol_name: sym,
-                })
-            });
-            llvm::LLVMRustSetLinkage(g2, llvm::Linkage::InternalLinkage);
-            llvm::LLVMSetInitializer(g2, g1);
-            g2
-        }
+        // Declare an internal global `extern_with_linkage_foo` which
+        // is initialized with the address of `foo`. If `foo` is
+        // discarded during linking (for example, if `foo` has weak
+        // linkage and there are no definitions), then
+        // `extern_with_linkage_foo` will instead be initialized to
+        // zero.
+        let mut real_name = "_rust_extern_with_linkage_".to_string();
+        real_name.push_str(sym);
+        let g2 = cx.define_global(&real_name, llty).unwrap_or_else(|| {
+            cx.sess().dcx().emit_fatal(SymbolAlreadyDefined {
+                span: cx.tcx.def_span(def_id),
+                symbol_name: sym,
+            })
+        });
+        llvm::set_linkage(g2, llvm::Linkage::InternalLinkage);
+        unsafe { llvm::LLVMSetInitializer(g2, g1) };
+        g2
     } else if cx.tcx.sess.target.arch == "x86"
         && let Some(dllimport) = crate::common::get_dllimport(cx.tcx, def_id, sym)
     {
@@ -224,23 +222,21 @@
         align: Align,
         kind: Option<&str>,
     ) -> &'ll Value {
-        unsafe {
-            let gv = match kind {
-                Some(kind) if !self.tcx.sess.fewer_names() => {
-                    let name = self.generate_local_symbol_name(kind);
-                    let gv = self.define_global(&name, self.val_ty(cv)).unwrap_or_else(|| {
-                        bug!("symbol `{}` is already defined", name);
-                    });
-                    llvm::LLVMRustSetLinkage(gv, llvm::Linkage::PrivateLinkage);
-                    gv
-                }
-                _ => self.define_private_global(self.val_ty(cv)),
-            };
-            llvm::LLVMSetInitializer(gv, cv);
-            set_global_alignment(self, gv, align);
-            llvm::SetUnnamedAddress(gv, llvm::UnnamedAddr::Global);
-            gv
-        }
+        let gv = match kind {
+            Some(kind) if !self.tcx.sess.fewer_names() => {
+                let name = self.generate_local_symbol_name(kind);
+                let gv = self.define_global(&name, self.val_ty(cv)).unwrap_or_else(|| {
+                    bug!("symbol `{}` is already defined", name);
+                });
+                llvm::set_linkage(gv, llvm::Linkage::PrivateLinkage);
+                gv
+            }
+            _ => self.define_private_global(self.val_ty(cv)),
+        };
+        unsafe { llvm::LLVMSetInitializer(gv, cv) };
+        set_global_alignment(self, gv, align);
+        llvm::SetUnnamedAddress(gv, llvm::UnnamedAddr::Global);
+        gv
     }
 
     #[instrument(level = "debug", skip(self))]
@@ -292,9 +288,7 @@
             let g = self.declare_global(sym, llty);
 
             if !self.tcx.is_reachable_non_generic(def_id) {
-                unsafe {
-                    llvm::LLVMRustSetVisibility(g, llvm::Visibility::Hidden);
-                }
+                llvm::set_visibility(g, llvm::Visibility::Hidden);
             }
 
             g
@@ -312,7 +306,7 @@
             llvm::set_thread_local_mode(g, self.tls_model);
         }
 
-        let dso_local = unsafe { self.should_assume_dso_local(g, true) };
+        let dso_local = self.should_assume_dso_local(g, true);
         if dso_local {
             unsafe {
                 llvm::LLVMRustSetDSOLocal(g, true);
@@ -401,8 +395,8 @@
                 let name = llvm::get_value_name(g).to_vec();
                 llvm::set_value_name(g, b"");
 
-                let linkage = llvm::LLVMRustGetLinkage(g);
-                let visibility = llvm::LLVMRustGetVisibility(g);
+                let linkage = llvm::get_linkage(g);
+                let visibility = llvm::get_visibility(g);
 
                 let new_g = llvm::LLVMRustGetOrInsertGlobal(
                     self.llmod,
@@ -411,8 +405,8 @@
                     val_llty,
                 );
 
-                llvm::LLVMRustSetLinkage(new_g, linkage);
-                llvm::LLVMRustSetVisibility(new_g, visibility);
+                llvm::set_linkage(new_g, linkage);
+                llvm::set_visibility(new_g, visibility);
 
                 // The old global has had its name removed but is returned by
                 // get_static since it is in the instance cache. Provide an
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index 2f830d6..067028a 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -80,6 +80,7 @@
 
     pub isize_ty: &'ll Type,
 
+    /// Extra codegen state needed when coverage instrumentation is enabled.
     pub coverage_cx: Option<coverageinfo::CrateCoverageContext<'ll, 'tcx>>,
     pub dbg_cx: Option<debuginfo::CodegenUnitDebugContext<'ll, 'tcx>>,
 
@@ -592,11 +593,10 @@
         &self.statics_to_rauw
     }
 
+    /// Extra state that is only available when coverage instrumentation is enabled.
     #[inline]
-    pub(crate) fn coverage_context(
-        &self,
-    ) -> Option<&coverageinfo::CrateCoverageContext<'ll, 'tcx>> {
-        self.coverage_cx.as_ref()
+    pub(crate) fn coverage_cx(&self) -> &coverageinfo::CrateCoverageContext<'ll, 'tcx> {
+        self.coverage_cx.as_ref().expect("only called when coverage instrumentation is enabled")
     }
 
     pub(crate) fn create_used_variable_impl(&self, name: &'static CStr, values: &[&'ll Value]) {
@@ -605,7 +605,7 @@
         unsafe {
             let g = llvm::LLVMAddGlobal(self.llmod, self.val_ty(array), name.as_ptr());
             llvm::LLVMSetInitializer(g, array);
-            llvm::LLVMRustSetLinkage(g, llvm::Linkage::AppendingLinkage);
+            llvm::set_linkage(g, llvm::Linkage::AppendingLinkage);
             llvm::LLVMSetSection(g, c"llvm.metadata".as_ptr());
         }
     }
@@ -1099,6 +1099,10 @@
 
         if self.sess().instrument_coverage() {
             ifn!("llvm.instrprof.increment", fn(ptr, t_i64, t_i32, t_i32) -> void);
+            if crate::llvm_util::get_version() >= (19, 0, 0) {
+                ifn!("llvm.instrprof.mcdc.parameters", fn(ptr, t_i64, t_i32) -> void);
+                ifn!("llvm.instrprof.mcdc.tvbitmap.update", fn(ptr, t_i64, t_i32, ptr) -> void);
+            }
         }
 
         ifn!("llvm.type.test", fn(ptr, t_metadata) -> i1);
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs
index 90f7dd73..feac97f 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs
@@ -1,11 +1,9 @@
-use rustc_middle::mir::coverage::{
-    ConditionInfo, CounterId, CovTerm, DecisionInfo, ExpressionId, MappingKind, SourceRegion,
-};
+use rustc_middle::mir::coverage::{CounterId, CovTerm, ExpressionId, SourceRegion};
 
 /// Must match the layout of `LLVMRustCounterKind`.
 #[derive(Copy, Clone, Debug)]
 #[repr(C)]
-pub enum CounterKind {
+pub(crate) enum CounterKind {
     Zero = 0,
     CounterValueReference = 1,
     Expression = 2,
@@ -25,9 +23,9 @@
 /// Must match the layout of `LLVMRustCounter`.
 #[derive(Copy, Clone, Debug)]
 #[repr(C)]
-pub struct Counter {
+pub(crate) struct Counter {
     // Important: The layout (order and types of fields) must match its C++ counterpart.
-    pub kind: CounterKind,
+    pub(crate) kind: CounterKind,
     id: u32,
 }
 
@@ -36,7 +34,7 @@
     pub(crate) const ZERO: Self = Self { kind: CounterKind::Zero, id: 0 };
 
     /// Constructs a new `Counter` of kind `CounterValueReference`.
-    pub fn counter_value_reference(counter_id: CounterId) -> Self {
+    pub(crate) fn counter_value_reference(counter_id: CounterId) -> Self {
         Self { kind: CounterKind::CounterValueReference, id: counter_id.as_u32() }
     }
 
@@ -59,7 +57,7 @@
 /// Must match the layout of `LLVMRustCounterExprKind`.
 #[derive(Copy, Clone, Debug)]
 #[repr(C)]
-pub enum ExprKind {
+pub(crate) enum ExprKind {
     Subtract = 0,
     Add = 1,
 }
@@ -69,48 +67,13 @@
 /// Must match the layout of `LLVMRustCounterExpression`.
 #[derive(Copy, Clone, Debug)]
 #[repr(C)]
-pub struct CounterExpression {
-    pub kind: ExprKind,
-    pub lhs: Counter,
-    pub rhs: Counter,
+pub(crate) struct CounterExpression {
+    pub(crate) kind: ExprKind,
+    pub(crate) lhs: Counter,
+    pub(crate) rhs: Counter,
 }
 
-/// Corresponds to enum `llvm::coverage::CounterMappingRegion::RegionKind`.
-///
-/// Must match the layout of `LLVMRustCounterMappingRegionKind`.
-#[derive(Copy, Clone, Debug)]
-#[repr(C)]
-enum RegionKind {
-    /// A CodeRegion associates some code with a counter
-    CodeRegion = 0,
-
-    /// An ExpansionRegion represents a file expansion region that associates
-    /// a source range with the expansion of a virtual source file, such as
-    /// for a macro instantiation or #include file.
-    ExpansionRegion = 1,
-
-    /// A SkippedRegion represents a source range with code that was skipped
-    /// by a preprocessor or similar means.
-    SkippedRegion = 2,
-
-    /// A GapRegion is like a CodeRegion, but its count is only set as the
-    /// line execution count when its the only region in the line.
-    GapRegion = 3,
-
-    /// A BranchRegion represents leaf-level boolean expressions and is
-    /// associated with two counters, each representing the number of times the
-    /// expression evaluates to true or false.
-    BranchRegion = 4,
-
-    /// A DecisionRegion represents a top-level boolean expression and is
-    /// associated with a variable length bitmap index and condition number.
-    MCDCDecisionRegion = 5,
-
-    /// A Branch Region can be extended to include IDs to facilitate MC/DC.
-    MCDCBranchRegion = 6,
-}
-
-mod mcdc {
+pub(crate) mod mcdc {
     use rustc_middle::mir::coverage::{ConditionId, ConditionInfo, DecisionInfo};
 
     /// Must match the layout of `LLVMRustMCDCDecisionParameters`.
@@ -121,8 +84,6 @@
         num_conditions: u16,
     }
 
-    // ConditionId in llvm is `unsigned int` at 18 while `int16_t` at
-    // [19](https://github.com/llvm/llvm-project/pull/81257).
     type LLVMConditionId = i16;
 
     /// Must match the layout of `LLVMRustMCDCBranchParameters`.
@@ -133,38 +94,6 @@
         condition_ids: [LLVMConditionId; 2],
     }
 
-    #[repr(C)]
-    #[derive(Clone, Copy, Debug)]
-    enum ParameterTag {
-        None = 0,
-        Decision = 1,
-        Branch = 2,
-    }
-    /// Same layout with `LLVMRustMCDCParameters`
-    #[repr(C)]
-    #[derive(Clone, Copy, Debug)]
-    pub(crate) struct Parameters {
-        tag: ParameterTag,
-        decision_params: DecisionParameters,
-        branch_params: BranchParameters,
-    }
-
-    impl Parameters {
-        pub(crate) fn none() -> Self {
-            Self {
-                tag: ParameterTag::None,
-                decision_params: Default::default(),
-                branch_params: Default::default(),
-            }
-        }
-        pub(crate) fn decision(decision_params: DecisionParameters) -> Self {
-            Self { tag: ParameterTag::Decision, decision_params, branch_params: Default::default() }
-        }
-        pub(crate) fn branch(branch_params: BranchParameters) -> Self {
-            Self { tag: ParameterTag::Branch, decision_params: Default::default(), branch_params }
-        }
-    }
-
     impl From<ConditionInfo> for BranchParameters {
         fn from(value: ConditionInfo) -> Self {
             let to_llvm_cond_id = |cond_id: Option<ConditionId>| {
@@ -186,267 +115,68 @@
     }
 }
 
-/// This struct provides LLVM's representation of a "CoverageMappingRegion", encoded into the
-/// coverage map, in accordance with the
-/// [LLVM Code Coverage Mapping Format](https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/docs/CoverageMappingFormat.rst#llvm-code-coverage-mapping-format).
-/// The struct composes fields representing the `Counter` type and value(s) (injected counter
-/// ID, or expression type and operands), the source file (an indirect index into a "filenames
-/// array", encoded separately), and source location (start and end positions of the represented
-/// code region).
+/// A span of source code coordinates to be embedded in coverage metadata.
 ///
-/// Corresponds to struct `llvm::coverage::CounterMappingRegion`.
-///
-/// Must match the layout of `LLVMRustCounterMappingRegion`.
-#[derive(Copy, Clone, Debug)]
+/// Must match the layout of `LLVMRustCoverageSpan`.
+#[derive(Clone, Debug)]
 #[repr(C)]
-pub struct CounterMappingRegion {
-    /// The counter type and type-dependent counter data, if any.
-    counter: Counter,
-
-    /// If the `RegionKind` is a `BranchRegion`, this represents the counter
-    /// for the false branch of the region.
-    false_counter: Counter,
-
-    mcdc_params: mcdc::Parameters,
-    /// An indirect reference to the source filename. In the LLVM Coverage Mapping Format, the
-    /// file_id is an index into a function-specific `virtual_file_mapping` array of indexes
-    /// that, in turn, are used to look up the filename for this region.
+pub(crate) struct CoverageSpan {
+    /// Local index into the function's local-to-global file ID table.
+    /// The value at that index is itself an index into the coverage filename
+    /// table in the CGU's `__llvm_covmap` section.
     file_id: u32,
 
-    /// If the `RegionKind` is an `ExpansionRegion`, the `expanded_file_id` can be used to find
-    /// the mapping regions created as a result of macro expansion, by checking if their file id
-    /// matches the expanded file id.
-    expanded_file_id: u32,
-
-    /// 1-based starting line of the mapping region.
+    /// 1-based starting line of the source code span.
     start_line: u32,
-
-    /// 1-based starting column of the mapping region.
+    /// 1-based starting column of the source code span.
     start_col: u32,
-
-    /// 1-based ending line of the mapping region.
+    /// 1-based ending line of the source code span.
     end_line: u32,
-
-    /// 1-based ending column of the mapping region. If the high bit is set, the current
-    /// mapping region is a gap area.
+    /// 1-based ending column of the source code span. High bit must be unset.
     end_col: u32,
-
-    kind: RegionKind,
 }
 
-impl CounterMappingRegion {
-    pub(crate) fn from_mapping(
-        mapping_kind: &MappingKind,
-        local_file_id: u32,
-        source_region: &SourceRegion,
-    ) -> Self {
-        let &SourceRegion { file_name: _, start_line, start_col, end_line, end_col } =
-            source_region;
-        match *mapping_kind {
-            MappingKind::Code(term) => Self::code_region(
-                Counter::from_term(term),
-                local_file_id,
-                start_line,
-                start_col,
-                end_line,
-                end_col,
-            ),
-            MappingKind::Branch { true_term, false_term } => Self::branch_region(
-                Counter::from_term(true_term),
-                Counter::from_term(false_term),
-                local_file_id,
-                start_line,
-                start_col,
-                end_line,
-                end_col,
-            ),
-            MappingKind::MCDCBranch { true_term, false_term, mcdc_params } => {
-                Self::mcdc_branch_region(
-                    Counter::from_term(true_term),
-                    Counter::from_term(false_term),
-                    mcdc_params,
-                    local_file_id,
-                    start_line,
-                    start_col,
-                    end_line,
-                    end_col,
-                )
-            }
-            MappingKind::MCDCDecision(decision_info) => Self::decision_region(
-                decision_info,
-                local_file_id,
-                start_line,
-                start_col,
-                end_line,
-                end_col,
-            ),
-        }
+impl CoverageSpan {
+    pub(crate) fn from_source_region(file_id: u32, code_region: &SourceRegion) -> Self {
+        let &SourceRegion { file_name: _, start_line, start_col, end_line, end_col } = code_region;
+        // Internally, LLVM uses the high bit of `end_col` to distinguish between
+        // code regions and gap regions, so it can't be used by the column number.
+        assert!(end_col & (1u32 << 31) == 0, "high bit of `end_col` must be unset: {end_col:#X}");
+        Self { file_id, start_line, start_col, end_line, end_col }
     }
+}
 
-    pub(crate) fn code_region(
-        counter: Counter,
-        file_id: u32,
-        start_line: u32,
-        start_col: u32,
-        end_line: u32,
-        end_col: u32,
-    ) -> Self {
-        Self {
-            counter,
-            false_counter: Counter::ZERO,
-            mcdc_params: mcdc::Parameters::none(),
-            file_id,
-            expanded_file_id: 0,
-            start_line,
-            start_col,
-            end_line,
-            end_col,
-            kind: RegionKind::CodeRegion,
-        }
-    }
+/// Must match the layout of `LLVMRustCoverageCodeRegion`.
+#[derive(Clone, Debug)]
+#[repr(C)]
+pub(crate) struct CodeRegion {
+    pub(crate) span: CoverageSpan,
+    pub(crate) counter: Counter,
+}
 
-    pub(crate) fn branch_region(
-        counter: Counter,
-        false_counter: Counter,
-        file_id: u32,
-        start_line: u32,
-        start_col: u32,
-        end_line: u32,
-        end_col: u32,
-    ) -> Self {
-        Self {
-            counter,
-            false_counter,
-            mcdc_params: mcdc::Parameters::none(),
-            file_id,
-            expanded_file_id: 0,
-            start_line,
-            start_col,
-            end_line,
-            end_col,
-            kind: RegionKind::BranchRegion,
-        }
-    }
+/// Must match the layout of `LLVMRustCoverageBranchRegion`.
+#[derive(Clone, Debug)]
+#[repr(C)]
+pub(crate) struct BranchRegion {
+    pub(crate) span: CoverageSpan,
+    pub(crate) true_counter: Counter,
+    pub(crate) false_counter: Counter,
+}
 
-    pub(crate) fn mcdc_branch_region(
-        counter: Counter,
-        false_counter: Counter,
-        condition_info: ConditionInfo,
-        file_id: u32,
-        start_line: u32,
-        start_col: u32,
-        end_line: u32,
-        end_col: u32,
-    ) -> Self {
-        Self {
-            counter,
-            false_counter,
-            mcdc_params: mcdc::Parameters::branch(condition_info.into()),
-            file_id,
-            expanded_file_id: 0,
-            start_line,
-            start_col,
-            end_line,
-            end_col,
-            kind: RegionKind::MCDCBranchRegion,
-        }
-    }
+/// Must match the layout of `LLVMRustCoverageMCDCBranchRegion`.
+#[derive(Clone, Debug)]
+#[repr(C)]
+pub(crate) struct MCDCBranchRegion {
+    pub(crate) span: CoverageSpan,
+    pub(crate) true_counter: Counter,
+    pub(crate) false_counter: Counter,
+    pub(crate) mcdc_branch_params: mcdc::BranchParameters,
+}
 
-    pub(crate) fn decision_region(
-        decision_info: DecisionInfo,
-        file_id: u32,
-        start_line: u32,
-        start_col: u32,
-        end_line: u32,
-        end_col: u32,
-    ) -> Self {
-        let mcdc_params = mcdc::Parameters::decision(decision_info.into());
-
-        Self {
-            counter: Counter::ZERO,
-            false_counter: Counter::ZERO,
-            mcdc_params,
-            file_id,
-            expanded_file_id: 0,
-            start_line,
-            start_col,
-            end_line,
-            end_col,
-            kind: RegionKind::MCDCDecisionRegion,
-        }
-    }
-
-    // This function might be used in the future; the LLVM API is still evolving, as is coverage
-    // support.
-    #[allow(dead_code)]
-    pub(crate) fn expansion_region(
-        file_id: u32,
-        expanded_file_id: u32,
-        start_line: u32,
-        start_col: u32,
-        end_line: u32,
-        end_col: u32,
-    ) -> Self {
-        Self {
-            counter: Counter::ZERO,
-            false_counter: Counter::ZERO,
-            mcdc_params: mcdc::Parameters::none(),
-            file_id,
-            expanded_file_id,
-            start_line,
-            start_col,
-            end_line,
-            end_col,
-            kind: RegionKind::ExpansionRegion,
-        }
-    }
-
-    // This function might be used in the future; the LLVM API is still evolving, as is coverage
-    // support.
-    #[allow(dead_code)]
-    pub(crate) fn skipped_region(
-        file_id: u32,
-        start_line: u32,
-        start_col: u32,
-        end_line: u32,
-        end_col: u32,
-    ) -> Self {
-        Self {
-            counter: Counter::ZERO,
-            false_counter: Counter::ZERO,
-            mcdc_params: mcdc::Parameters::none(),
-            file_id,
-            expanded_file_id: 0,
-            start_line,
-            start_col,
-            end_line,
-            end_col,
-            kind: RegionKind::SkippedRegion,
-        }
-    }
-
-    // This function might be used in the future; the LLVM API is still evolving, as is coverage
-    // support.
-    #[allow(dead_code)]
-    pub(crate) fn gap_region(
-        counter: Counter,
-        file_id: u32,
-        start_line: u32,
-        start_col: u32,
-        end_line: u32,
-        end_col: u32,
-    ) -> Self {
-        Self {
-            counter,
-            false_counter: Counter::ZERO,
-            mcdc_params: mcdc::Parameters::none(),
-            file_id,
-            expanded_file_id: 0,
-            start_line,
-            start_col,
-            end_line,
-            end_col: (1_u32 << 31) | end_col,
-            kind: RegionKind::GapRegion,
-        }
-    }
+/// Must match the layout of `LLVMRustCoverageMCDCDecisionRegion`.
+#[derive(Clone, Debug)]
+#[repr(C)]
+pub(crate) struct MCDCDecisionRegion {
+    pub(crate) span: CoverageSpan,
+    pub(crate) mcdc_decision_params: mcdc::DecisionParameters,
 }
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
index cee704a..8edd788 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
@@ -1,18 +1,23 @@
-use std::ffi::CStr;
+use std::ffi::CString;
 
 use itertools::Itertools as _;
-use rustc_codegen_ssa::traits::{BaseTypeCodegenMethods, ConstCodegenMethods};
+use rustc_abi::Align;
+use rustc_codegen_ssa::traits::{
+    BaseTypeCodegenMethods, ConstCodegenMethods, StaticCodegenMethods,
+};
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_index::IndexVec;
+use rustc_middle::mir::coverage::MappingKind;
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_middle::{bug, mir};
 use rustc_span::Symbol;
 use rustc_span::def_id::DefIdSet;
+use rustc_target::spec::HasTargetSpec;
 use tracing::debug;
 
 use crate::common::CodegenCx;
-use crate::coverageinfo::ffi::CounterMappingRegion;
+use crate::coverageinfo::ffi;
 use crate::coverageinfo::map_data::{FunctionCoverage, FunctionCoverageCollector};
 use crate::{coverageinfo, llvm};
 
@@ -49,11 +54,7 @@
         add_unused_functions(cx);
     }
 
-    let function_coverage_map = match cx.coverage_context() {
-        Some(ctx) => ctx.take_function_coverage_map(),
-        None => return,
-    };
-
+    let function_coverage_map = cx.coverage_cx().take_function_coverage_map();
     if function_coverage_map.is_empty() {
         // This module has no functions with coverage instrumentation
         return;
@@ -77,11 +78,9 @@
 
     // Generate the coverage map header, which contains the filenames used by
     // this CGU's coverage mappings, and store it in a well-known global.
-    let cov_data_val = generate_coverage_map(cx, covmap_version, filenames_size, filenames_val);
-    coverageinfo::save_cov_data_to_mod(cx, cov_data_val);
+    generate_covmap_record(cx, covmap_version, filenames_size, filenames_val);
 
     let mut unused_function_names = Vec::new();
-    let covfun_section_name = coverageinfo::covfun_section_name(cx);
 
     // Encode coverage mappings and generate function records
     for (instance, function_coverage) in function_coverage_entries {
@@ -110,9 +109,8 @@
             unused_function_names.push(mangled_function_name);
         }
 
-        save_function_record(
+        generate_covfun_record(
             cx,
-            &covfun_section_name,
             mangled_function_name,
             source_hash,
             filenames_ref,
@@ -237,7 +235,10 @@
     let expressions = function_coverage.counter_expressions().collect::<Vec<_>>();
 
     let mut virtual_file_mapping = VirtualFileMapping::default();
-    let mut mapping_regions = Vec::with_capacity(counter_regions.len());
+    let mut code_regions = vec![];
+    let mut branch_regions = vec![];
+    let mut mcdc_branch_regions = vec![];
+    let mut mcdc_decision_regions = vec![];
 
     // Group mappings into runs with the same filename, preserving the order
     // yielded by `FunctionCoverage`.
@@ -257,11 +258,36 @@
         // form suitable for FFI.
         for (mapping_kind, region) in counter_regions_for_file {
             debug!("Adding counter {mapping_kind:?} to map for {region:?}");
-            mapping_regions.push(CounterMappingRegion::from_mapping(
-                &mapping_kind,
-                local_file_id.as_u32(),
-                region,
-            ));
+            let span = ffi::CoverageSpan::from_source_region(local_file_id.as_u32(), region);
+            match mapping_kind {
+                MappingKind::Code(term) => {
+                    code_regions
+                        .push(ffi::CodeRegion { span, counter: ffi::Counter::from_term(term) });
+                }
+                MappingKind::Branch { true_term, false_term } => {
+                    branch_regions.push(ffi::BranchRegion {
+                        span,
+                        true_counter: ffi::Counter::from_term(true_term),
+                        false_counter: ffi::Counter::from_term(false_term),
+                    });
+                }
+                MappingKind::MCDCBranch { true_term, false_term, mcdc_params } => {
+                    mcdc_branch_regions.push(ffi::MCDCBranchRegion {
+                        span,
+                        true_counter: ffi::Counter::from_term(true_term),
+                        false_counter: ffi::Counter::from_term(false_term),
+                        mcdc_branch_params: ffi::mcdc::BranchParameters::from(mcdc_params),
+                    });
+                }
+                MappingKind::MCDCDecision(mcdc_decision_params) => {
+                    mcdc_decision_regions.push(ffi::MCDCDecisionRegion {
+                        span,
+                        mcdc_decision_params: ffi::mcdc::DecisionParameters::from(
+                            mcdc_decision_params,
+                        ),
+                    });
+                }
+            }
         }
     }
 
@@ -270,21 +296,24 @@
         coverageinfo::write_mapping_to_buffer(
             virtual_file_mapping.into_vec(),
             expressions,
-            mapping_regions,
+            &code_regions,
+            &branch_regions,
+            &mcdc_branch_regions,
+            &mcdc_decision_regions,
             buffer,
         );
     })
 }
 
-/// Construct coverage map header and the array of function records, and combine them into the
-/// coverage map. Save the coverage map data into the LLVM IR as a static global using a
-/// specific, well-known section and name.
-fn generate_coverage_map<'ll>(
+/// Generates the contents of the covmap record for this CGU, which mostly
+/// consists of a header and a list of filenames. The record is then stored
+/// as a global variable in the `__llvm_covmap` section.
+fn generate_covmap_record<'ll>(
     cx: &CodegenCx<'ll, '_>,
     version: u32,
     filenames_size: usize,
     filenames_val: &'ll llvm::Value,
-) -> &'ll llvm::Value {
+) {
     debug!("cov map: filenames_size = {}, 0-based version = {}", filenames_size, version);
 
     // Create the coverage data header (Note, fields 0 and 2 are now always zero,
@@ -299,15 +328,37 @@
     );
 
     // Create the complete LLVM coverage data value to add to the LLVM IR
-    cx.const_struct(&[cov_data_header_val, filenames_val], /*packed=*/ false)
+    let covmap_data =
+        cx.const_struct(&[cov_data_header_val, filenames_val], /*packed=*/ false);
+
+    let covmap_var_name = CString::new(llvm::build_byte_buffer(|s| unsafe {
+        llvm::LLVMRustCoverageWriteMappingVarNameToString(s);
+    }))
+    .unwrap();
+    debug!("covmap var name: {:?}", covmap_var_name);
+
+    let covmap_section_name = CString::new(llvm::build_byte_buffer(|s| unsafe {
+        llvm::LLVMRustCoverageWriteMapSectionNameToString(cx.llmod, s);
+    }))
+    .expect("covmap section name should not contain NUL");
+    debug!("covmap section name: {:?}", covmap_section_name);
+
+    let llglobal = llvm::add_global(cx.llmod, cx.val_ty(covmap_data), &covmap_var_name);
+    llvm::set_initializer(llglobal, covmap_data);
+    llvm::set_global_constant(llglobal, true);
+    llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage);
+    llvm::set_section(llglobal, &covmap_section_name);
+    // LLVM's coverage mapping format specifies 8-byte alignment for items in this section.
+    // <https://llvm.org/docs/CoverageMappingFormat.html>
+    llvm::set_alignment(llglobal, Align::EIGHT);
+    cx.add_used_global(llglobal);
 }
 
-/// Construct a function record and combine it with the function's coverage mapping data.
-/// Save the function record into the LLVM IR as a static global using a
-/// specific, well-known section and name.
-fn save_function_record(
+/// Generates the contents of the covfun record for this function, which
+/// contains the function's coverage mapping data. The record is then stored
+/// as a global variable in the `__llvm_covfun` section.
+fn generate_covfun_record(
     cx: &CodegenCx<'_, '_>,
-    covfun_section_name: &CStr,
     mangled_function_name: &str,
     source_hash: u64,
     filenames_ref: u64,
@@ -334,13 +385,28 @@
         /*packed=*/ true,
     );
 
-    coverageinfo::save_func_record_to_mod(
-        cx,
-        covfun_section_name,
-        func_name_hash,
-        func_record_val,
-        is_used,
-    );
+    // Choose a variable name to hold this function's covfun data.
+    // Functions that are used have a suffix ("u") to distinguish them from
+    // unused copies of the same function (from different CGUs), so that if a
+    // linker sees both it won't discard the used copy's data.
+    let func_record_var_name =
+        CString::new(format!("__covrec_{:X}{}", func_name_hash, if is_used { "u" } else { "" }))
+            .unwrap();
+    debug!("function record var name: {:?}", func_record_var_name);
+
+    let llglobal = llvm::add_global(cx.llmod, cx.val_ty(func_record_val), &func_record_var_name);
+    llvm::set_initializer(llglobal, func_record_val);
+    llvm::set_global_constant(llglobal, true);
+    llvm::set_linkage(llglobal, llvm::Linkage::LinkOnceODRLinkage);
+    llvm::set_visibility(llglobal, llvm::Visibility::Hidden);
+    llvm::set_section(llglobal, cx.covfun_section_name());
+    // LLVM's coverage mapping format specifies 8-byte alignment for items in this section.
+    // <https://llvm.org/docs/CoverageMappingFormat.html>
+    llvm::set_alignment(llglobal, Align::EIGHT);
+    if cx.target_spec().supports_comdat() {
+        llvm::set_comdat(cx.llmod, llglobal, &func_record_var_name);
+    }
+    cx.add_used_global(llglobal);
 }
 
 /// Each CGU will normally only emit coverage metadata for the functions that it actually generates.
@@ -472,9 +538,5 @@
     // zero, because none of its counters/expressions are marked as seen.
     let function_coverage = FunctionCoverageCollector::unused(instance, function_coverage_info);
 
-    if let Some(coverage_context) = cx.coverage_context() {
-        coverage_context.function_coverage_map.borrow_mut().insert(instance, function_coverage);
-    } else {
-        bug!("Could not get the `coverage_context`");
-    }
+    cx.coverage_cx().function_coverage_map.borrow_mut().insert(instance, function_coverage);
 }
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
index 484a4d0..c6b2a62 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
@@ -1,24 +1,20 @@
-use std::cell::RefCell;
+use std::cell::{OnceCell, RefCell};
 use std::ffi::{CStr, CString};
 
 use libc::c_uint;
 use rustc_codegen_ssa::traits::{
-    BaseTypeCodegenMethods, BuilderMethods, ConstCodegenMethods, CoverageInfoBuilderMethods,
-    MiscCodegenMethods, StaticCodegenMethods,
+    BuilderMethods, ConstCodegenMethods, CoverageInfoBuilderMethods, MiscCodegenMethods,
 };
 use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
 use rustc_llvm::RustString;
-use rustc_middle::bug;
 use rustc_middle::mir::coverage::CoverageKind;
 use rustc_middle::ty::Instance;
 use rustc_middle::ty::layout::HasTyCtxt;
-use rustc_target::abi::{Align, Size};
-use rustc_target::spec::HasTargetSpec;
+use rustc_target::abi::Size;
 use tracing::{debug, instrument};
 
 use crate::builder::Builder;
 use crate::common::CodegenCx;
-use crate::coverageinfo::ffi::{CounterExpression, CounterMappingRegion};
 use crate::coverageinfo::map_data::FunctionCoverageCollector;
 use crate::llvm;
 
@@ -33,6 +29,8 @@
         RefCell<FxIndexMap<Instance<'tcx>, FunctionCoverageCollector<'tcx>>>,
     pub(crate) pgo_func_name_var_map: RefCell<FxHashMap<Instance<'tcx>, &'ll llvm::Value>>,
     pub(crate) mcdc_condition_bitmap_map: RefCell<FxHashMap<Instance<'tcx>, Vec<&'ll llvm::Value>>>,
+
+    covfun_section_name: OnceCell<CString>,
 }
 
 impl<'ll, 'tcx> CrateCoverageContext<'ll, 'tcx> {
@@ -41,6 +39,7 @@
             function_coverage_map: Default::default(),
             pgo_func_name_var_map: Default::default(),
             mcdc_condition_bitmap_map: Default::default(),
+            covfun_section_name: Default::default(),
         }
     }
 
@@ -67,27 +66,38 @@
     }
 }
 
-// These methods used to be part of trait `CoverageInfoMethods`, which no longer
-// exists after most coverage code was moved out of SSA.
 impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
     pub(crate) fn coverageinfo_finalize(&self) {
         mapgen::finalize(self)
     }
 
+    /// Returns the section name to use when embedding per-function coverage information
+    /// in the object file, according to the target's object file format. LLVM's coverage
+    /// tools use information from this section when producing coverage reports.
+    ///
+    /// Typical values are:
+    /// - `__llvm_covfun` on Linux
+    /// - `__LLVM_COV,__llvm_covfun` on macOS (includes `__LLVM_COV,` segment prefix)
+    /// - `.lcovfun$M` on Windows (includes `$M` sorting suffix)
+    fn covfun_section_name(&self) -> &CStr {
+        self.coverage_cx().covfun_section_name.get_or_init(|| {
+            CString::new(llvm::build_byte_buffer(|s| unsafe {
+                llvm::LLVMRustCoverageWriteFuncSectionNameToString(self.llmod, s);
+            }))
+            .expect("covfun section name should not contain NUL")
+        })
+    }
+
     /// For LLVM codegen, returns a function-specific `Value` for a global
     /// string, to hold the function name passed to LLVM intrinsic
     /// `instrprof.increment()`. The `Value` is only created once per instance.
     /// Multiple invocations with the same instance return the same `Value`.
     fn get_pgo_func_name_var(&self, instance: Instance<'tcx>) -> &'ll llvm::Value {
-        if let Some(coverage_context) = self.coverage_context() {
-            debug!("getting pgo_func_name_var for instance={:?}", instance);
-            let mut pgo_func_name_var_map = coverage_context.pgo_func_name_var_map.borrow_mut();
-            pgo_func_name_var_map
-                .entry(instance)
-                .or_insert_with(|| create_pgo_func_name_var(self, instance))
-        } else {
-            bug!("Could not get the `coverage_context`");
-        }
+        debug!("getting pgo_func_name_var for instance={:?}", instance);
+        let mut pgo_func_name_var_map = self.coverage_cx().pgo_func_name_var_map.borrow_mut();
+        pgo_func_name_var_map
+            .entry(instance)
+            .or_insert_with(|| create_pgo_func_name_var(self, instance))
     }
 }
 
@@ -121,11 +131,7 @@
             cond_bitmaps.push(cond_bitmap);
         }
 
-        self.coverage_context()
-            .expect("always present when coverage is enabled")
-            .mcdc_condition_bitmap_map
-            .borrow_mut()
-            .insert(instance, cond_bitmaps);
+        self.coverage_cx().mcdc_condition_bitmap_map.borrow_mut().insert(instance, cond_bitmaps);
     }
 
     #[instrument(level = "debug", skip(self))]
@@ -146,8 +152,7 @@
             return;
         };
 
-        let Some(coverage_context) = bx.coverage_context() else { return };
-        let mut coverage_map = coverage_context.function_coverage_map.borrow_mut();
+        let mut coverage_map = bx.coverage_cx().function_coverage_map.borrow_mut();
         let func_coverage = coverage_map
             .entry(instance)
             .or_insert_with(|| FunctionCoverageCollector::new(instance, function_coverage_info));
@@ -189,7 +194,8 @@
             }
             CoverageKind::CondBitmapUpdate { index, decision_depth } => {
                 drop(coverage_map);
-                let cond_bitmap = coverage_context
+                let cond_bitmap = bx
+                    .coverage_cx()
                     .try_get_mcdc_condition_bitmap(&instance, decision_depth)
                     .expect("mcdc cond bitmap should have been allocated for updating");
                 let cond_index = bx.const_i32(index as i32);
@@ -197,7 +203,7 @@
             }
             CoverageKind::TestVectorBitmapUpdate { bitmap_idx, decision_depth } => {
                 drop(coverage_map);
-                let cond_bitmap = coverage_context
+                let cond_bitmap = bx.coverage_cx()
                                     .try_get_mcdc_condition_bitmap(&instance, decision_depth)
                                     .expect("mcdc cond bitmap should have been allocated for merging into the global bitmap");
                 assert!(
@@ -209,6 +215,7 @@
                 let hash = bx.const_u64(function_coverage_info.function_source_hash);
                 let bitmap_index = bx.const_u32(bitmap_idx);
                 bx.mcdc_tvbitmap_update(fn_name, hash, bitmap_index, cond_bitmap);
+                bx.mcdc_condbitmap_reset(cond_bitmap);
             }
         }
     }
@@ -257,8 +264,11 @@
 
 pub(crate) fn write_mapping_to_buffer(
     virtual_file_mapping: Vec<u32>,
-    expressions: Vec<CounterExpression>,
-    mapping_regions: Vec<CounterMappingRegion>,
+    expressions: Vec<ffi::CounterExpression>,
+    code_regions: &[ffi::CodeRegion],
+    branch_regions: &[ffi::BranchRegion],
+    mcdc_branch_regions: &[ffi::MCDCBranchRegion],
+    mcdc_decision_regions: &[ffi::MCDCDecisionRegion],
     buffer: &RustString,
 ) {
     unsafe {
@@ -267,8 +277,14 @@
             virtual_file_mapping.len() as c_uint,
             expressions.as_ptr(),
             expressions.len() as c_uint,
-            mapping_regions.as_ptr(),
-            mapping_regions.len() as c_uint,
+            code_regions.as_ptr(),
+            code_regions.len() as c_uint,
+            branch_regions.as_ptr(),
+            branch_regions.len() as c_uint,
+            mcdc_branch_regions.as_ptr(),
+            mcdc_branch_regions.len() as c_uint,
+            mcdc_decision_regions.as_ptr(),
+            mcdc_decision_regions.len() as c_uint,
             buffer,
         );
     }
@@ -281,82 +297,3 @@
 pub(crate) fn mapping_version() -> u32 {
     unsafe { llvm::LLVMRustCoverageMappingVersion() }
 }
-
-pub(crate) fn save_cov_data_to_mod<'ll, 'tcx>(
-    cx: &CodegenCx<'ll, 'tcx>,
-    cov_data_val: &'ll llvm::Value,
-) {
-    let covmap_var_name = CString::new(llvm::build_byte_buffer(|s| unsafe {
-        llvm::LLVMRustCoverageWriteMappingVarNameToString(s);
-    }))
-    .unwrap();
-    debug!("covmap var name: {:?}", covmap_var_name);
-
-    let covmap_section_name = CString::new(llvm::build_byte_buffer(|s| unsafe {
-        llvm::LLVMRustCoverageWriteMapSectionNameToString(cx.llmod, s);
-    }))
-    .expect("covmap section name should not contain NUL");
-    debug!("covmap section name: {:?}", covmap_section_name);
-
-    let llglobal = llvm::add_global(cx.llmod, cx.val_ty(cov_data_val), &covmap_var_name);
-    llvm::set_initializer(llglobal, cov_data_val);
-    llvm::set_global_constant(llglobal, true);
-    llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage);
-    llvm::set_section(llglobal, &covmap_section_name);
-    // LLVM's coverage mapping format specifies 8-byte alignment for items in this section.
-    llvm::set_alignment(llglobal, Align::EIGHT);
-    cx.add_used_global(llglobal);
-}
-
-pub(crate) fn save_func_record_to_mod<'ll, 'tcx>(
-    cx: &CodegenCx<'ll, 'tcx>,
-    covfun_section_name: &CStr,
-    func_name_hash: u64,
-    func_record_val: &'ll llvm::Value,
-    is_used: bool,
-) {
-    // Assign a name to the function record. This is used to merge duplicates.
-    //
-    // In LLVM, a "translation unit" (effectively, a `Crate` in Rust) can describe functions that
-    // are included-but-not-used. If (or when) Rust generates functions that are
-    // included-but-not-used, note that a dummy description for a function included-but-not-used
-    // in a Crate can be replaced by full description provided by a different Crate. The two kinds
-    // of descriptions play distinct roles in LLVM IR; therefore, assign them different names (by
-    // appending "u" to the end of the function record var name, to prevent `linkonce_odr` merging.
-    let func_record_var_name =
-        CString::new(format!("__covrec_{:X}{}", func_name_hash, if is_used { "u" } else { "" }))
-            .unwrap();
-    debug!("function record var name: {:?}", func_record_var_name);
-    debug!("function record section name: {:?}", covfun_section_name);
-
-    let llglobal = llvm::add_global(cx.llmod, cx.val_ty(func_record_val), &func_record_var_name);
-    llvm::set_initializer(llglobal, func_record_val);
-    llvm::set_global_constant(llglobal, true);
-    llvm::set_linkage(llglobal, llvm::Linkage::LinkOnceODRLinkage);
-    llvm::set_visibility(llglobal, llvm::Visibility::Hidden);
-    llvm::set_section(llglobal, covfun_section_name);
-    // LLVM's coverage mapping format specifies 8-byte alignment for items in this section.
-    llvm::set_alignment(llglobal, Align::EIGHT);
-    if cx.target_spec().supports_comdat() {
-        llvm::set_comdat(cx.llmod, llglobal, &func_record_var_name);
-    }
-    cx.add_used_global(llglobal);
-}
-
-/// Returns the section name string to pass through to the linker when embedding
-/// per-function coverage information in the object file, according to the target
-/// platform's object file format.
-///
-/// LLVM's coverage tools read coverage mapping details from this section when
-/// producing coverage reports.
-///
-/// Typical values are:
-/// - `__llvm_covfun` on Linux
-/// - `__LLVM_COV,__llvm_covfun` on macOS (includes `__LLVM_COV,` segment prefix)
-/// - `.lcovfun$M` on Windows (includes `$M` sorting suffix)
-pub(crate) fn covfun_section_name(cx: &CodegenCx<'_, '_>) -> CString {
-    CString::new(llvm::build_byte_buffer(|s| unsafe {
-        llvm::LLVMRustCoverageWriteFuncSectionNameToString(cx.llmod, s);
-    }))
-    .expect("covfun section name should not contain NUL")
-}
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs
index f93d3e4..7947c9c 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs
@@ -76,7 +76,7 @@
             llvm::LLVMSetInitializer(section_var, cx.const_bytes(section_contents));
             llvm::LLVMSetGlobalConstant(section_var, llvm::True);
             llvm::LLVMSetUnnamedAddress(section_var, llvm::UnnamedAddr::Global);
-            llvm::LLVMRustSetLinkage(section_var, llvm::Linkage::LinkOnceODRLinkage);
+            llvm::set_linkage(section_var, llvm::Linkage::LinkOnceODRLinkage);
             // This should make sure that the whole section is not larger than
             // the string it contains. Otherwise we get a warning from GDB.
             llvm::LLVMSetAlignment(section_var, 1);
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
index 1a8153a..3de4ca7 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
@@ -350,7 +350,6 @@
         type_names::push_generic_params(
             tcx,
             tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), args),
-            enclosing_fn_def_id,
             &mut name,
         );
 
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index c9a17c9..d04b525 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -785,13 +785,12 @@
         let type_info =
             bx.const_struct(&[type_info_vtable, bx.const_null(bx.type_ptr()), type_name], false);
         let tydesc = bx.declare_global("__rust_panic_type_info", bx.val_ty(type_info));
-        unsafe {
-            llvm::LLVMRustSetLinkage(tydesc, llvm::Linkage::LinkOnceODRLinkage);
-            if bx.cx.tcx.sess.target.supports_comdat() {
-                llvm::SetUniqueComdat(bx.llmod, tydesc);
-            }
-            llvm::LLVMSetInitializer(tydesc, type_info);
+
+        llvm::set_linkage(tydesc, llvm::Linkage::LinkOnceODRLinkage);
+        if bx.cx.tcx.sess.target.supports_comdat() {
+            llvm::SetUniqueComdat(bx.llmod, tydesc);
         }
+        unsafe { llvm::LLVMSetInitializer(tydesc, type_info) };
 
         // The flag value of 8 indicates that we are catching the exception by
         // reference instead of by value. We can't use catch by value because
@@ -1064,7 +1063,7 @@
     cx.set_frame_pointer_type(llfn);
     cx.apply_target_cpu_attr(llfn);
     // FIXME(eddyb) find a nicer way to do this.
-    unsafe { llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::InternalLinkage) };
+    llvm::set_linkage(llfn, llvm::Linkage::InternalLinkage);
     let llbb = Builder::append_block(cx, llfn, "entry-block");
     let bx = Builder::build(cx, llbb);
     codegen(bx);
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index d0034de..acc6607 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -1,9 +1,11 @@
 #![allow(non_camel_case_types)]
 #![allow(non_upper_case_globals)]
 
+use std::fmt::Debug;
 use std::marker::PhantomData;
 
 use libc::{c_char, c_int, c_uint, c_ulonglong, c_void, size_t};
+use rustc_macros::TryFromU32;
 use rustc_target::spec::SymbolVisibility;
 
 use super::RustString;
@@ -19,6 +21,30 @@
 pub const True: Bool = 1 as Bool;
 pub const False: Bool = 0 as Bool;
 
+/// Wrapper for a raw enum value returned from LLVM's C APIs.
+///
+/// For C enums returned by LLVM, it's risky to use a Rust enum as the return
+/// type, because it would be UB if a later version of LLVM adds a new enum
+/// value and returns it. Instead, return this raw wrapper, then convert to the
+/// Rust-side enum explicitly.
+#[repr(transparent)]
+pub struct RawEnum<T> {
+    value: u32,
+    /// We don't own or consume a `T`, but we can produce one.
+    _rust_side_type: PhantomData<fn() -> T>,
+}
+
+impl<T: TryFrom<u32>> RawEnum<T> {
+    #[track_caller]
+    pub(crate) fn to_rust(self) -> T
+    where
+        T::Error: Debug,
+    {
+        // If this fails, the Rust-side enum is out of sync with LLVM's enum.
+        T::try_from(self.value).expect("enum value returned by LLVM should be known")
+    }
+}
+
 #[derive(Copy, Clone, PartialEq)]
 #[repr(C)]
 #[allow(dead_code)] // Variants constructed by C++.
@@ -108,26 +134,36 @@
     AvrInterrupt = 85,
 }
 
-/// LLVMRustLinkage
-#[derive(Copy, Clone, PartialEq)]
+/// Must match the layout of `LLVMLinkage`.
+#[derive(Copy, Clone, PartialEq, TryFromU32)]
 #[repr(C)]
 pub enum Linkage {
     ExternalLinkage = 0,
     AvailableExternallyLinkage = 1,
     LinkOnceAnyLinkage = 2,
     LinkOnceODRLinkage = 3,
-    WeakAnyLinkage = 4,
-    WeakODRLinkage = 5,
-    AppendingLinkage = 6,
-    InternalLinkage = 7,
-    PrivateLinkage = 8,
-    ExternalWeakLinkage = 9,
-    CommonLinkage = 10,
+    #[deprecated = "marked obsolete by LLVM"]
+    LinkOnceODRAutoHideLinkage = 4,
+    WeakAnyLinkage = 5,
+    WeakODRLinkage = 6,
+    AppendingLinkage = 7,
+    InternalLinkage = 8,
+    PrivateLinkage = 9,
+    #[deprecated = "marked obsolete by LLVM"]
+    DLLImportLinkage = 10,
+    #[deprecated = "marked obsolete by LLVM"]
+    DLLExportLinkage = 11,
+    ExternalWeakLinkage = 12,
+    #[deprecated = "marked obsolete by LLVM"]
+    GhostLinkage = 13,
+    CommonLinkage = 14,
+    LinkerPrivateLinkage = 15,
+    LinkerPrivateWeakLinkage = 16,
 }
 
-// LLVMRustVisibility
+/// Must match the layout of `LLVMVisibility`.
 #[repr(C)]
-#[derive(Copy, Clone, PartialEq)]
+#[derive(Copy, Clone, PartialEq, TryFromU32)]
 pub enum Visibility {
     Default = 0,
     Hidden = 1,
@@ -945,7 +981,11 @@
 
     // Operations on global variables, functions, and aliases (globals)
     pub fn LLVMIsDeclaration(Global: &Value) -> Bool;
+    pub fn LLVMGetLinkage(Global: &Value) -> RawEnum<Linkage>;
+    pub fn LLVMSetLinkage(Global: &Value, RustLinkage: Linkage);
     pub fn LLVMSetSection(Global: &Value, Section: *const c_char);
+    pub fn LLVMGetVisibility(Global: &Value) -> RawEnum<Visibility>;
+    pub fn LLVMSetVisibility(Global: &Value, Viz: Visibility);
     pub fn LLVMGetAlignment(Global: &Value) -> c_uint;
     pub fn LLVMSetAlignment(Global: &Value, Bytes: c_uint);
     pub fn LLVMSetDLLStorageClass(V: &Value, C: DLLStorageClass);
@@ -1521,10 +1561,6 @@
     ) -> bool;
 
     // Operations on global variables, functions, and aliases (globals)
-    pub fn LLVMRustGetLinkage(Global: &Value) -> Linkage;
-    pub fn LLVMRustSetLinkage(Global: &Value, RustLinkage: Linkage);
-    pub fn LLVMRustGetVisibility(Global: &Value) -> Visibility;
-    pub fn LLVMRustSetVisibility(Global: &Value, Viz: Visibility);
     pub fn LLVMRustSetDSOLocal(Global: &Value, is_dso_local: bool);
 
     // Operations on global variables
@@ -1615,10 +1651,6 @@
     pub fn LLVMRustSetAllowReassoc(Instr: &Value);
 
     // Miscellaneous instructions
-    pub fn LLVMRustGetInstrProfIncrementIntrinsic(M: &Module) -> &Value;
-    pub fn LLVMRustGetInstrProfMCDCParametersIntrinsic(M: &Module) -> &Value;
-    pub fn LLVMRustGetInstrProfMCDCTVBitmapUpdateIntrinsic(M: &Module) -> &Value;
-
     pub fn LLVMRustBuildCall<'a>(
         B: &Builder<'a>,
         Ty: &'a Type,
@@ -1744,7 +1776,7 @@
     ) -> bool;
 
     #[allow(improper_ctypes)]
-    pub fn LLVMRustCoverageWriteFilenamesSectionToBuffer(
+    pub(crate) fn LLVMRustCoverageWriteFilenamesSectionToBuffer(
         Filenames: *const *const c_char,
         FilenamesLen: size_t,
         Lengths: *const size_t,
@@ -1753,33 +1785,39 @@
     );
 
     #[allow(improper_ctypes)]
-    pub fn LLVMRustCoverageWriteMappingToBuffer(
+    pub(crate) fn LLVMRustCoverageWriteMappingToBuffer(
         VirtualFileMappingIDs: *const c_uint,
         NumVirtualFileMappingIDs: c_uint,
         Expressions: *const crate::coverageinfo::ffi::CounterExpression,
         NumExpressions: c_uint,
-        MappingRegions: *const crate::coverageinfo::ffi::CounterMappingRegion,
-        NumMappingRegions: c_uint,
+        CodeRegions: *const crate::coverageinfo::ffi::CodeRegion,
+        NumCodeRegions: c_uint,
+        BranchRegions: *const crate::coverageinfo::ffi::BranchRegion,
+        NumBranchRegions: c_uint,
+        MCDCBranchRegions: *const crate::coverageinfo::ffi::MCDCBranchRegion,
+        NumMCDCBranchRegions: c_uint,
+        MCDCDecisionRegions: *const crate::coverageinfo::ffi::MCDCDecisionRegion,
+        NumMCDCDecisionRegions: c_uint,
         BufferOut: &RustString,
     );
 
-    pub fn LLVMRustCoverageCreatePGOFuncNameVar(
+    pub(crate) fn LLVMRustCoverageCreatePGOFuncNameVar(
         F: &Value,
         FuncName: *const c_char,
         FuncNameLen: size_t,
     ) -> &Value;
-    pub fn LLVMRustCoverageHashByteArray(Bytes: *const c_char, NumBytes: size_t) -> u64;
+    pub(crate) fn LLVMRustCoverageHashByteArray(Bytes: *const c_char, NumBytes: size_t) -> u64;
 
     #[allow(improper_ctypes)]
-    pub fn LLVMRustCoverageWriteMapSectionNameToString(M: &Module, Str: &RustString);
+    pub(crate) fn LLVMRustCoverageWriteMapSectionNameToString(M: &Module, Str: &RustString);
 
     #[allow(improper_ctypes)]
-    pub fn LLVMRustCoverageWriteFuncSectionNameToString(M: &Module, Str: &RustString);
+    pub(crate) fn LLVMRustCoverageWriteFuncSectionNameToString(M: &Module, Str: &RustString);
 
     #[allow(improper_ctypes)]
-    pub fn LLVMRustCoverageWriteMappingVarNameToString(Str: &RustString);
+    pub(crate) fn LLVMRustCoverageWriteMappingVarNameToString(Str: &RustString);
 
-    pub fn LLVMRustCoverageMappingVersion() -> u32;
+    pub(crate) fn LLVMRustCoverageMappingVersion() -> u32;
     pub fn LLVMRustDebugMetadataVersion() -> u32;
     pub fn LLVMRustVersionMajor() -> u32;
     pub fn LLVMRustVersionMinor() -> u32;
diff --git a/compiler/rustc_codegen_llvm/src/llvm/mod.rs b/compiler/rustc_codegen_llvm/src/llvm/mod.rs
index e837022..6aac2ee 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/mod.rs
@@ -232,15 +232,23 @@
     }
 }
 
+pub fn get_linkage(llglobal: &Value) -> Linkage {
+    unsafe { LLVMGetLinkage(llglobal) }.to_rust()
+}
+
 pub fn set_linkage(llglobal: &Value, linkage: Linkage) {
     unsafe {
-        LLVMRustSetLinkage(llglobal, linkage);
+        LLVMSetLinkage(llglobal, linkage);
     }
 }
 
+pub fn get_visibility(llglobal: &Value) -> Visibility {
+    unsafe { LLVMGetVisibility(llglobal) }.to_rust()
+}
+
 pub fn set_visibility(llglobal: &Value, visibility: Visibility) {
     unsafe {
-        LLVMRustSetVisibility(llglobal, visibility);
+        LLVMSetVisibility(llglobal, visibility);
     }
 }
 
diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index 5793621..aa38c02 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -248,6 +248,7 @@
         ("aarch64", "pmuv3") => Some(LLVMFeature::new("perfmon")),
         ("aarch64", "paca") => Some(LLVMFeature::new("pauth")),
         ("aarch64", "pacg") => Some(LLVMFeature::new("pauth")),
+        ("aarch64", "pauth-lr") if get_version().0 < 19 => None,
         // Before LLVM 20 those two features were packaged together as b16b16
         ("aarch64", "sve-b16b16") if get_version().0 < 20 => Some(LLVMFeature::new("b16b16")),
         ("aarch64", "sme-b16b16") if get_version().0 < 20 => Some(LLVMFeature::new("b16b16")),
diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs
index bf6ef21..ea8857b 100644
--- a/compiler/rustc_codegen_llvm/src/mono_item.rs
+++ b/compiler/rustc_codegen_llvm/src/mono_item.rs
@@ -39,9 +39,9 @@
                 .emit_fatal(SymbolAlreadyDefined { span: self.tcx.def_span(def_id), symbol_name })
         });
 
+        llvm::set_linkage(g, base::linkage_to_llvm(linkage));
+        llvm::set_visibility(g, base::visibility_to_llvm(visibility));
         unsafe {
-            llvm::LLVMRustSetLinkage(g, base::linkage_to_llvm(linkage));
-            llvm::LLVMRustSetVisibility(g, base::visibility_to_llvm(visibility));
             if self.should_assume_dso_local(g, false) {
                 llvm::LLVMRustSetDSOLocal(g, true);
             }
@@ -61,7 +61,7 @@
 
         let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty());
         let lldecl = self.declare_fn(symbol_name, fn_abi, Some(instance));
-        unsafe { llvm::LLVMRustSetLinkage(lldecl, base::linkage_to_llvm(linkage)) };
+        llvm::set_linkage(lldecl, base::linkage_to_llvm(linkage));
         let attrs = self.tcx.codegen_fn_attrs(instance.def_id());
         base::set_link_section(lldecl, attrs);
         if (linkage == Linkage::LinkOnceODR || linkage == Linkage::WeakODR)
@@ -78,21 +78,15 @@
             && linkage != Linkage::Private
             && self.tcx.is_compiler_builtins(LOCAL_CRATE)
         {
-            unsafe {
-                llvm::LLVMRustSetVisibility(lldecl, llvm::Visibility::Hidden);
-            }
+            llvm::set_visibility(lldecl, llvm::Visibility::Hidden);
         } else {
-            unsafe {
-                llvm::LLVMRustSetVisibility(lldecl, base::visibility_to_llvm(visibility));
-            }
+            llvm::set_visibility(lldecl, base::visibility_to_llvm(visibility));
         }
 
         debug!("predefine_fn: instance = {:?}", instance);
 
-        unsafe {
-            if self.should_assume_dso_local(lldecl, false) {
-                llvm::LLVMRustSetDSOLocal(lldecl, true);
-            }
+        if self.should_assume_dso_local(lldecl, false) {
+            unsafe { llvm::LLVMRustSetDSOLocal(lldecl, true) };
         }
 
         self.instances.borrow_mut().insert(instance, lldecl);
@@ -102,13 +96,13 @@
 impl CodegenCx<'_, '_> {
     /// Whether a definition or declaration can be assumed to be local to a group of
     /// libraries that form a single DSO or executable.
-    pub(crate) unsafe fn should_assume_dso_local(
+    pub(crate) fn should_assume_dso_local(
         &self,
         llval: &llvm::Value,
         is_declaration: bool,
     ) -> bool {
-        let linkage = unsafe { llvm::LLVMRustGetLinkage(llval) };
-        let visibility = unsafe { llvm::LLVMRustGetVisibility(llval) };
+        let linkage = llvm::get_linkage(llval);
+        let visibility = llvm::get_visibility(llval);
 
         if matches!(linkage, llvm::Linkage::InternalLinkage | llvm::Linkage::PrivateLinkage) {
             return true;
diff --git a/compiler/rustc_codegen_llvm/src/type_of.rs b/compiler/rustc_codegen_llvm/src/type_of.rs
index 1af666f..6be4c3f 100644
--- a/compiler/rustc_codegen_llvm/src/type_of.rs
+++ b/compiler/rustc_codegen_llvm/src/type_of.rs
@@ -191,7 +191,7 @@
     /// `[T]` becomes `T`, while `str` and `Trait` turn into `i8` - this
     /// is useful for indexing slices, as `&[T]`'s data pointer is `T*`.
     /// If the type is an unsized struct, the regular layout is generated,
-    /// with the inner-most trailing unsized field using the "minimal unit"
+    /// with the innermost trailing unsized field using the "minimal unit"
     /// of that field's type - this is useful for taking the address of
     /// that field and ensuring the struct has the right alignment.
     fn llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> &'a Type {
diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
index 77c35a1..d966945 100644
--- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
+++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
@@ -312,7 +312,7 @@
 
             match *mono_item {
                 MonoItem::Fn(Instance { def: InstanceKind::Item(def), args }) => {
-                    if args.non_erasable_generics(tcx, def).next().is_some() {
+                    if args.non_erasable_generics().next().is_some() {
                         let symbol = ExportedSymbol::Generic(def, args);
                         symbols.push((symbol, SymbolExportInfo {
                             level: SymbolExportLevel::Rust,
@@ -321,12 +321,9 @@
                         }));
                     }
                 }
-                MonoItem::Fn(Instance { def: InstanceKind::DropGlue(def_id, Some(ty)), args }) => {
+                MonoItem::Fn(Instance { def: InstanceKind::DropGlue(_, Some(ty)), args }) => {
                     // A little sanity-check
-                    assert_eq!(
-                        args.non_erasable_generics(tcx, def_id).next(),
-                        Some(GenericArgKind::Type(ty))
-                    );
+                    assert_eq!(args.non_erasable_generics().next(), Some(GenericArgKind::Type(ty)));
                     symbols.push((ExportedSymbol::DropGlue(ty), SymbolExportInfo {
                         level: SymbolExportLevel::Rust,
                         kind: SymbolExportKind::Text,
@@ -334,14 +331,11 @@
                     }));
                 }
                 MonoItem::Fn(Instance {
-                    def: InstanceKind::AsyncDropGlueCtorShim(def_id, Some(ty)),
+                    def: InstanceKind::AsyncDropGlueCtorShim(_, Some(ty)),
                     args,
                 }) => {
                     // A little sanity-check
-                    assert_eq!(
-                        args.non_erasable_generics(tcx, def_id).next(),
-                        Some(GenericArgKind::Type(ty))
-                    );
+                    assert_eq!(args.non_erasable_generics().next(), Some(GenericArgKind::Type(ty)));
                     symbols.push((ExportedSymbol::AsyncDropGlueCtorShim(ty), SymbolExportInfo {
                         level: SymbolExportLevel::Rust,
                         kind: SymbolExportKind::Text,
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index f3d9a7d..a726ee7 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -888,7 +888,7 @@
         // below.
         //
         // In order to get this left-to-right dependency ordering, we use the reverse
-        // postorder of all crates putting the leaves at the right-most positions.
+        // postorder of all crates putting the leaves at the rightmost positions.
         let mut compiler_builtins = None;
         let mut used_crates: Vec<_> = tcx
             .postorder_cnums(())
diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
index d536419..a5bd3ad 100644
--- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
+++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
@@ -137,7 +137,7 @@
                 let inner = attr.meta_item_list();
                 match inner.as_deref() {
                     Some([item]) if item.has_name(sym::linker) => {
-                        if !tcx.features().used_with_arg {
+                        if !tcx.features().used_with_arg() {
                             feature_err(
                                 &tcx.sess,
                                 sym::used_with_arg,
@@ -149,7 +149,7 @@
                         codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_LINKER;
                     }
                     Some([item]) if item.has_name(sym::compiler) => {
-                        if !tcx.features().used_with_arg {
+                        if !tcx.features().used_with_arg() {
                             feature_err(
                                 &tcx.sess,
                                 sym::used_with_arg,
@@ -213,7 +213,7 @@
                     .emit();
                 }
                 if is_closure
-                    && !tcx.features().closure_track_caller
+                    && !tcx.features().closure_track_caller()
                     && !attr.span.allows_unstable(sym::closure_track_caller)
                 {
                     feature_err(
@@ -268,7 +268,7 @@
                         //
                         // This exception needs to be kept in sync with allowing
                         // `#[target_feature]` on `main` and `start`.
-                    } else if !tcx.features().target_feature_11 {
+                    } else if !tcx.features().target_feature_11() {
                         feature_err(
                             &tcx.sess,
                             sym::target_feature_11,
@@ -584,7 +584,7 @@
     // its parent function, which effectively inherits the features anyway. Boxing this closure
     // would result in this closure being compiled without the inherited target features, but this
     // is probably a poor usage of `#[inline(always)]` and easily avoided by not using the attribute.
-    if tcx.features().target_feature_11
+    if tcx.features().target_feature_11()
         && tcx.is_closure_like(did.to_def_id())
         && codegen_fn_attrs.inline != InlineAttr::Always
     {
diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
index 526d2b8..1e5b4f3 100644
--- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
+++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
@@ -110,14 +110,14 @@
                     ty_and_layout,
                     &|output, visited| {
                         push_item_name(tcx, def.did(), true, output);
-                        push_generic_params_internal(tcx, args, def.did(), output, visited);
+                        push_generic_params_internal(tcx, args, output, visited);
                     },
                     output,
                     visited,
                 );
             } else {
                 push_item_name(tcx, def.did(), qualified, output);
-                push_generic_params_internal(tcx, args, def.did(), output, visited);
+                push_generic_params_internal(tcx, args, output, visited);
             }
         }
         ty::Tuple(component_types) => {
@@ -251,13 +251,8 @@
                 let principal =
                     tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), principal);
                 push_item_name(tcx, principal.def_id, qualified, output);
-                let principal_has_generic_params = push_generic_params_internal(
-                    tcx,
-                    principal.args,
-                    principal.def_id,
-                    output,
-                    visited,
-                );
+                let principal_has_generic_params =
+                    push_generic_params_internal(tcx, principal.args, output, visited);
 
                 let projection_bounds: SmallVec<[_; 4]> = trait_data
                     .projection_bounds()
@@ -538,13 +533,7 @@
             tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), trait_ref);
         push_item_name(tcx, trait_ref.def_id, true, &mut vtable_name);
         visited.clear();
-        push_generic_params_internal(
-            tcx,
-            trait_ref.args,
-            trait_ref.def_id,
-            &mut vtable_name,
-            &mut visited,
-        );
+        push_generic_params_internal(tcx, trait_ref.args, &mut vtable_name, &mut visited);
     } else {
         vtable_name.push('_');
     }
@@ -647,12 +636,11 @@
 fn push_generic_params_internal<'tcx>(
     tcx: TyCtxt<'tcx>,
     args: GenericArgsRef<'tcx>,
-    def_id: DefId,
     output: &mut String,
     visited: &mut FxHashSet<Ty<'tcx>>,
 ) -> bool {
     assert_eq!(args, tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), args));
-    let mut args = args.non_erasable_generics(tcx, def_id).peekable();
+    let mut args = args.non_erasable_generics().peekable();
     if args.peek().is_none() {
         return false;
     }
@@ -736,12 +724,11 @@
 pub fn push_generic_params<'tcx>(
     tcx: TyCtxt<'tcx>,
     args: GenericArgsRef<'tcx>,
-    def_id: DefId,
     output: &mut String,
 ) {
     let _prof = tcx.prof.generic_activity("compute_debuginfo_type_name");
     let mut visited = FxHashSet::default();
-    push_generic_params_internal(tcx, args, def_id, output, &mut visited);
+    push_generic_params_internal(tcx, args, output, &mut visited);
 }
 
 fn push_closure_or_coroutine_name<'tcx>(
@@ -786,7 +773,7 @@
     // FIXME(async_closures): This is probably not going to be correct w.r.t.
     // multiple coroutine flavors. Maybe truncate to (parent + 1)?
     let args = args.truncate_to(tcx, generics);
-    push_generic_params_internal(tcx, args, enclosing_fn_def_id, output, visited);
+    push_generic_params_internal(tcx, args, output, visited);
 }
 
 fn push_close_angle_bracket(cpp_like_debuginfo: bool, output: &mut String) {
diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs
index dfe8fd6..0845bcc 100644
--- a/compiler/rustc_codegen_ssa/src/target_features.rs
+++ b/compiler/rustc_codegen_ssa/src/target_features.rs
@@ -5,7 +5,6 @@
 use rustc_errors::Applicability;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};
-use rustc_middle::bug;
 use rustc_middle::middle::codegen_fn_attrs::TargetFeature;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::TyCtxt;
@@ -61,30 +60,9 @@
                 return None;
             };
 
-            // Only allow features whose feature gates have been enabled.
+            // Only allow target features whose feature gates have been enabled.
             let allowed = match feature_gate.as_ref().copied() {
-                Some(sym::arm_target_feature) => rust_features.arm_target_feature,
-                Some(sym::hexagon_target_feature) => rust_features.hexagon_target_feature,
-                Some(sym::powerpc_target_feature) => rust_features.powerpc_target_feature,
-                Some(sym::mips_target_feature) => rust_features.mips_target_feature,
-                Some(sym::riscv_target_feature) => rust_features.riscv_target_feature,
-                Some(sym::avx512_target_feature) => rust_features.avx512_target_feature,
-                Some(sym::sse4a_target_feature) => rust_features.sse4a_target_feature,
-                Some(sym::tbm_target_feature) => rust_features.tbm_target_feature,
-                Some(sym::wasm_target_feature) => rust_features.wasm_target_feature,
-                Some(sym::rtm_target_feature) => rust_features.rtm_target_feature,
-                Some(sym::ermsb_target_feature) => rust_features.ermsb_target_feature,
-                Some(sym::bpf_target_feature) => rust_features.bpf_target_feature,
-                Some(sym::aarch64_ver_target_feature) => rust_features.aarch64_ver_target_feature,
-                Some(sym::csky_target_feature) => rust_features.csky_target_feature,
-                Some(sym::loongarch_target_feature) => rust_features.loongarch_target_feature,
-                Some(sym::lahfsahf_target_feature) => rust_features.lahfsahf_target_feature,
-                Some(sym::prfchw_target_feature) => rust_features.prfchw_target_feature,
-                Some(sym::sha512_sm_x86) => rust_features.sha512_sm_x86,
-                Some(sym::x86_amx_intrinsics) => rust_features.x86_amx_intrinsics,
-                Some(sym::xop_target_feature) => rust_features.xop_target_feature,
-                Some(sym::s390x_target_feature) => rust_features.s390x_target_feature,
-                Some(name) => bug!("unknown target feature gate {}", name),
+                Some(name) => rust_features.enabled(name),
                 None => true,
             };
             if !allowed {
diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs
index c0c1085..50a5171 100644
--- a/compiler/rustc_codegen_ssa/src/traits/builder.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs
@@ -437,14 +437,6 @@
     /// Called for `StorageDead`
     fn lifetime_end(&mut self, ptr: Self::Value, size: Size);
 
-    fn instrprof_increment(
-        &mut self,
-        fn_name: Self::Value,
-        hash: Self::Value,
-        num_counters: Self::Value,
-        index: Self::Value,
-    );
-
     fn call(
         &mut self,
         llty: Self::Type,
diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl
index 24dbe68..3e4f83c 100644
--- a/compiler/rustc_const_eval/messages.ftl
+++ b/compiler/rustc_const_eval/messages.ftl
@@ -41,8 +41,6 @@
     *[other] {""}
 }
 
-const_eval_const_stable = const-stable functions can only call other const-stable functions
-
 const_eval_copy_nonoverlapping_overlapping =
     `copy_nonoverlapping` called on overlapping ranges
 
@@ -259,6 +257,9 @@
 const_eval_non_const_impl =
     impl defined here, but it is not `const`
 
+const_eval_non_const_intrinsic =
+    cannot call non-const intrinsic `{$name}` in {const_eval_const_context}s
+
 const_eval_not_enough_caller_args =
     calling a function with fewer arguments than it requires
 
@@ -397,17 +398,29 @@
     read discriminant of an uninhabited enum variant
 const_eval_uninhabited_enum_variant_written =
     writing discriminant of an uninhabited enum variant
+
+const_eval_unmarked_const_fn_exposed = `{$def_path}` cannot be (indirectly) exposed to stable
+    .help = either mark the callee as `#[rustc_const_stable_indirect]`, or the caller as `#[rustc_const_unstable]`
+const_eval_unmarked_intrinsic_exposed = intrinsic `{$def_path}` cannot be (indirectly) exposed to stable
+    .help = mark the caller as `#[rustc_const_unstable]`, or mark the intrinsic `#[rustc_const_stable_indirect]` (but this requires team approval)
+
 const_eval_unreachable = entering unreachable code
 const_eval_unreachable_unwind =
     unwinding past a stack frame that does not allow unwinding
 
 const_eval_unsized_local = unsized locals are not supported
 const_eval_unstable_const_fn = `{$def_path}` is not yet stable as a const fn
+const_eval_unstable_in_stable_exposed =
+    const function that might be (indirectly) exposed to stable cannot use `#[feature({$gate})]`
+    .is_function_call = mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features
+    .unstable_sugg = if the {$is_function_call2 ->
+            [true] caller
+            *[false] function
+        } is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do)
+    .bypass_sugg = otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
 
-const_eval_unstable_in_stable =
-    const-stable function cannot use `#[feature({$gate})]`
-    .unstable_sugg = if the function is not (yet) meant to be stable, make this function unstably const
-    .bypass_sugg = otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (but requires team approval)
+const_eval_unstable_intrinsic = `{$name}` is not yet stable as a const intrinsic
+    .help = add `#![feature({$feature})]` to the crate attributes to enable
 
 const_eval_unterminated_c_string =
     reading a null-terminated string starting at {$pointer} with no null found before end of allocation
diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs
index 463a66d..004fb12 100644
--- a/compiler/rustc_const_eval/src/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/check_consts/check.rs
@@ -5,6 +5,7 @@
 use std::mem;
 use std::ops::Deref;
 
+use rustc_attr::{ConstStability, StabilityLevel};
 use rustc_errors::{Diag, ErrorGuaranteed};
 use rustc_hir::def_id::DefId;
 use rustc_hir::{self as hir, LangItem};
@@ -28,8 +29,8 @@
 use super::qualifs::{self, HasMutInterior, NeedsDrop, NeedsNonConstDrop};
 use super::resolver::FlowSensitiveAnalysis;
 use super::{ConstCx, Qualif};
-use crate::const_eval::is_unstable_const_fn;
-use crate::errors::UnstableInStable;
+use crate::check_consts::is_safe_to_expose_on_stable_const_fn;
+use crate::errors;
 
 type QualifResults<'mir, 'tcx, Q> =
     rustc_mir_dataflow::ResultsCursor<'mir, 'tcx, FlowSensitiveAnalysis<'mir, 'mir, 'tcx, Q>>;
@@ -274,19 +275,22 @@
     /// context.
     pub fn check_op_spanned<O: NonConstOp<'tcx>>(&mut self, op: O, span: Span) {
         let gate = match op.status_in_item(self.ccx) {
-            Status::Allowed => return,
-
-            Status::Unstable(gate) if self.tcx.features().active(gate) => {
-                let unstable_in_stable = self.ccx.is_const_stable_const_fn()
-                    && !super::rustc_allow_const_fn_unstable(self.tcx, self.def_id(), gate);
-                if unstable_in_stable {
-                    emit_unstable_in_stable_error(self.ccx, span, gate);
+            Status::Unstable { gate, safe_to_expose_on_stable, is_function_call }
+                if self.tcx.features().enabled(gate) =>
+            {
+                // Generally this is allowed since the feature gate is enabled -- except
+                // if this function wants to be safe-to-expose-on-stable.
+                if !safe_to_expose_on_stable
+                    && self.enforce_recursive_const_stability()
+                    && !super::rustc_allow_const_fn_unstable(self.tcx, self.def_id(), gate)
+                {
+                    emit_unstable_in_stable_exposed_error(self.ccx, span, gate, is_function_call);
                 }
 
                 return;
             }
 
-            Status::Unstable(gate) => Some(gate),
+            Status::Unstable { gate, .. } => Some(gate),
             Status::Forbidden => None,
         };
 
@@ -304,7 +308,13 @@
                 self.error_emitted = Some(reported);
             }
 
-            ops::DiagImportance::Secondary => self.secondary_errors.push(err),
+            ops::DiagImportance::Secondary => {
+                self.secondary_errors.push(err);
+                self.tcx.dcx().span_delayed_bug(
+                    span,
+                    "compilation must fail when there is a secondary const checker error",
+                );
+            }
         }
     }
 
@@ -569,6 +579,8 @@
 
                     ty::FnPtr(..) => {
                         self.check_op(ops::FnCallIndirect);
+                        // We can get here without an error in miri-unleashed mode... might as well
+                        // skip the rest of the checks as well then.
                         return;
                     }
                     _ => {
@@ -604,14 +616,17 @@
 
                 let mut is_trait = false;
                 // Attempting to call a trait method?
-                if tcx.trait_of_item(callee).is_some() {
+                if let Some(trait_did) = tcx.trait_of_item(callee) {
                     trace!("attempting to call a trait method");
+
+                    let trait_is_const = tcx.is_const_trait(trait_did);
                     // trait method calls are only permitted when `effects` is enabled.
-                    // we don't error, since that is handled by typeck. We try to resolve
-                    // the trait into the concrete method, and uses that for const stability
-                    // checks.
+                    // typeck ensures the conditions for calling a const trait method are met,
+                    // so we only error if the trait isn't const. We try to resolve the trait
+                    // into the concrete method, and uses that for const stability checks.
                     // FIXME(effects) we might consider moving const stability checks to typeck as well.
-                    if tcx.features().effects {
+                    if tcx.features().effects() && trait_is_const {
+                        // This skips the check below that ensures we only call `const fn`.
                         is_trait = true;
 
                         if let Ok(Some(instance)) =
@@ -625,18 +640,27 @@
                             callee = def;
                         }
                     } else {
+                        // if the trait is const but the user has not enabled the feature(s),
+                        // suggest them.
+                        let feature = if trait_is_const {
+                            Some(if tcx.features().const_trait_impl() {
+                                sym::effects
+                            } else {
+                                sym::const_trait_impl
+                            })
+                        } else {
+                            None
+                        };
                         self.check_op(ops::FnCallNonConst {
                             caller,
                             callee,
                             args: fn_args,
                             span: *fn_span,
                             call_source,
-                            feature: Some(if tcx.features().const_trait_impl {
-                                sym::effects
-                            } else {
-                                sym::const_trait_impl
-                            }),
+                            feature,
                         });
+                        // If we allowed this, we're in miri-unleashed mode, so we might
+                        // as well skip the remaining checks.
                         return;
                     }
                 }
@@ -650,29 +674,73 @@
                 // const-eval of the `begin_panic` fn assumes the argument is `&str`
                 if tcx.is_lang_item(callee, LangItem::BeginPanic) {
                     match args[0].node.ty(&self.ccx.body.local_decls, tcx).kind() {
-                        ty::Ref(_, ty, _) if ty.is_str() => return,
+                        ty::Ref(_, ty, _) if ty.is_str() => {}
                         _ => self.check_op(ops::PanicNonStr),
                     }
+                    // Allow this call, skip all the checks below.
+                    return;
                 }
 
                 // const-eval of `#[rustc_const_panic_str]` functions assumes the argument is `&&str`
                 if tcx.has_attr(callee, sym::rustc_const_panic_str) {
                     match args[0].node.ty(&self.ccx.body.local_decls, tcx).kind() {
                         ty::Ref(_, ty, _) if matches!(ty.kind(), ty::Ref(_, ty, _) if ty.is_str()) =>
-                        {
-                            return;
+                            {}
+                        _ => {
+                            self.check_op(ops::PanicNonStr);
                         }
-                        _ => self.check_op(ops::PanicNonStr),
                     }
+                    // Allow this call, skip all the checks below.
+                    return;
                 }
 
                 // This can be called on stable via the `vec!` macro.
                 if tcx.is_lang_item(callee, LangItem::ExchangeMalloc) {
                     self.check_op(ops::HeapAllocation);
+                    // Allow this call, skip all the checks below.
                     return;
                 }
 
-                if !tcx.is_const_fn_raw(callee) && !is_trait {
+                // Intrinsics are language primitives, not regular calls, so treat them separately.
+                if let Some(intrinsic) = tcx.intrinsic(callee) {
+                    match tcx.lookup_const_stability(callee) {
+                        None => {
+                            // Non-const intrinsic.
+                            self.check_op(ops::IntrinsicNonConst { name: intrinsic.name });
+                        }
+                        Some(ConstStability { feature: None, const_stable_indirect, .. }) => {
+                            // Intrinsic does not need a separate feature gate (we rely on the
+                            // regular stability checker). However, we have to worry about recursive
+                            // const stability.
+                            if !const_stable_indirect && self.enforce_recursive_const_stability() {
+                                self.dcx().emit_err(errors::UnmarkedIntrinsicExposed {
+                                    span: self.span,
+                                    def_path: self.tcx.def_path_str(callee),
+                                });
+                            }
+                        }
+                        Some(ConstStability {
+                            feature: Some(feature),
+                            level: StabilityLevel::Unstable { .. },
+                            const_stable_indirect,
+                            ..
+                        }) => {
+                            self.check_op(ops::IntrinsicUnstable {
+                                name: intrinsic.name,
+                                feature,
+                                const_stable_indirect,
+                            });
+                        }
+                        Some(ConstStability { level: StabilityLevel::Stable { .. }, .. }) => {
+                            // All good.
+                        }
+                    }
+                    // This completes the checks for intrinsics.
+                    return;
+                }
+
+                // Trait functions are not `const fn` so we have to skip them here.
+                if !tcx.is_const_fn(callee) && !is_trait {
                     self.check_op(ops::FnCallNonConst {
                         caller,
                         callee,
@@ -681,66 +749,68 @@
                         call_source,
                         feature: None,
                     });
+                    // If we allowed this, we're in miri-unleashed mode, so we might
+                    // as well skip the remaining checks.
                     return;
                 }
 
-                // If the `const fn` we are trying to call is not const-stable, ensure that we have
-                // the proper feature gate enabled.
-                if let Some((gate, implied_by)) = is_unstable_const_fn(tcx, callee) {
-                    trace!(?gate, "calling unstable const fn");
-                    if self.span.allows_unstable(gate) {
-                        return;
+                // Finally, stability for regular function calls -- this is the big one.
+                match tcx.lookup_const_stability(callee) {
+                    Some(ConstStability { level: StabilityLevel::Stable { .. }, .. }) => {
+                        // All good.
                     }
-                    if let Some(implied_by_gate) = implied_by
-                        && self.span.allows_unstable(implied_by_gate)
-                    {
-                        return;
+                    None | Some(ConstStability { feature: None, .. }) => {
+                        // This doesn't need a separate const-stability check -- const-stability equals
+                        // regular stability, and regular stability is checked separately.
+                        // However, we *do* have to worry about *recursive* const stability.
+                        if self.enforce_recursive_const_stability()
+                            && !is_safe_to_expose_on_stable_const_fn(tcx, callee)
+                        {
+                            self.dcx().emit_err(errors::UnmarkedConstFnExposed {
+                                span: self.span,
+                                def_path: self.tcx.def_path_str(callee),
+                            });
+                        }
                     }
+                    Some(ConstStability {
+                        feature: Some(feature),
+                        level: StabilityLevel::Unstable { implied_by: implied_feature, .. },
+                        ..
+                    }) => {
+                        // An unstable const fn with a feature gate.
+                        let callee_safe_to_expose_on_stable =
+                            is_safe_to_expose_on_stable_const_fn(tcx, callee);
 
-                    // Calling an unstable function *always* requires that the corresponding gate
-                    // (or implied gate) be enabled, even if the function has
-                    // `#[rustc_allow_const_fn_unstable(the_gate)]`.
-                    let gate_declared = |gate| tcx.features().declared(gate);
-                    let feature_gate_declared = gate_declared(gate);
-                    let implied_gate_declared = implied_by.is_some_and(gate_declared);
-                    if !feature_gate_declared && !implied_gate_declared {
-                        self.check_op(ops::FnCallUnstable(callee, Some(gate)));
-                        return;
-                    }
+                        // We only honor `span.allows_unstable` aka `#[allow_internal_unstable]` if
+                        // the callee is safe to expose, to avoid bypassing recursive stability.
+                        if (self.span.allows_unstable(feature)
+                            || implied_feature.is_some_and(|f| self.span.allows_unstable(f)))
+                            && callee_safe_to_expose_on_stable
+                        {
+                            return;
+                        }
 
-                    // If this crate is not using stability attributes, or the caller is not claiming to be a
-                    // stable `const fn`, that is all that is required.
-                    if !self.ccx.is_const_stable_const_fn() {
-                        trace!("crate not using stability attributes or caller not stably const");
-                        return;
-                    }
-
-                    // Otherwise, we are something const-stable calling a const-unstable fn.
-                    if super::rustc_allow_const_fn_unstable(tcx, caller, gate) {
-                        trace!("rustc_allow_const_fn_unstable gate active");
-                        return;
-                    }
-
-                    self.check_op(ops::FnCallUnstable(callee, Some(gate)));
-                    return;
-                }
-
-                // FIXME(ecstaticmorse); For compatibility, we consider `unstable` callees that
-                // have no `rustc_const_stable` attributes to be const-unstable as well. This
-                // should be fixed later.
-                let callee_is_unstable_unmarked = tcx.lookup_const_stability(callee).is_none()
-                    && tcx.lookup_stability(callee).is_some_and(|s| s.is_unstable());
-                if callee_is_unstable_unmarked {
-                    trace!("callee_is_unstable_unmarked");
-                    // We do not use `const` modifiers for intrinsic "functions", as intrinsics are
-                    // `extern` functions, and these have no way to get marked `const`. So instead we
-                    // use `rustc_const_(un)stable` attributes to mean that the intrinsic is `const`
-                    if self.ccx.is_const_stable_const_fn() || tcx.intrinsic(callee).is_some() {
-                        self.check_op(ops::FnCallUnstable(callee, None));
-                        return;
+                        // We can't use `check_op` to check whether the feature is enabled because
+                        // the logic is a bit different than elsewhere: local functions don't need
+                        // the feature gate, and there might be an "implied" gate that also suffices
+                        // to allow this.
+                        let feature_enabled = callee.is_local()
+                            || tcx.features().enabled(feature)
+                            || implied_feature.is_some_and(|f| tcx.features().enabled(f));
+                        // We do *not* honor this if we are in the "danger zone": we have to enforce
+                        // recursive const-stability and the callee is not safe-to-expose. In that
+                        // case we need `check_op` to do the check.
+                        let danger_zone = !callee_safe_to_expose_on_stable
+                            && self.enforce_recursive_const_stability();
+                        if danger_zone || !feature_enabled {
+                            self.check_op(ops::FnCallUnstable {
+                                def_id: callee,
+                                feature,
+                                safe_to_expose_on_stable: callee_safe_to_expose_on_stable,
+                            });
+                        }
                     }
                 }
-                trace!("permitting call");
             }
 
             // Forbid all `Drop` terminators unless the place being dropped is a local with no
@@ -785,11 +855,13 @@
 
             TerminatorKind::InlineAsm { .. } => self.check_op(ops::InlineAsm),
 
-            TerminatorKind::Yield { .. } => self.check_op(ops::Coroutine(
-                self.tcx
-                    .coroutine_kind(self.body.source.def_id())
-                    .expect("Only expected to have a yield in a coroutine"),
-            )),
+            TerminatorKind::Yield { .. } => {
+                self.check_op(ops::Coroutine(
+                    self.tcx
+                        .coroutine_kind(self.body.source.def_id())
+                        .expect("Only expected to have a yield in a coroutine"),
+                ));
+            }
 
             TerminatorKind::CoroutineDrop => {
                 span_bug!(
@@ -819,8 +891,19 @@
     ty.is_bool() || ty.is_integral() || ty.is_char() || ty.is_floating_point()
 }
 
-fn emit_unstable_in_stable_error(ccx: &ConstCx<'_, '_>, span: Span, gate: Symbol) {
+fn emit_unstable_in_stable_exposed_error(
+    ccx: &ConstCx<'_, '_>,
+    span: Span,
+    gate: Symbol,
+    is_function_call: bool,
+) -> ErrorGuaranteed {
     let attr_span = ccx.tcx.def_span(ccx.def_id()).shrink_to_lo();
 
-    ccx.dcx().emit_err(UnstableInStable { gate: gate.to_string(), span, attr_span });
+    ccx.dcx().emit_err(errors::UnstableInStableExposed {
+        gate: gate.to_string(),
+        span,
+        attr_span,
+        is_function_call,
+        is_function_call2: is_function_call,
+    })
 }
diff --git a/compiler/rustc_const_eval/src/check_consts/mod.rs b/compiler/rustc_const_eval/src/check_consts/mod.rs
index 15ac4ce..56da679 100644
--- a/compiler/rustc_const_eval/src/check_consts/mod.rs
+++ b/compiler/rustc_const_eval/src/check_consts/mod.rs
@@ -59,10 +59,12 @@
         self.const_kind.expect("`const_kind` must not be called on a non-const fn")
     }
 
-    pub fn is_const_stable_const_fn(&self) -> bool {
+    pub fn enforce_recursive_const_stability(&self) -> bool {
+        // We can skip this if `staged_api` is not enabled, since in such crates
+        // `lookup_const_stability` will always be `None`.
         self.const_kind == Some(hir::ConstContext::ConstFn)
-            && self.tcx.features().staged_api
-            && is_const_stable_const_fn(self.tcx, self.def_id().to_def_id())
+            && self.tcx.features().staged_api()
+            && is_safe_to_expose_on_stable_const_fn(self.tcx, self.def_id().to_def_id())
     }
 
     fn is_async(&self) -> bool {
@@ -90,50 +92,38 @@
     attr::rustc_allow_const_fn_unstable(tcx.sess, attrs).any(|name| name == feature_gate)
 }
 
-/// Returns `true` if the given `const fn` is "const-stable".
+/// Returns `true` if the given `const fn` is "safe to expose on stable".
 ///
 /// Panics if the given `DefId` does not refer to a `const fn`.
 ///
-/// Const-stability is only relevant for `const fn` within a `staged_api` crate. Only "const-stable"
-/// functions can be called in a const-context by users of the stable compiler. "const-stable"
-/// functions are subject to more stringent restrictions than "const-unstable" functions: They
-/// cannot use unstable features and can only call other "const-stable" functions.
-pub fn is_const_stable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
-    // A default body in a `#[const_trait]` is not const-stable because const
-    // trait fns currently cannot be const-stable. We shouldn't
-    // restrict default bodies to only call const-stable functions.
+/// This is relevant within a `staged_api` crate. Unlike with normal features, the use of unstable
+/// const features *recursively* taints the functions that use them. This is to avoid accidentally
+/// exposing e.g. the implementation of an unstable const intrinsic on stable. So we partition the
+/// world into two functions: those that are safe to expose on stable (and hence may not use
+/// unstable features, not even recursively), and those that are not.
+pub fn is_safe_to_expose_on_stable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
+    // A default body in a `#[const_trait]` is not const-stable because const trait fns currently
+    // cannot be const-stable. These functions can't be called from anything stable, so we shouldn't
+    // restrict them to only call const-stable functions.
     if tcx.is_const_default_method(def_id) {
+        // FIXME(const_trait_impl): we have to eventually allow some of these if these things can ever be stable.
+        // They should probably behave like regular `const fn` for that...
         return false;
     }
 
     // Const-stability is only relevant for `const fn`.
-    assert!(tcx.is_const_fn_raw(def_id));
+    assert!(tcx.is_const_fn(def_id));
 
-    // A function is only const-stable if it has `#[rustc_const_stable]` or it the trait it belongs
-    // to is const-stable.
     match tcx.lookup_const_stability(def_id) {
-        Some(stab) => stab.is_const_stable(),
-        None if is_parent_const_stable_trait(tcx, def_id) => {
-            // Remove this when `#![feature(const_trait_impl)]` is stabilized,
-            // returning `true` unconditionally.
-            tcx.dcx().span_delayed_bug(
-                tcx.def_span(def_id),
-                "trait implementations cannot be const stable yet",
-            );
-            true
+        None => {
+            // Only marked functions can be trusted. Note that this may be a function in a
+            // non-staged-API crate where no recursive checks were done!
+            false
         }
-        None => false, // By default, items are not const stable.
+        Some(stab) => {
+            // We consider things safe-to-expose if they are stable, if they don't have any explicit
+            // const stability attribute, or if they are marked as `const_stable_indirect`.
+            stab.is_const_stable() || stab.feature.is_none() || stab.const_stable_indirect
+        }
     }
 }
-
-fn is_parent_const_stable_trait(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
-    let local_def_id = def_id.expect_local();
-    let hir_id = tcx.local_def_id_to_hir_id(local_def_id);
-
-    let parent_owner_id = tcx.parent_hir_id(hir_id).owner;
-    if !tcx.is_const_trait_impl_raw(parent_owner_id.to_def_id()) {
-        return false;
-    }
-
-    tcx.lookup_const_stability(parent_owner_id).is_some_and(|stab| stab.is_const_stable())
-}
diff --git a/compiler/rustc_const_eval/src/check_consts/ops.rs b/compiler/rustc_const_eval/src/check_consts/ops.rs
index 5c4a899..3ac06ae 100644
--- a/compiler/rustc_const_eval/src/check_consts/ops.rs
+++ b/compiler/rustc_const_eval/src/check_consts/ops.rs
@@ -26,8 +26,16 @@
 
 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
 pub enum Status {
-    Allowed,
-    Unstable(Symbol),
+    Unstable {
+        /// The feature that must be enabled to use this operation.
+        gate: Symbol,
+        /// Whether it is allowed to use this operation from stable `const fn`.
+        /// This will usually be `false`.
+        safe_to_expose_on_stable: bool,
+        /// We indicate whether this is a function call, since we can use targeted
+        /// diagnostics for "callee is not safe to expose om stable".
+        is_function_call: bool,
+    },
     Forbidden,
 }
 
@@ -40,9 +48,9 @@
     Secondary,
 }
 
-/// An operation that is not *always* allowed in a const context.
+/// An operation that is *not allowed* in a const context.
 pub trait NonConstOp<'tcx>: std::fmt::Debug {
-    /// Returns an enum indicating whether this operation is allowed within the given item.
+    /// Returns an enum indicating whether this operation can be enabled with a feature gate.
     fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status {
         Status::Forbidden
     }
@@ -114,7 +122,7 @@
 
                     if let Ok(Some(ImplSource::UserDefined(data))) = implsrc {
                         // FIXME(effects) revisit this
-                        if !tcx.is_const_trait_impl_raw(data.impl_def_id) {
+                        if !tcx.is_const_trait_impl(data.impl_def_id) {
                             let span = tcx.def_span(data.impl_def_id);
                             err.subdiagnostic(errors::NonConstImplNote { span });
                         }
@@ -166,7 +174,7 @@
                 let note = match self_ty.kind() {
                     FnDef(def_id, ..) => {
                         let span = tcx.def_span(*def_id);
-                        if ccx.tcx.is_const_fn_raw(*def_id) {
+                        if ccx.tcx.is_const_fn(*def_id) {
                             span_bug!(span, "calling const FnDef errored when it shouldn't");
                         }
 
@@ -298,30 +306,78 @@
 ///
 /// Contains the name of the feature that would allow the use of this function.
 #[derive(Debug)]
-pub(crate) struct FnCallUnstable(pub DefId, pub Option<Symbol>);
+pub(crate) struct FnCallUnstable {
+    pub def_id: DefId,
+    pub feature: Symbol,
+    pub safe_to_expose_on_stable: bool,
+}
 
 impl<'tcx> NonConstOp<'tcx> for FnCallUnstable {
+    fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status {
+        Status::Unstable {
+            gate: self.feature,
+            safe_to_expose_on_stable: self.safe_to_expose_on_stable,
+            is_function_call: true,
+        }
+    }
+
     fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
-        let FnCallUnstable(def_id, feature) = *self;
-
-        let mut err = ccx
-            .dcx()
-            .create_err(errors::UnstableConstFn { span, def_path: ccx.tcx.def_path_str(def_id) });
-
+        let mut err = ccx.dcx().create_err(errors::UnstableConstFn {
+            span,
+            def_path: ccx.tcx.def_path_str(self.def_id),
+        });
         // FIXME: make this translatable
         #[allow(rustc::untranslatable_diagnostic)]
-        if ccx.is_const_stable_const_fn() {
-            err.help(fluent_generated::const_eval_const_stable);
-        } else if ccx.tcx.sess.is_nightly_build() {
-            if let Some(feature) = feature {
-                err.help(format!("add `#![feature({feature})]` to the crate attributes to enable"));
-            }
-        }
+        err.help(format!("add `#![feature({})]` to the crate attributes to enable", self.feature));
 
         err
     }
 }
 
+/// A call to an intrinsic that is just not const-callable at all.
+#[derive(Debug)]
+pub(crate) struct IntrinsicNonConst {
+    pub name: Symbol,
+}
+
+impl<'tcx> NonConstOp<'tcx> for IntrinsicNonConst {
+    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
+        ccx.dcx().create_err(errors::NonConstIntrinsic {
+            span,
+            name: self.name,
+            kind: ccx.const_kind(),
+        })
+    }
+}
+
+/// A call to an intrinsic that is just not const-callable at all.
+#[derive(Debug)]
+pub(crate) struct IntrinsicUnstable {
+    pub name: Symbol,
+    pub feature: Symbol,
+    pub const_stable_indirect: bool,
+}
+
+impl<'tcx> NonConstOp<'tcx> for IntrinsicUnstable {
+    fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status {
+        Status::Unstable {
+            gate: self.feature,
+            safe_to_expose_on_stable: self.const_stable_indirect,
+            // We do *not* want to suggest to mark the intrinsic as `const_stable_indirect`,
+            // that's not a trivial change!
+            is_function_call: false,
+        }
+    }
+
+    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
+        ccx.dcx().create_err(errors::UnstableIntrinsic {
+            span,
+            name: self.name,
+            feature: self.feature,
+        })
+    }
+}
+
 #[derive(Debug)]
 pub(crate) struct Coroutine(pub hir::CoroutineKind);
 impl<'tcx> NonConstOp<'tcx> for Coroutine {
@@ -331,7 +387,11 @@
             hir::CoroutineSource::Block,
         ) = self.0
         {
-            Status::Unstable(sym::const_async_blocks)
+            Status::Unstable {
+                gate: sym::const_async_blocks,
+                safe_to_expose_on_stable: false,
+                is_function_call: false,
+            }
         } else {
             Status::Forbidden
         }
diff --git a/compiler/rustc_const_eval/src/check_consts/post_drop_elaboration.rs b/compiler/rustc_const_eval/src/check_consts/post_drop_elaboration.rs
index f98234c..0173a52 100644
--- a/compiler/rustc_const_eval/src/check_consts/post_drop_elaboration.rs
+++ b/compiler/rustc_const_eval/src/check_consts/post_drop_elaboration.rs
@@ -15,7 +15,7 @@
 /// elaboration.
 pub fn checking_enabled(ccx: &ConstCx<'_, '_>) -> bool {
     // Const-stable functions must always use the stable live drop checker...
-    if ccx.is_const_stable_const_fn() {
+    if ccx.enforce_recursive_const_stability() {
         // ...except if they have the feature flag set via `rustc_allow_const_fn_unstable`.
         return rustc_allow_const_fn_unstable(
             ccx.tcx,
@@ -24,7 +24,7 @@
         );
     }
 
-    ccx.tcx.features().const_precise_live_drops
+    ccx.tcx.features().const_precise_live_drops()
 }
 
 /// Look for live drops in a const context.
diff --git a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs
index ca0993f..037fdcb 100644
--- a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs
@@ -1,25 +1,8 @@
+use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_middle::query::Providers;
 use rustc_middle::ty::TyCtxt;
-use rustc_span::symbol::Symbol;
-use {rustc_attr as attr, rustc_hir as hir};
-
-/// Whether the `def_id` is an unstable const fn and what feature gate(s) are necessary to enable
-/// it.
-pub fn is_unstable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> Option<(Symbol, Option<Symbol>)> {
-    if tcx.is_const_fn_raw(def_id) {
-        let const_stab = tcx.lookup_const_stability(def_id)?;
-        match const_stab.level {
-            attr::StabilityLevel::Unstable { implied_by, .. } => {
-                Some((const_stab.feature, implied_by))
-            }
-            attr::StabilityLevel::Stable { .. } => None,
-        }
-    } else {
-        None
-    }
-}
 
 pub fn is_parent_const_impl_raw(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
     let parent_id = tcx.local_parent(def_id);
diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs
index 2db43a0..d54c5b7 100644
--- a/compiler/rustc_const_eval/src/const_eval/machine.rs
+++ b/compiler/rustc_const_eval/src/const_eval/machine.rs
@@ -219,7 +219,7 @@
     }
 
     /// "Intercept" a function call, because we have something special to do for it.
-    /// All `#[rustc_do_not_const_check]` functions should be hooked here.
+    /// All `#[rustc_do_not_const_check]` functions MUST be hooked here.
     /// If this returns `Some` function, which may be `instance` or a different function with
     /// compatible arguments, then evaluation should continue with that function.
     /// If this returns `None`, the function call has been handled and the function has returned.
@@ -431,8 +431,8 @@
             // sensitive check here. But we can at least rule out functions that are not const at
             // all. That said, we have to allow calling functions inside a trait marked with
             // #[const_trait]. These *are* const-checked!
-            // FIXME: why does `is_const_fn_raw` not classify them as const?
-            if (!ecx.tcx.is_const_fn_raw(def) && !ecx.tcx.is_const_default_method(def))
+            // FIXME(effects): why does `is_const_fn` not classify them as const?
+            if (!ecx.tcx.is_const_fn(def) && !ecx.tcx.is_const_default_method(def))
                 || ecx.tcx.has_attr(def, sym::rustc_do_not_const_check)
             {
                 // We certainly do *not* want to actually call the fn
diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs
index 211668c..38b87b7 100644
--- a/compiler/rustc_const_eval/src/errors.rs
+++ b/compiler/rustc_const_eval/src/errors.rs
@@ -14,7 +14,7 @@
     UndefinedBehaviorInfo, UnsupportedOpInfo, ValidationErrorInfo,
 };
 use rustc_middle::ty::{self, Mutability, Ty};
-use rustc_span::Span;
+use rustc_span::{Span, Symbol};
 use rustc_target::abi::WrappingRange;
 use rustc_target::abi::call::AdjustForForeignAbiError;
 
@@ -44,11 +44,15 @@
 }
 
 #[derive(Diagnostic)]
-#[diag(const_eval_unstable_in_stable)]
-pub(crate) struct UnstableInStable {
+#[diag(const_eval_unstable_in_stable_exposed)]
+pub(crate) struct UnstableInStableExposed {
     pub gate: String,
     #[primary_span]
     pub span: Span,
+    #[help(const_eval_is_function_call)]
+    pub is_function_call: bool,
+    /// Need to duplicate the field so that fluent also provides it as a variable...
+    pub is_function_call2: bool,
     #[suggestion(
         const_eval_unstable_sugg,
         code = "#[rustc_const_unstable(feature = \"...\", issue = \"...\")]\n",
@@ -118,6 +122,34 @@
 }
 
 #[derive(Diagnostic)]
+#[diag(const_eval_unstable_intrinsic)]
+#[help]
+pub(crate) struct UnstableIntrinsic {
+    #[primary_span]
+    pub span: Span,
+    pub name: Symbol,
+    pub feature: Symbol,
+}
+
+#[derive(Diagnostic)]
+#[diag(const_eval_unmarked_const_fn_exposed)]
+#[help]
+pub(crate) struct UnmarkedConstFnExposed {
+    #[primary_span]
+    pub span: Span,
+    pub def_path: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(const_eval_unmarked_intrinsic_exposed)]
+#[help]
+pub(crate) struct UnmarkedIntrinsicExposed {
+    #[primary_span]
+    pub span: Span,
+    pub def_path: String,
+}
+
+#[derive(Diagnostic)]
 #[diag(const_eval_mutable_ref_escaping, code = E0764)]
 pub(crate) struct MutableRefEscaping {
     #[primary_span]
@@ -154,6 +186,15 @@
 }
 
 #[derive(Diagnostic)]
+#[diag(const_eval_non_const_intrinsic)]
+pub(crate) struct NonConstIntrinsic {
+    #[primary_span]
+    pub span: Span,
+    pub name: Symbol,
+    pub kind: ConstContext,
+}
+
+#[derive(Diagnostic)]
 #[diag(const_eval_unallowed_op_in_const_context)]
 pub(crate) struct UnallowedOpInConstContext {
     #[primary_span]
diff --git a/compiler/rustc_data_structures/src/graph/dominators/mod.rs b/compiler/rustc_data_structures/src/graph/dominators/mod.rs
index 7cb013f..53ff67f 100644
--- a/compiler/rustc_data_structures/src/graph/dominators/mod.rs
+++ b/compiler/rustc_data_structures/src/graph/dominators/mod.rs
@@ -2,15 +2,13 @@
 //!
 //! Algorithm based on Loukas Georgiadis,
 //! "Linear-Time Algorithms for Dominators and Related Problems",
-//! <ftp://ftp.cs.princeton.edu/techreports/2005/737.pdf>
+//! <https://www.cs.princeton.edu/techreports/2005/737.pdf>
 //!
 //! Additionally useful is the original Lengauer-Tarjan paper on this subject,
 //! "A Fast Algorithm for Finding Dominators in a Flowgraph"
 //! Thomas Lengauer and Robert Endre Tarjan.
 //! <https://www.cs.princeton.edu/courses/archive/spr03/cs423/download/dominators.pdf>
 
-use std::cmp::Ordering;
-
 use rustc_index::{Idx, IndexSlice, IndexVec};
 
 use super::ControlFlowGraph;
@@ -64,9 +62,6 @@
 }
 
 fn dominators_impl<G: ControlFlowGraph>(graph: &G) -> Inner<G::Node> {
-    // compute the post order index (rank) for each node
-    let mut post_order_rank = IndexVec::from_elem_n(0, graph.num_nodes());
-
     // We allocate capacity for the full set of nodes, because most of the time
     // most of the nodes *are* reachable.
     let mut parent: IndexVec<PreorderIndex, PreorderIndex> =
@@ -83,12 +78,10 @@
     pre_order_to_real.push(graph.start_node());
     parent.push(PreorderIndex::ZERO); // the parent of the root node is the root for now.
     real_to_pre_order[graph.start_node()] = Some(PreorderIndex::ZERO);
-    let mut post_order_idx = 0;
 
     // Traverse the graph, collecting a number of things:
     //
     // * Preorder mapping (to it, and back to the actual ordering)
-    // * Postorder mapping (used exclusively for `cmp_in_dominator_order` on the final product)
     // * Parents for each vertex in the preorder tree
     //
     // These are all done here rather than through one of the 'standard'
@@ -104,8 +97,6 @@
                 continue 'recurse;
             }
         }
-        post_order_rank[pre_order_to_real[frame.pre_order_idx]] = post_order_idx;
-        post_order_idx += 1;
 
         stack.pop();
     }
@@ -282,7 +273,7 @@
 
     let time = compute_access_time(start_node, &immediate_dominators);
 
-    Inner { post_order_rank, immediate_dominators, time }
+    Inner { immediate_dominators, time }
 }
 
 /// Evaluate the link-eval virtual forest, providing the currently minimum semi
@@ -348,7 +339,6 @@
 /// Tracks the list of dominators for each node.
 #[derive(Clone, Debug)]
 struct Inner<N: Idx> {
-    post_order_rank: IndexVec<N, usize>,
     // Even though we track only the immediate dominator of each node, it's
     // possible to get its full list of dominators by looking up the dominator
     // of each dominator.
@@ -379,17 +369,6 @@
         }
     }
 
-    /// Provide deterministic ordering of nodes such that, if any two nodes have a dominator
-    /// relationship, the dominator will always precede the dominated. (The relative ordering
-    /// of two unrelated nodes will also be consistent, but otherwise the order has no
-    /// meaning.) This method cannot be used to determine if either Node dominates the other.
-    pub fn cmp_in_dominator_order(&self, lhs: Node, rhs: Node) -> Ordering {
-        match &self.kind {
-            Kind::Path => lhs.index().cmp(&rhs.index()),
-            Kind::General(g) => g.post_order_rank[rhs].cmp(&g.post_order_rank[lhs]),
-        }
-    }
-
     /// Returns true if `a` dominates `b`.
     ///
     /// # Panics
diff --git a/compiler/rustc_error_codes/src/error_codes/E0539.md b/compiler/rustc_error_codes/src/error_codes/E0539.md
index cd28afb..6b2e23b 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0539.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0539.md
@@ -45,6 +45,7 @@
 #[stable(feature = "stable_struct", since = "1.39.0")] // ok!
 struct Stable;
 
+#[stable(feature = "stable_fn", since = "1.39.0")]
 #[rustc_const_stable(feature = "stable_fn", since = "1.39.0")] // ok!
 const fn stable_fn() {}
 ```
diff --git a/compiler/rustc_error_codes/src/error_codes/E0542.md b/compiler/rustc_error_codes/src/error_codes/E0542.md
index be186db..70590f2 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0542.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0542.md
@@ -30,6 +30,7 @@
 #[stable(feature = "_stable_fn", since = "1.0.0")] // ok!
 fn _stable_fn() {}
 
+#[stable(feature = "_stable_const_fn", since = "1.0.0")]
 #[rustc_const_stable(feature = "_stable_const_fn", since = "1.0.0")] // ok!
 const fn _stable_const_fn() {}
 
diff --git a/compiler/rustc_error_codes/src/error_codes/E0636.md b/compiler/rustc_error_codes/src/error_codes/E0636.md
index 57cf72d..41fd701 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0636.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0636.md
@@ -1,9 +1,9 @@
-A `#![feature]` attribute was declared multiple times.
+The same feature is enabled multiple times with `#![feature]` attributes
 
 Erroneous code example:
 
 ```compile_fail,E0636
 #![allow(stable_features)]
 #![feature(rust1)]
-#![feature(rust1)] // error: the feature `rust1` has already been declared
+#![feature(rust1)] // error: the feature `rust1` has already been enabled
 ```
diff --git a/compiler/rustc_error_codes/src/error_codes/E0667.md b/compiler/rustc_error_codes/src/error_codes/E0667.md
index 0709a24..339bc06 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0667.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0667.md
@@ -1,8 +1,10 @@
+#### Note: this error code is no longer emitted by the compiler.
+
 `impl Trait` is not allowed in path parameters.
 
 Erroneous code example:
 
-```compile_fail,E0667
+```ignore (removed error code)
 fn some_fn(mut x: impl Iterator) -> <impl Iterator>::Item { // error!
     x.next().unwrap()
 }
@@ -11,7 +13,7 @@
 You cannot use `impl Trait` in path parameters. If you want something
 equivalent, you can do this instead:
 
-```
+```ignore (removed error code)
 fn some_fn<T: Iterator>(mut x: T) -> T::Item { // ok!
     x.next().unwrap()
 }
diff --git a/compiler/rustc_error_codes/src/error_codes/E0705.md b/compiler/rustc_error_codes/src/error_codes/E0705.md
index 317f3a4..e7d7d74 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0705.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0705.md
@@ -1,6 +1,6 @@
 #### Note: this error code is no longer emitted by the compiler.
 
-A `#![feature]` attribute was declared for a feature that is stable in the
+A `#![feature]` attribute was used for a feature that is stable in the
 current edition, but not in all editions.
 
 Erroneous code example:
diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs
index 1adb6b9..0ccc71a 100644
--- a/compiler/rustc_errors/src/emitter.rs
+++ b/compiler/rustc_errors/src/emitter.rs
@@ -58,9 +58,9 @@
 struct Margin {
     /// The available whitespace in the left that can be consumed when centering.
     pub whitespace_left: usize,
-    /// The column of the beginning of left-most span.
+    /// The column of the beginning of leftmost span.
     pub span_left: usize,
-    /// The column of the end of right-most span.
+    /// The column of the end of rightmost span.
     pub span_right: usize,
     /// The beginning of the line to be displayed.
     pub computed_left: usize,
@@ -128,7 +128,7 @@
         } else {
             0
         };
-        // We want to show as much as possible, max_line_len is the right-most boundary for the
+        // We want to show as much as possible, max_line_len is the rightmost boundary for the
         // relevant code.
         self.computed_right = max(max_line_len, self.computed_left);
 
@@ -685,7 +685,7 @@
             buffer.puts(line_offset, code_offset, "...", Style::LineNumber);
         }
         if margin.was_cut_right(line_len) {
-            // We have stripped some code after the right-most span end, make it clear we did so.
+            // We have stripped some code after the rightmost span end, make it clear we did so.
             buffer.puts(line_offset, code_offset + taken - 3, "...", Style::LineNumber);
         }
         buffer.puts(line_offset, 0, &self.maybe_anonymized(line_index), Style::LineNumber);
diff --git a/compiler/rustc_expand/messages.ftl b/compiler/rustc_expand/messages.ftl
index 57bac9d..fcf3352 100644
--- a/compiler/rustc_expand/messages.ftl
+++ b/compiler/rustc_expand/messages.ftl
@@ -25,7 +25,7 @@
     illegal value for attribute #[collapse_debuginfo(no|external|yes)]
 
 expand_count_repetition_misplaced =
-    `count` can not be placed inside the inner-most repetition
+    `count` can not be placed inside the innermost repetition
 
 expand_crate_name_in_cfg_attr =
     `crate_name` within an `#![cfg_attr]` attribute is forbidden
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index f0cfe13..7e4bc50 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -1,5 +1,6 @@
 use std::default::Default;
 use std::iter;
+use std::path::Component::Prefix;
 use std::path::{Path, PathBuf};
 use std::rc::Rc;
 
@@ -865,7 +866,9 @@
             })
             .unwrap_or_else(|| (None, helper_attrs));
         let stability = attr::find_stability(sess, attrs, span);
-        let const_stability = attr::find_const_stability(sess, attrs, span);
+        // We set `is_const_fn` false to avoid getting any implicit const stability.
+        let const_stability =
+            attr::find_const_stability(sess, attrs, span, /* is_const_fn */ false);
         let body_stability = attr::find_body_stability(sess, attrs);
         if let Some((_, sp)) = const_stability {
             sess.dcx().emit_err(errors::MacroConstStability {
@@ -1293,7 +1296,12 @@
         base_path.push(path);
         Ok(base_path)
     } else {
-        Ok(path)
+        // This ensures that Windows verbatim paths are fixed if mixed path separators are used,
+        // which can happen when `concat!` is used to join paths.
+        match path.components().next() {
+            Some(Prefix(prefix)) if prefix.kind().is_verbatim() => Ok(path.components().collect()),
+            _ => Ok(path),
+        }
     }
 }
 
diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs
index ea06415..dc6aa11 100644
--- a/compiler/rustc_expand/src/config.rs
+++ b/compiler/rustc_expand/src/config.rs
@@ -11,7 +11,8 @@
 use rustc_attr as attr;
 use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
 use rustc_feature::{
-    ACCEPTED_FEATURES, AttributeSafety, Features, REMOVED_FEATURES, UNSTABLE_FEATURES,
+    ACCEPTED_LANG_FEATURES, AttributeSafety, EnabledLangFeature, EnabledLibFeature, Features,
+    REMOVED_LANG_FEATURES, UNSTABLE_LANG_FEATURES,
 };
 use rustc_lint_defs::BuiltinLintDiag;
 use rustc_parse::validate_attr;
@@ -52,7 +53,7 @@
 
     let mut features = Features::default();
 
-    // Process all features declared in the code.
+    // Process all features enabled in the code.
     for attr in krate_attrs {
         for mi in feature_list(attr) {
             let name = match mi.ident() {
@@ -76,8 +77,8 @@
                 }
             };
 
-            // If the declared feature has been removed, issue an error.
-            if let Some(f) = REMOVED_FEATURES.iter().find(|f| name == f.feature.name) {
+            // If the enabled feature has been removed, issue an error.
+            if let Some(f) = REMOVED_LANG_FEATURES.iter().find(|f| name == f.feature.name) {
                 sess.dcx().emit_err(FeatureRemoved {
                     span: mi.span(),
                     reason: f.reason.map(|reason| FeatureRemovedReason { reason }),
@@ -85,14 +86,17 @@
                 continue;
             }
 
-            // If the declared feature is stable, record it.
-            if let Some(f) = ACCEPTED_FEATURES.iter().find(|f| name == f.name) {
-                let since = Some(Symbol::intern(f.since));
-                features.set_declared_lang_feature(name, mi.span(), since);
+            // If the enabled feature is stable, record it.
+            if let Some(f) = ACCEPTED_LANG_FEATURES.iter().find(|f| name == f.name) {
+                features.set_enabled_lang_feature(EnabledLangFeature {
+                    gate_name: name,
+                    attr_sp: mi.span(),
+                    stable_since: Some(Symbol::intern(f.since)),
+                });
                 continue;
             }
 
-            // If `-Z allow-features` is used and the declared feature is
+            // If `-Z allow-features` is used and the enabled feature is
             // unstable and not also listed as one of the allowed features,
             // issue an error.
             if let Some(allowed) = sess.opts.unstable_opts.allow_features.as_ref() {
@@ -102,9 +106,8 @@
                 }
             }
 
-            // If the declared feature is unstable, record it.
-            if let Some(f) = UNSTABLE_FEATURES.iter().find(|f| name == f.feature.name) {
-                (f.set_enabled)(&mut features);
+            // If the enabled feature is unstable, record it.
+            if UNSTABLE_LANG_FEATURES.iter().find(|f| name == f.name).is_some() {
                 // When the ICE comes from core, alloc or std (approximation of the standard
                 // library), there's a chance that the person hitting the ICE may be using
                 // -Zbuild-std or similar with an untested target. The bug is probably in the
@@ -115,13 +118,19 @@
                 {
                     sess.using_internal_features.store(true, std::sync::atomic::Ordering::Relaxed);
                 }
-                features.set_declared_lang_feature(name, mi.span(), None);
+
+                features.set_enabled_lang_feature(EnabledLangFeature {
+                    gate_name: name,
+                    attr_sp: mi.span(),
+                    stable_since: None,
+                });
                 continue;
             }
 
-            // Otherwise, the feature is unknown. Record it as a lib feature.
-            // It will be checked later.
-            features.set_declared_lib_feature(name, mi.span());
+            // Otherwise, the feature is unknown. Enable it as a lib feature.
+            // It will be checked later whether the feature really exists.
+            features
+                .set_enabled_lib_feature(EnabledLibFeature { gate_name: name, attr_sp: mi.span() });
 
             // Similar to above, detect internal lib features to suppress
             // the ICE message that asks for a report.
@@ -396,7 +405,7 @@
     /// If attributes are not allowed on expressions, emit an error for `attr`
     #[instrument(level = "trace", skip(self))]
     pub(crate) fn maybe_emit_expr_attr_err(&self, attr: &Attribute) {
-        if self.features.is_some_and(|features| !features.stmt_expr_attributes)
+        if self.features.is_some_and(|features| !features.stmt_expr_attributes())
             && !attr.span.allows_unstable(sym::stmt_expr_attributes)
         {
             let mut err = feature_err(
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index a872b12..5ffafca 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -867,7 +867,7 @@
             | Annotatable::FieldDef(..)
             | Annotatable::Variant(..) => panic!("unexpected annotatable"),
         };
-        if self.cx.ecfg.features.proc_macro_hygiene {
+        if self.cx.ecfg.features.proc_macro_hygiene() {
             return;
         }
         feature_err(
@@ -905,7 +905,7 @@
             }
         }
 
-        if !self.cx.ecfg.features.proc_macro_hygiene {
+        if !self.cx.ecfg.features.proc_macro_hygiene() {
             annotatable.visit_with(&mut GateProcMacroInput { sess: &self.cx.sess });
         }
     }
diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs
index f40f99b..fcc90c3 100644
--- a/compiler/rustc_expand/src/mbe/macro_rules.rs
+++ b/compiler/rustc_expand/src/mbe/macro_rules.rs
@@ -3,12 +3,11 @@
 use std::{mem, slice};
 
 use ast::token::IdentIsRaw;
-use rustc_ast as ast;
 use rustc_ast::token::NtPatKind::*;
 use rustc_ast::token::TokenKind::*;
 use rustc_ast::token::{self, Delimiter, NonterminalKind, Token, TokenKind};
 use rustc_ast::tokenstream::{DelimSpan, TokenStream};
-use rustc_ast::{DUMMY_NODE_ID, NodeId};
+use rustc_ast::{self as ast, DUMMY_NODE_ID, NodeId};
 use rustc_ast_pretty::pprust;
 use rustc_attr::{self as attr, TransparencyError};
 use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
@@ -370,34 +369,32 @@
 pub fn compile_declarative_macro(
     sess: &Session,
     features: &Features,
-    def: &ast::Item,
+    macro_def: &ast::MacroDef,
+    ident: Ident,
+    attrs: &[ast::Attribute],
+    span: Span,
+    node_id: NodeId,
     edition: Edition,
 ) -> (SyntaxExtension, Vec<(usize, Span)>) {
-    debug!("compile_declarative_macro: {:?}", def);
     let mk_syn_ext = |expander| {
         SyntaxExtension::new(
             sess,
             features,
             SyntaxExtensionKind::LegacyBang(expander),
-            def.span,
+            span,
             Vec::new(),
             edition,
-            def.ident.name,
-            &def.attrs,
-            def.id != DUMMY_NODE_ID,
+            ident.name,
+            attrs,
+            node_id != DUMMY_NODE_ID,
         )
     };
     let dummy_syn_ext = |guar| (mk_syn_ext(Box::new(DummyExpander(guar))), Vec::new());
 
     let dcx = sess.dcx();
-    let lhs_nm = Ident::new(sym::lhs, def.span);
-    let rhs_nm = Ident::new(sym::rhs, def.span);
+    let lhs_nm = Ident::new(sym::lhs, span);
+    let rhs_nm = Ident::new(sym::rhs, span);
     let tt_spec = Some(NonterminalKind::TT);
-
-    let macro_def = match &def.kind {
-        ast::ItemKind::MacroDef(def) => def,
-        _ => unreachable!(),
-    };
     let macro_rules = macro_def.macro_rules;
 
     // Parse the macro_rules! invocation
@@ -410,25 +407,22 @@
     let argument_gram = vec![
         mbe::TokenTree::Sequence(DelimSpan::dummy(), mbe::SequenceRepetition {
             tts: vec![
-                mbe::TokenTree::MetaVarDecl(def.span, lhs_nm, tt_spec),
-                mbe::TokenTree::token(token::FatArrow, def.span),
-                mbe::TokenTree::MetaVarDecl(def.span, rhs_nm, tt_spec),
+                mbe::TokenTree::MetaVarDecl(span, lhs_nm, tt_spec),
+                mbe::TokenTree::token(token::FatArrow, span),
+                mbe::TokenTree::MetaVarDecl(span, rhs_nm, tt_spec),
             ],
-            separator: Some(Token::new(
-                if macro_rules { token::Semi } else { token::Comma },
-                def.span,
-            )),
-            kleene: mbe::KleeneToken::new(mbe::KleeneOp::OneOrMore, def.span),
+            separator: Some(Token::new(if macro_rules { token::Semi } else { token::Comma }, span)),
+            kleene: mbe::KleeneToken::new(mbe::KleeneOp::OneOrMore, span),
             num_captures: 2,
         }),
         // to phase into semicolon-termination instead of semicolon-separation
         mbe::TokenTree::Sequence(DelimSpan::dummy(), mbe::SequenceRepetition {
             tts: vec![mbe::TokenTree::token(
                 if macro_rules { token::Semi } else { token::Comma },
-                def.span,
+                span,
             )],
             separator: None,
-            kleene: mbe::KleeneToken::new(mbe::KleeneOp::ZeroOrMore, def.span),
+            kleene: mbe::KleeneToken::new(mbe::KleeneOp::ZeroOrMore, span),
             num_captures: 0,
         }),
     ];
@@ -460,7 +454,7 @@
                 };
 
                 let s = parse_failure_msg(&token, track.get_expected_token());
-                let sp = token.span.substitute_dummy(def.span);
+                let sp = token.span.substitute_dummy(span);
                 let mut err = sess.dcx().struct_span_err(sp, s);
                 err.span_label(sp, msg);
                 annotate_doc_comment(&mut err, sess.source_map(), sp);
@@ -468,7 +462,7 @@
                 return dummy_syn_ext(guar);
             }
             Error(sp, msg) => {
-                let guar = sess.dcx().span_err(sp.substitute_dummy(def.span), msg);
+                let guar = sess.dcx().span_err(sp.substitute_dummy(span), msg);
                 return dummy_syn_ext(guar);
             }
             ErrorReported(guar) => {
@@ -489,7 +483,7 @@
                         &TokenStream::new(vec![tt.clone()]),
                         true,
                         sess,
-                        def.id,
+                        node_id,
                         features,
                         edition,
                     )
@@ -497,13 +491,13 @@
                     .unwrap();
                     // We don't handle errors here, the driver will abort
                     // after parsing/expansion. We can report every error in every macro this way.
-                    check_emission(check_lhs_nt_follows(sess, def, &tt));
+                    check_emission(check_lhs_nt_follows(sess, node_id, &tt));
                     return tt;
                 }
-                sess.dcx().span_bug(def.span, "wrong-structured lhs")
+                sess.dcx().span_bug(span, "wrong-structured lhs")
             })
             .collect::<Vec<mbe::TokenTree>>(),
-        _ => sess.dcx().span_bug(def.span, "wrong-structured lhs"),
+        _ => sess.dcx().span_bug(span, "wrong-structured lhs"),
     };
 
     let rhses = match &argument_map[&MacroRulesNormalizedIdent::new(rhs_nm)] {
@@ -515,17 +509,17 @@
                         &TokenStream::new(vec![tt.clone()]),
                         false,
                         sess,
-                        def.id,
+                        node_id,
                         features,
                         edition,
                     )
                     .pop()
                     .unwrap();
                 }
-                sess.dcx().span_bug(def.span, "wrong-structured rhs")
+                sess.dcx().span_bug(span, "wrong-structured rhs")
             })
             .collect::<Vec<mbe::TokenTree>>(),
-        _ => sess.dcx().span_bug(def.span, "wrong-structured rhs"),
+        _ => sess.dcx().span_bug(span, "wrong-structured rhs"),
     };
 
     for rhs in &rhses {
@@ -537,15 +531,9 @@
         check_emission(check_lhs_no_empty_seq(sess, slice::from_ref(lhs)));
     }
 
-    check_emission(macro_check::check_meta_variables(
-        &sess.psess,
-        def.id,
-        def.span,
-        &lhses,
-        &rhses,
-    ));
+    check_emission(macro_check::check_meta_variables(&sess.psess, node_id, span, &lhses, &rhses));
 
-    let (transparency, transparency_error) = attr::find_transparency(&def.attrs, macro_rules);
+    let (transparency, transparency_error) = attr::find_transparency(attrs, macro_rules);
     match transparency_error {
         Some(TransparencyError::UnknownTransparency(value, span)) => {
             dcx.span_err(span, format!("unknown macro transparency: `{value}`"));
@@ -564,7 +552,7 @@
 
     // Compute the spans of the macro rules for unused rule linting.
     // Also, we are only interested in non-foreign macros.
-    let rule_spans = if def.id != DUMMY_NODE_ID {
+    let rule_spans = if node_id != DUMMY_NODE_ID {
         lhses
             .iter()
             .zip(rhses.iter())
@@ -590,15 +578,15 @@
                 mbe::TokenTree::Delimited(.., delimited) => {
                     mbe::macro_parser::compute_locs(&delimited.tts)
                 }
-                _ => sess.dcx().span_bug(def.span, "malformed macro lhs"),
+                _ => sess.dcx().span_bug(span, "malformed macro lhs"),
             }
         })
         .collect();
 
     let expander = Box::new(MacroRulesMacroExpander {
-        name: def.ident,
-        span: def.span,
-        node_id: def.id,
+        name: ident,
+        span,
+        node_id,
         transparency,
         lhses,
         rhses,
@@ -608,13 +596,13 @@
 
 fn check_lhs_nt_follows(
     sess: &Session,
-    def: &ast::Item,
+    node_id: NodeId,
     lhs: &mbe::TokenTree,
 ) -> Result<(), ErrorGuaranteed> {
     // lhs is going to be like TokenTree::Delimited(...), where the
     // entire lhs is those tts. Or, it can be a "bare sequence", not wrapped in parens.
     if let mbe::TokenTree::Delimited(.., delimited) = lhs {
-        check_matcher(sess, def, &delimited.tts)
+        check_matcher(sess, node_id, &delimited.tts)
     } else {
         let msg = "invalid macro matcher; matchers must be contained in balanced delimiters";
         Err(sess.dcx().span_err(lhs.span(), msg))
@@ -686,12 +674,12 @@
 
 fn check_matcher(
     sess: &Session,
-    def: &ast::Item,
+    node_id: NodeId,
     matcher: &[mbe::TokenTree],
 ) -> Result<(), ErrorGuaranteed> {
     let first_sets = FirstSets::new(matcher);
     let empty_suffix = TokenSet::empty();
-    check_matcher_core(sess, def, &first_sets, matcher, &empty_suffix)?;
+    check_matcher_core(sess, node_id, &first_sets, matcher, &empty_suffix)?;
     Ok(())
 }
 
@@ -1028,7 +1016,7 @@
 // see `FirstSets::new`.
 fn check_matcher_core<'tt>(
     sess: &Session,
-    def: &ast::Item,
+    node_id: NodeId,
     first_sets: &FirstSets<'tt>,
     matcher: &'tt [mbe::TokenTree],
     follow: &TokenSet<'tt>,
@@ -1082,7 +1070,7 @@
                     token::CloseDelim(d.delim),
                     span.close,
                 ));
-                check_matcher_core(sess, def, first_sets, &d.tts, &my_suffix)?;
+                check_matcher_core(sess, node_id, first_sets, &d.tts, &my_suffix)?;
                 // don't track non NT tokens
                 last.replace_with_irrelevant();
 
@@ -1114,7 +1102,7 @@
                 // At this point, `suffix_first` is built, and
                 // `my_suffix` is some TokenSet that we can use
                 // for checking the interior of `seq_rep`.
-                let next = check_matcher_core(sess, def, first_sets, &seq_rep.tts, my_suffix)?;
+                let next = check_matcher_core(sess, node_id, first_sets, &seq_rep.tts, my_suffix)?;
                 if next.maybe_empty {
                     last.add_all(&next);
                 } else {
@@ -1144,7 +1132,7 @@
                     // macro. (See #86567.)
                     // Macros defined in the current crate have a real node id,
                     // whereas macros from an external crate have a dummy id.
-                    if def.id != DUMMY_NODE_ID
+                    if node_id != DUMMY_NODE_ID
                         && matches!(kind, NonterminalKind::Pat(PatParam { inferred: true }))
                         && matches!(
                             next_token,
diff --git a/compiler/rustc_expand/src/mbe/metavar_expr.rs b/compiler/rustc_expand/src/mbe/metavar_expr.rs
index c4ba98f..810a5d3 100644
--- a/compiler/rustc_expand/src/mbe/metavar_expr.rs
+++ b/compiler/rustc_expand/src/mbe/metavar_expr.rs
@@ -23,11 +23,11 @@
     /// Ignore a meta-variable for repetition without expansion.
     Ignore(Ident),
 
-    /// The index of the repetition at a particular depth, where 0 is the inner-most
+    /// The index of the repetition at a particular depth, where 0 is the innermost
     /// repetition. The `usize` is the depth.
     Index(usize),
 
-    /// The length of the repetition at a particular depth, where 0 is the inner-most
+    /// The length of the repetition at a particular depth, where 0 is the innermost
     /// repetition. The `usize` is the depth.
     Len(usize),
 }
diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs
index 2edd289..1345f06 100644
--- a/compiler/rustc_expand/src/mbe/quoted.rs
+++ b/compiler/rustc_expand/src/mbe/quoted.rs
@@ -119,16 +119,16 @@
     result
 }
 
-/// Asks for the `macro_metavar_expr` feature if it is not already declared
+/// Asks for the `macro_metavar_expr` feature if it is not enabled
 fn maybe_emit_macro_metavar_expr_feature(features: &Features, sess: &Session, span: Span) {
-    if !features.macro_metavar_expr {
+    if !features.macro_metavar_expr() {
         let msg = "meta-variable expressions are unstable";
         feature_err(sess, sym::macro_metavar_expr, span, msg).emit();
     }
 }
 
 fn maybe_emit_macro_metavar_expr_concat_feature(features: &Features, sess: &Session, span: Span) {
-    if !features.macro_metavar_expr_concat {
+    if !features.macro_metavar_expr_concat() {
         let msg = "the `concat` meta-variable expression is unstable";
         feature_err(sess, sym::macro_metavar_expr_concat, span, msg).emit();
     }
diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs
index fb6fe0b..34811ca 100644
--- a/compiler/rustc_expand/src/mbe/transcribe.rs
+++ b/compiler/rustc_expand/src/mbe/transcribe.rs
@@ -570,7 +570,7 @@
     }
 }
 
-/// Used solely by the `count` meta-variable expression, counts the outer-most repetitions at a
+/// Used solely by the `count` meta-variable expression, counts the outermost repetitions at a
 /// given optional nested depth.
 ///
 /// For example, a macro parameter of `$( { $( $foo:ident ),* } )*` called with `{ a, b } { c }`:
diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs
index 5344580..ac922f1 100644
--- a/compiler/rustc_feature/src/accepted.rs
+++ b/compiler/rustc_feature/src/accepted.rs
@@ -9,7 +9,7 @@
         $(#[doc = $doc:tt])* (accepted, $feature:ident, $ver:expr, $issue:expr),
     )+) => {
         /// Formerly unstable features that have now been accepted (stabilized).
-        pub const ACCEPTED_FEATURES: &[Feature] = &[
+        pub const ACCEPTED_LANG_FEATURES: &[Feature] = &[
             $(Feature {
                 name: sym::$feature,
                 since: $ver,
@@ -364,6 +364,8 @@
     (accepted, self_in_typedefs, "1.32.0", Some(49303)),
     /// Allows `Self` struct constructor (RFC 2302).
     (accepted, self_struct_ctor, "1.32.0", Some(51994)),
+    /// Shortern the tail expression lifetime
+    (accepted, shorter_tail_lifetimes, "CURRENT_RUSTC_VERSION", Some(123739)),
     /// Allows using subslice patterns, `[a, .., b]` and `[a, xs @ .., b]`.
     (accepted, slice_patterns, "1.42.0", Some(62254)),
     /// Allows use of `&foo[a..b]` as a slicing syntax.
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index 477760a..0069b07 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -12,33 +12,31 @@
 
 type GateFn = fn(&Features) -> bool;
 
-macro_rules! cfg_fn {
-    ($field: ident) => {
-        (|features| features.$field) as GateFn
-    };
-}
-
 pub type GatedCfg = (Symbol, Symbol, GateFn);
 
 /// `cfg(...)`'s that are feature gated.
 const GATED_CFGS: &[GatedCfg] = &[
     // (name in cfg, feature, function to check if the feature is enabled)
-    (sym::overflow_checks, sym::cfg_overflow_checks, cfg_fn!(cfg_overflow_checks)),
-    (sym::ub_checks, sym::cfg_ub_checks, cfg_fn!(cfg_ub_checks)),
-    (sym::target_thread_local, sym::cfg_target_thread_local, cfg_fn!(cfg_target_thread_local)),
+    (sym::overflow_checks, sym::cfg_overflow_checks, Features::cfg_overflow_checks),
+    (sym::ub_checks, sym::cfg_ub_checks, Features::cfg_ub_checks),
+    (sym::target_thread_local, sym::cfg_target_thread_local, Features::cfg_target_thread_local),
     (
         sym::target_has_atomic_equal_alignment,
         sym::cfg_target_has_atomic_equal_alignment,
-        cfg_fn!(cfg_target_has_atomic_equal_alignment),
+        Features::cfg_target_has_atomic_equal_alignment,
     ),
-    (sym::target_has_atomic_load_store, sym::cfg_target_has_atomic, cfg_fn!(cfg_target_has_atomic)),
-    (sym::sanitize, sym::cfg_sanitize, cfg_fn!(cfg_sanitize)),
-    (sym::version, sym::cfg_version, cfg_fn!(cfg_version)),
-    (sym::relocation_model, sym::cfg_relocation_model, cfg_fn!(cfg_relocation_model)),
-    (sym::sanitizer_cfi_generalize_pointers, sym::cfg_sanitizer_cfi, cfg_fn!(cfg_sanitizer_cfi)),
-    (sym::sanitizer_cfi_normalize_integers, sym::cfg_sanitizer_cfi, cfg_fn!(cfg_sanitizer_cfi)),
+    (
+        sym::target_has_atomic_load_store,
+        sym::cfg_target_has_atomic,
+        Features::cfg_target_has_atomic,
+    ),
+    (sym::sanitize, sym::cfg_sanitize, Features::cfg_sanitize),
+    (sym::version, sym::cfg_version, Features::cfg_version),
+    (sym::relocation_model, sym::cfg_relocation_model, Features::cfg_relocation_model),
+    (sym::sanitizer_cfi_generalize_pointers, sym::cfg_sanitizer_cfi, Features::cfg_sanitizer_cfi),
+    (sym::sanitizer_cfi_normalize_integers, sym::cfg_sanitizer_cfi, Features::cfg_sanitizer_cfi),
     // this is consistent with naming of the compiler flag it's for
-    (sym::fmt_debug, sym::fmt_debug, cfg_fn!(fmt_debug)),
+    (sym::fmt_debug, sym::fmt_debug, Features::fmt_debug),
 ];
 
 /// Find a gated cfg determined by the `pred`icate which is given the cfg's name.
@@ -220,7 +218,7 @@
             safety: AttributeSafety::Unsafe,
             template: $tpl,
             duplicates: $duplicates,
-            gate: Gated(Stability::Unstable, sym::$gate, $msg, cfg_fn!($gate)),
+            gate: Gated(Stability::Unstable, sym::$gate, $msg, Features::$gate),
         }
     };
     (unsafe $attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $msg:expr $(,)?) => {
@@ -231,7 +229,7 @@
             safety: AttributeSafety::Unsafe,
             template: $tpl,
             duplicates: $duplicates,
-            gate: Gated(Stability::Unstable, sym::$attr, $msg, cfg_fn!($attr)),
+            gate: Gated(Stability::Unstable, sym::$attr, $msg, Features::$attr),
         }
     };
     ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $gate:ident, $msg:expr $(,)?) => {
@@ -242,7 +240,7 @@
             safety: AttributeSafety::Normal,
             template: $tpl,
             duplicates: $duplicates,
-            gate: Gated(Stability::Unstable, sym::$gate, $msg, cfg_fn!($gate)),
+            gate: Gated(Stability::Unstable, sym::$gate, $msg, Features::$gate),
         }
     };
     ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $msg:expr $(,)?) => {
@@ -253,7 +251,7 @@
             safety: AttributeSafety::Normal,
             template: $tpl,
             duplicates: $duplicates,
-            gate: Gated(Stability::Unstable, sym::$attr, $msg, cfg_fn!($attr)),
+            gate: Gated(Stability::Unstable, sym::$attr, $msg, Features::$attr),
         }
     };
 }
@@ -282,7 +280,7 @@
             safety: AttributeSafety::Normal,
             template: $tpl,
             duplicates: $duplicates,
-            gate: Gated(Stability::Unstable, sym::rustc_attrs, $msg, cfg_fn!(rustc_attrs)),
+            gate: Gated(Stability::Unstable, sym::rustc_attrs, $msg, Features::rustc_attrs),
         }
     };
 }
@@ -620,11 +618,6 @@
         "allow_internal_unstable side-steps feature gating and stability checks",
     ),
     gated!(
-        rustc_allow_const_fn_unstable, Normal,
-        template!(Word, List: "feat1, feat2, ..."), DuplicatesOk, EncodeCrossCrate::No,
-        "rustc_allow_const_fn_unstable side-steps feature gating and stability checks"
-    ),
-    gated!(
         allow_internal_unsafe, Normal, template!(Word), WarnFollowing,
         EncodeCrossCrate::No, "allow_internal_unsafe side-steps the unsafe_code lint",
     ),
@@ -841,8 +834,13 @@
         EncodeCrossCrate::Yes, INTERNAL_UNSTABLE
     ),
     rustc_attr!(
-        rustc_runtime, Normal, template!(Word), WarnFollowing,
-        EncodeCrossCrate::No, INTERNAL_UNSTABLE
+        rustc_const_stable_indirect, Normal,
+        template!(Word), WarnFollowing, EncodeCrossCrate::No, IMPL_DETAIL,
+    ),
+    gated!(
+        rustc_allow_const_fn_unstable, Normal,
+        template!(Word, List: "feat1, feat2, ..."), DuplicatesOk, EncodeCrossCrate::No,
+        "rustc_allow_const_fn_unstable side-steps feature gating and stability checks"
     ),
 
     // ==========================================================================
@@ -935,7 +933,7 @@
             Stability::Unstable,
             sym::rustc_attrs,
             "diagnostic items compiler internal support for linting",
-            cfg_fn!(rustc_attrs),
+            Features::rustc_attrs,
         ),
     },
     gated!(
@@ -1193,7 +1191,7 @@
 pub fn is_stable_diagnostic_attribute(sym: Symbol, features: &Features) -> bool {
     match sym {
         sym::on_unimplemented => true,
-        sym::do_not_recommend => features.do_not_recommend,
+        sym::do_not_recommend => features.do_not_recommend(),
         _ => false,
     }
 }
diff --git a/compiler/rustc_feature/src/lib.rs b/compiler/rustc_feature/src/lib.rs
index 8f4c0b0..9f42d3e 100644
--- a/compiler/rustc_feature/src/lib.rs
+++ b/compiler/rustc_feature/src/lib.rs
@@ -94,13 +94,13 @@
 
 fn find_lang_feature_issue(feature: Symbol) -> Option<NonZero<u32>> {
     // Search in all the feature lists.
-    if let Some(f) = UNSTABLE_FEATURES.iter().find(|f| f.feature.name == feature) {
-        return f.feature.issue;
-    }
-    if let Some(f) = ACCEPTED_FEATURES.iter().find(|f| f.name == feature) {
+    if let Some(f) = UNSTABLE_LANG_FEATURES.iter().find(|f| f.name == feature) {
         return f.issue;
     }
-    if let Some(f) = REMOVED_FEATURES.iter().find(|f| f.feature.name == feature) {
+    if let Some(f) = ACCEPTED_LANG_FEATURES.iter().find(|f| f.name == feature) {
+        return f.issue;
+    }
+    if let Some(f) = REMOVED_LANG_FEATURES.iter().find(|f| f.feature.name == feature) {
         return f.feature.issue;
     }
     panic!("feature `{feature}` is not declared anywhere");
@@ -127,12 +127,14 @@
     }
 }
 
-pub use accepted::ACCEPTED_FEATURES;
+pub use accepted::ACCEPTED_LANG_FEATURES;
 pub use builtin_attrs::{
     AttributeDuplicates, AttributeGate, AttributeSafety, AttributeTemplate, AttributeType,
     BUILTIN_ATTRIBUTE_MAP, BUILTIN_ATTRIBUTES, BuiltinAttribute, GatedCfg, deprecated_attributes,
     encode_cross_crate, find_gated_cfg, is_builtin_attr_name, is_stable_diagnostic_attribute,
     is_valid_for_get_attr,
 };
-pub use removed::REMOVED_FEATURES;
-pub use unstable::{Features, INCOMPATIBLE_FEATURES, UNSTABLE_FEATURES};
+pub use removed::REMOVED_LANG_FEATURES;
+pub use unstable::{
+    EnabledLangFeature, EnabledLibFeature, Features, INCOMPATIBLE_FEATURES, UNSTABLE_LANG_FEATURES,
+};
diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs
index d797fee..8d2e1e8 100644
--- a/compiler/rustc_feature/src/removed.rs
+++ b/compiler/rustc_feature/src/removed.rs
@@ -14,7 +14,7 @@
         $(#[doc = $doc:tt])* (removed, $feature:ident, $ver:expr, $issue:expr, $reason:expr),
     )+) => {
         /// Formerly unstable features that have now been removed.
-        pub const REMOVED_FEATURES: &[RemovedFeature] = &[
+        pub const REMOVED_LANG_FEATURES: &[RemovedFeature] = &[
             $(RemovedFeature {
                 feature: Feature {
                     name: sym::$feature,
@@ -85,6 +85,8 @@
     /// Allows default type parameters to influence type inference.
     (removed, default_type_parameter_fallback, "1.82.0", Some(27336),
      Some("never properly implemented; requires significant design work")),
+    /// Allows deriving traits as per `SmartPointer` specification
+    (removed, derive_smart_pointer, "1.79.0", Some(123430), Some("replaced by `CoercePointee`")),
     /// Allows using `#[doc(keyword = "...")]`.
     (removed, doc_keyword, "1.28.0", Some(51315),
      Some("merged into `#![feature(rustdoc_internals)]`")),
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index f4795c7..93047d4 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -6,11 +6,6 @@
 
 use super::{Feature, to_nonzero};
 
-pub struct UnstableFeature {
-    pub feature: Feature,
-    pub set_enabled: fn(&mut Features),
-}
-
 #[derive(PartialEq)]
 enum FeatureStatus {
     Default,
@@ -30,86 +25,98 @@
     };
 }
 
+/// A set of features to be used by later passes.
+///
+/// There are two ways to check if a language feature `foo` is enabled:
+/// - Directly with the `foo` method, e.g. `if tcx.features().foo() { ... }`.
+/// - With the `enabled` method, e.g. `if tcx.features.enabled(sym::foo) { ... }`.
+///
+/// The former is preferred. `enabled` should only be used when the feature symbol is not a
+/// constant, e.g. a parameter, or when the feature is a library feature.
+#[derive(Clone, Default, Debug)]
+pub struct Features {
+    /// `#![feature]` attrs for language features, for error reporting.
+    enabled_lang_features: Vec<EnabledLangFeature>,
+    /// `#![feature]` attrs for non-language (library) features.
+    enabled_lib_features: Vec<EnabledLibFeature>,
+    /// `enabled_lang_features` + `enabled_lib_features`.
+    enabled_features: FxHashSet<Symbol>,
+}
+
+/// Information about an enabled language feature.
+#[derive(Debug, Copy, Clone)]
+pub struct EnabledLangFeature {
+    /// Name of the feature gate guarding the language feature.
+    pub gate_name: Symbol,
+    /// Span of the `#[feature(...)]` attribute.
+    pub attr_sp: Span,
+    /// If the lang feature is stable, the version number when it was stabilized.
+    pub stable_since: Option<Symbol>,
+}
+
+/// Information abhout an enabled library feature.
+#[derive(Debug, Copy, Clone)]
+pub struct EnabledLibFeature {
+    pub gate_name: Symbol,
+    pub attr_sp: Span,
+}
+
+impl Features {
+    /// `since` should be set for stable features that are nevertheless enabled with a `#[feature]`
+    /// attribute, indicating since when they are stable.
+    pub fn set_enabled_lang_feature(&mut self, lang_feat: EnabledLangFeature) {
+        self.enabled_lang_features.push(lang_feat);
+        self.enabled_features.insert(lang_feat.gate_name);
+    }
+
+    pub fn set_enabled_lib_feature(&mut self, lib_feat: EnabledLibFeature) {
+        self.enabled_lib_features.push(lib_feat);
+        self.enabled_features.insert(lib_feat.gate_name);
+    }
+
+    /// Returns a list of [`EnabledLangFeature`] with info about:
+    ///
+    /// - Feature gate name.
+    /// - The span of the `#[feature]` attribute.
+    /// - For stable language features, version info for when it was stabilized.
+    pub fn enabled_lang_features(&self) -> &Vec<EnabledLangFeature> {
+        &self.enabled_lang_features
+    }
+
+    pub fn enabled_lib_features(&self) -> &Vec<EnabledLibFeature> {
+        &self.enabled_lib_features
+    }
+
+    pub fn enabled_features(&self) -> &FxHashSet<Symbol> {
+        &self.enabled_features
+    }
+
+    /// Is the given feature enabled (via `#[feature(...)]`)?
+    pub fn enabled(&self, feature: Symbol) -> bool {
+        self.enabled_features.contains(&feature)
+    }
+}
+
 macro_rules! declare_features {
     ($(
         $(#[doc = $doc:tt])* ($status:ident, $feature:ident, $ver:expr, $issue:expr),
     )+) => {
         /// Unstable language features that are being implemented or being
         /// considered for acceptance (stabilization) or removal.
-        pub const UNSTABLE_FEATURES: &[UnstableFeature] = &[
-            $(UnstableFeature {
-                feature: Feature {
-                    name: sym::$feature,
-                    since: $ver,
-                    issue: to_nonzero($issue),
-                },
-                // Sets this feature's corresponding bool within `features`.
-                set_enabled: |features| features.$feature = true,
+        pub const UNSTABLE_LANG_FEATURES: &[Feature] = &[
+            $(Feature {
+                name: sym::$feature,
+                since: $ver,
+                issue: to_nonzero($issue),
             }),+
         ];
 
-        const NUM_FEATURES: usize = UNSTABLE_FEATURES.len();
-
-        /// A set of features to be used by later passes.
-        #[derive(Clone, Default, Debug)]
-        pub struct Features {
-            /// `#![feature]` attrs for language features, for error reporting.
-            /// "declared" here means that the feature is actually enabled in the current crate.
-            pub declared_lang_features: Vec<(Symbol, Span, Option<Symbol>)>,
-            /// `#![feature]` attrs for non-language (library) features.
-            /// "declared" here means that the feature is actually enabled in the current crate.
-            pub declared_lib_features: Vec<(Symbol, Span)>,
-            /// `declared_lang_features` + `declared_lib_features`.
-            pub declared_features: FxHashSet<Symbol>,
-            /// Active state of individual features (unstable only).
-            $(
-                $(#[doc = $doc])*
-                pub $feature: bool
-            ),+
-        }
-
         impl Features {
-            pub fn set_declared_lang_feature(
-                &mut self,
-                symbol: Symbol,
-                span: Span,
-                since: Option<Symbol>
-            ) {
-                self.declared_lang_features.push((symbol, span, since));
-                self.declared_features.insert(symbol);
-            }
-
-            pub fn set_declared_lib_feature(&mut self, symbol: Symbol, span: Span) {
-                self.declared_lib_features.push((symbol, span));
-                self.declared_features.insert(symbol);
-            }
-
-            /// This is intended for hashing the set of active features.
-            ///
-            /// The expectation is that this produces much smaller code than other alternatives.
-            ///
-            /// Note that the total feature count is pretty small, so this is not a huge array.
-            #[inline]
-            pub fn all_features(&self) -> [u8; NUM_FEATURES] {
-                [$(self.$feature as u8),+]
-            }
-
-            /// Is the given feature explicitly declared, i.e. named in a
-            /// `#![feature(...)]` within the code?
-            pub fn declared(&self, feature: Symbol) -> bool {
-                self.declared_features.contains(&feature)
-            }
-
-            /// Is the given feature active (enabled by the user)?
-            ///
-            /// Panics if the symbol doesn't correspond to a declared feature.
-            pub fn active(&self, feature: Symbol) -> bool {
-                match feature {
-                    $( sym::$feature => self.$feature, )*
-
-                    _ => panic!("`{}` was not listed in `declare_features`", feature),
+            $(
+                pub fn $feature(&self) -> bool {
+                    self.enabled_features.contains(&sym::$feature)
                 }
-            }
+            )*
 
             /// Some features are known to be incomplete and using them is likely to have
             /// unanticipated results, such as compiler crashes. We warn the user about these
@@ -119,8 +126,11 @@
                     $(
                         sym::$feature => status_to_enum!($status) == FeatureStatus::Incomplete,
                     )*
-                    // Accepted/removed features aren't in this file but are never incomplete.
-                    _ if self.declared_features.contains(&feature) => false,
+                    _ if self.enabled_features.contains(&feature) => {
+                        // Accepted/removed features and library features aren't in this file but
+                        // are never incomplete.
+                        false
+                    }
                     _ => panic!("`{}` was not listed in `declare_features`", feature),
                 }
             }
@@ -132,7 +142,7 @@
                     $(
                         sym::$feature => status_to_enum!($status) == FeatureStatus::Internal,
                     )*
-                    _ if self.declared_features.contains(&feature) => {
+                    _ if self.enabled_features.contains(&feature) => {
                         // This could be accepted/removed, or a libs feature.
                         // Accepted/removed features aren't in this file but are never internal
                         // (a removed feature might have been internal, but that's now irrelevant).
@@ -440,8 +450,6 @@
     (unstable, deprecated_suggestion, "1.61.0", Some(94785)),
     /// Allows deref patterns.
     (incomplete, deref_patterns, "1.79.0", Some(87121)),
-    /// Allows deriving `SmartPointer` traits
-    (unstable, derive_smart_pointer, "1.79.0", Some(123430)),
     /// Controls errors in trait implementations.
     (unstable, do_not_recommend, "1.67.0", Some(51992)),
     /// Tells rustdoc to automatically generate `#[doc(cfg(...))]`.
@@ -586,8 +594,6 @@
     (unstable, rust_cold_cc, "1.63.0", Some(97544)),
     /// Allows use of x86 SHA512, SM3 and SM4 target-features and intrinsics
     (unstable, sha512_sm_x86, "1.82.0", Some(126624)),
-    /// Shortern the tail expression lifetime
-    (unstable, shorter_tail_lifetimes, "1.79.0", Some(123739)),
     /// Allows the use of SIMD types in functions declared in `extern` blocks.
     (unstable, simd_ffi, "1.0.0", Some(27731)),
     /// Allows specialization of implementations (RFC 1210).
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 009c6c4..1c268c8 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -6,8 +6,8 @@
     LitKind, TraitObjectSyntax, UintTy,
 };
 pub use rustc_ast::{
-    BinOp, BinOpKind, BindingMode, BorrowKind, ByRef, CaptureBy, ImplPolarity, IsAuto, Movability,
-    Mutability, UnOp,
+    BinOp, BinOpKind, BindingMode, BorrowKind, BoundConstness, BoundPolarity, ByRef, CaptureBy,
+    ImplPolarity, IsAuto, Movability, Mutability, UnOp,
 };
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::sorted_map::SortedMap;
@@ -502,19 +502,16 @@
     ParenSugar,
 }
 
-/// A modifier on a trait bound.
+/// The modifiers on a trait bound.
 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
-pub enum TraitBoundModifier {
-    /// `Type: Trait`
-    None,
-    /// `Type: !Trait`
-    Negative,
-    /// `Type: ?Trait`
-    Maybe,
-    /// `Type: const Trait`
-    Const,
-    /// `Type: ~const Trait`
-    MaybeConst,
+pub struct TraitBoundModifiers {
+    pub constness: BoundConstness,
+    pub polarity: BoundPolarity,
+}
+
+impl TraitBoundModifiers {
+    pub const NONE: Self =
+        TraitBoundModifiers { constness: BoundConstness::Never, polarity: BoundPolarity::Positive };
 }
 
 #[derive(Clone, Copy, Debug, HashStable_Generic)]
@@ -583,7 +580,6 @@
         ty: &'hir Ty<'hir>,
         /// Optional default value for the const generic param
         default: Option<&'hir ConstArg<'hir>>,
-        is_host_effect: bool,
         synthetic: bool,
     },
 }
@@ -3180,7 +3176,7 @@
     /// The constness and polarity of the trait ref.
     ///
     /// The `async` modifier is lowered directly into a different trait for now.
-    pub modifiers: TraitBoundModifier,
+    pub modifiers: TraitBoundModifiers,
 
     /// The `Foo<&'a T>` in `for<'a> Foo<&'a T>`.
     pub trait_ref: TraitRef<'hir>,
@@ -4085,7 +4081,7 @@
     static_assert_size!(ForeignItem<'_>, 88);
     static_assert_size!(ForeignItemKind<'_>, 56);
     static_assert_size!(GenericArg<'_>, 16);
-    static_assert_size!(GenericBound<'_>, 48);
+    static_assert_size!(GenericBound<'_>, 64);
     static_assert_size!(Generics<'_>, 56);
     static_assert_size!(Impl<'_>, 80);
     static_assert_size!(ImplItem<'_>, 88);
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index ffe519b..322f8e2 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -935,7 +935,7 @@
     match param.kind {
         GenericParamKind::Lifetime { .. } => {}
         GenericParamKind::Type { ref default, .. } => visit_opt!(visitor, visit_ty, default),
-        GenericParamKind::Const { ref ty, ref default, is_host_effect: _, synthetic: _ } => {
+        GenericParamKind::Const { ref ty, ref default, synthetic: _ } => {
             try_visit!(visitor.visit_ty(ty));
             if let Some(ref default) = default {
                 try_visit!(visitor.visit_const_param_default(param.hir_id, default));
diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs
index b161e6b..7d81f97 100644
--- a/compiler/rustc_hir/src/lang_items.rs
+++ b/compiler/rustc_hir/src/lang_items.rs
@@ -241,7 +241,7 @@
     DerefMut,                sym::deref_mut,           deref_mut_trait,            Target::Trait,          GenericRequirement::Exact(0);
     DerefPure,               sym::deref_pure,          deref_pure_trait,           Target::Trait,          GenericRequirement::Exact(0);
     DerefTarget,             sym::deref_target,        deref_target,               Target::AssocTy,        GenericRequirement::None;
-    Receiver,                sym::receiver,            receiver_trait,             Target::Trait,          GenericRequirement::None;
+    LegacyReceiver,          sym::legacy_receiver,     legacy_receiver_trait,      Target::Trait,          GenericRequirement::None;
 
     Fn,                      kw::Fn,                   fn_trait,                   Target::Trait,          GenericRequirement::Exact(1);
     FnMut,                   sym::fn_mut,              fn_mut_trait,               Target::Trait,          GenericRequirement::Exact(1);
@@ -415,14 +415,6 @@
 
     String,                  sym::String,              string,                     Target::Struct,         GenericRequirement::None;
     CStr,                    sym::CStr,                c_str,                      Target::Struct,         GenericRequirement::None;
-
-    EffectsRuntime,          sym::EffectsRuntime,      effects_runtime,            Target::Struct,         GenericRequirement::None;
-    EffectsNoRuntime,        sym::EffectsNoRuntime,    effects_no_runtime,         Target::Struct,         GenericRequirement::None;
-    EffectsMaybe,            sym::EffectsMaybe,        effects_maybe,              Target::Struct,         GenericRequirement::None;
-    EffectsIntersection,     sym::EffectsIntersection, effects_intersection,       Target::Trait,          GenericRequirement::None;
-    EffectsIntersectionOutput, sym::EffectsIntersectionOutput, effects_intersection_output, Target::AssocTy, GenericRequirement::None;
-    EffectsCompat,           sym::EffectsCompat,       effects_compat,             Target::Trait,          GenericRequirement::Exact(1);
-    EffectsTyCompat,         sym::EffectsTyCompat,     effects_ty_compat,          Target::Trait,          GenericRequirement::Exact(1);
 }
 
 pub enum GenericRequirement {
diff --git a/compiler/rustc_hir_analysis/src/bounds.rs b/compiler/rustc_hir_analysis/src/bounds.rs
index 9a2c38e..09ddc6c 100644
--- a/compiler/rustc_hir_analysis/src/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/bounds.rs
@@ -1,15 +1,9 @@
 //! Bounds are restrictions applied to some types after they've been lowered from the HIR to the
 //! [`rustc_middle::ty`] form.
 
-use rustc_data_structures::fx::FxIndexMap;
 use rustc_hir::LangItem;
-use rustc_hir::def::DefKind;
-use rustc_middle::ty::fold::FnMutDelegate;
 use rustc_middle::ty::{self, Ty, TyCtxt, Upcast};
 use rustc_span::Span;
-use rustc_span::def_id::DefId;
-
-use crate::hir_ty_lowering::PredicateFilter;
 
 /// Collects together a list of type bounds. These lists of bounds occur in many places
 /// in Rust's syntax:
@@ -30,7 +24,6 @@
 #[derive(Default, PartialEq, Eq, Clone, Debug)]
 pub(crate) struct Bounds<'tcx> {
     clauses: Vec<(ty::Clause<'tcx>, Span)>,
-    effects_min_tys: FxIndexMap<Ty<'tcx>, Span>,
 }
 
 impl<'tcx> Bounds<'tcx> {
@@ -47,12 +40,9 @@
     pub(crate) fn push_trait_bound(
         &mut self,
         tcx: TyCtxt<'tcx>,
-        defining_def_id: DefId,
         bound_trait_ref: ty::PolyTraitRef<'tcx>,
         span: Span,
         polarity: ty::PredicatePolarity,
-        constness: Option<ty::BoundConstness>,
-        predicate_filter: PredicateFilter,
     ) {
         let clause = (
             bound_trait_ref
@@ -68,137 +58,6 @@
         } else {
             self.clauses.push(clause);
         }
-
-        // FIXME(effects): Lift this out of `push_trait_bound`, and move it somewhere else.
-        // Perhaps moving this into `lower_poly_trait_ref`, just like we lower associated
-        // type bounds.
-        if !tcx.features().effects {
-            return;
-        }
-        match predicate_filter {
-            PredicateFilter::SelfOnly | PredicateFilter::SelfThatDefines(_) => {
-                return;
-            }
-            PredicateFilter::All | PredicateFilter::SelfAndAssociatedTypeBounds => {
-                // Ok.
-            }
-        }
-
-        // For `T: ~const Tr` or `T: const Tr`, we need to add an additional bound on the
-        // associated type of `<T as Tr>` and make sure that the effect is compatible.
-        let compat_val = match (tcx.def_kind(defining_def_id), constness) {
-            // FIXME(effects): revisit the correctness of this
-            (_, Some(ty::BoundConstness::Const)) => tcx.consts.false_,
-            // body owners that can have trait bounds
-            (
-                DefKind::Const | DefKind::Fn | DefKind::AssocFn,
-                Some(ty::BoundConstness::ConstIfConst),
-            ) => tcx.expected_host_effect_param_for_body(defining_def_id),
-
-            (_, None) => {
-                if !tcx.is_const_trait(bound_trait_ref.def_id()) {
-                    return;
-                }
-                tcx.consts.true_
-            }
-            (DefKind::Trait, Some(ty::BoundConstness::ConstIfConst)) => {
-                // we are in a trait, where `bound_trait_ref` could be:
-                // (1) a super trait `trait Foo: ~const Bar`.
-                //     - This generates `<Self as Foo>::Effects: TyCompat<<Self as Bar>::Effects>`
-                //
-                // (2) a where clause `where for<..> Something: ~const Bar`.
-                //     - This generates `for<..> <Self as Foo>::Effects: TyCompat<<Something as Bar>::Effects>`
-                let Some(own_fx) = tcx.associated_type_for_effects(defining_def_id) else {
-                    tcx.dcx().span_delayed_bug(span, "should not have allowed `~const` on a trait that doesn't have `#[const_trait]`");
-                    return;
-                };
-                let own_fx_ty = Ty::new_projection(
-                    tcx,
-                    own_fx,
-                    ty::GenericArgs::identity_for_item(tcx, own_fx),
-                );
-                let Some(their_fx) = tcx.associated_type_for_effects(bound_trait_ref.def_id())
-                else {
-                    tcx.dcx().span_delayed_bug(span, "`~const` on trait without Effects assoc");
-                    return;
-                };
-                let their_fx_ty =
-                    Ty::new_projection(tcx, their_fx, bound_trait_ref.skip_binder().args);
-                let compat = tcx.require_lang_item(LangItem::EffectsTyCompat, Some(span));
-                let clause = bound_trait_ref
-                    .map_bound(|_| {
-                        let trait_ref = ty::TraitRef::new(tcx, compat, [own_fx_ty, their_fx_ty]);
-                        ty::ClauseKind::Trait(ty::TraitPredicate {
-                            trait_ref,
-                            polarity: ty::PredicatePolarity::Positive,
-                        })
-                    })
-                    .upcast(tcx);
-
-                self.clauses.push((clause, span));
-                return;
-            }
-
-            (DefKind::Impl { of_trait: true }, Some(ty::BoundConstness::ConstIfConst)) => {
-                // this is a where clause on an impl header.
-                // push `<T as Tr>::Effects` into the set for the `Min` bound.
-                let Some(assoc) = tcx.associated_type_for_effects(bound_trait_ref.def_id()) else {
-                    tcx.dcx().span_delayed_bug(span, "`~const` on trait without Effects assoc");
-                    return;
-                };
-
-                let ty = bound_trait_ref
-                    .map_bound(|trait_ref| Ty::new_projection(tcx, assoc, trait_ref.args));
-
-                // When the user has written `for<'a, T> X<'a, T>: ~const Foo`, replace the
-                // binders to dummy ones i.e. `X<'static, ()>` so they can be referenced in
-                // the `Min` associated type properly (which doesn't allow using `for<>`)
-                // This should work for any bound variables as long as they don't have any
-                // bounds e.g. `for<T: Trait>`.
-                // FIXME(effects) reconsider this approach to allow compatibility with `for<T: Tr>`
-                let ty = tcx.replace_bound_vars_uncached(ty, FnMutDelegate {
-                    regions: &mut |_| tcx.lifetimes.re_static,
-                    types: &mut |_| tcx.types.unit,
-                    consts: &mut |_| unimplemented!("`~const` does not support const binders"),
-                });
-
-                self.effects_min_tys.insert(ty, span);
-                return;
-            }
-            // for
-            // ```
-            // trait Foo { type Bar: ~const Trait }
-            // ```
-            // ensure that `<Self::Bar as Trait>::Effects: TyCompat<Self::Effects>`.
-            //
-            // FIXME(effects) this is equality for now, which wouldn't be helpful for a non-const implementor
-            // that uses a `Bar` that implements `Trait` with `Maybe` effects.
-            (DefKind::AssocTy, Some(ty::BoundConstness::ConstIfConst)) => {
-                // FIXME(effects): implement this
-                return;
-            }
-            // probably illegal in this position.
-            (_, Some(ty::BoundConstness::ConstIfConst)) => {
-                tcx.dcx().span_delayed_bug(span, "invalid `~const` encountered");
-                return;
-            }
-        };
-        // create a new projection type `<T as Tr>::Effects`
-        let Some(assoc) = tcx.associated_type_for_effects(bound_trait_ref.def_id()) else {
-            tcx.dcx().span_delayed_bug(
-                span,
-                "`~const` trait bound has no effect assoc yet no errors encountered?",
-            );
-            return;
-        };
-        let self_ty = Ty::new_projection(tcx, assoc, bound_trait_ref.skip_binder().args);
-        // make `<T as Tr>::Effects: Compat<runtime>`
-        let new_trait_ref =
-            ty::TraitRef::new(tcx, tcx.require_lang_item(LangItem::EffectsCompat, Some(span)), [
-                ty::GenericArg::from(self_ty),
-                compat_val.into(),
-            ]);
-        self.clauses.push((bound_trait_ref.rebind(new_trait_ref).upcast(tcx), span));
     }
 
     pub(crate) fn push_projection_bound(
@@ -220,15 +79,22 @@
         self.clauses.insert(0, (trait_ref.upcast(tcx), span));
     }
 
-    pub(crate) fn clauses(
-        &self,
-        // FIXME(effects): remove tcx
-        _tcx: TyCtxt<'tcx>,
-    ) -> impl Iterator<Item = (ty::Clause<'tcx>, Span)> + '_ {
-        self.clauses.iter().cloned()
+    /// Push a `const` or `~const` bound as a `HostEffect` predicate.
+    pub(crate) fn push_const_bound(
+        &mut self,
+        tcx: TyCtxt<'tcx>,
+        bound_trait_ref: ty::PolyTraitRef<'tcx>,
+        host: ty::HostPolarity,
+        span: Span,
+    ) {
+        if tcx.is_const_trait(bound_trait_ref.def_id()) {
+            self.clauses.push((bound_trait_ref.to_host_effect_clause(tcx, host), span));
+        } else {
+            tcx.dcx().span_delayed_bug(span, "tried to lower {host:?} bound for non-const trait");
+        }
     }
 
-    pub(crate) fn effects_min_tys(&self) -> impl Iterator<Item = Ty<'tcx>> + '_ {
-        self.effects_min_tys.keys().copied()
+    pub(crate) fn clauses(&self) -> impl Iterator<Item = (ty::Clause<'tcx>, Span)> + '_ {
+        self.clauses.iter().cloned()
     }
 }
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index 2aeeb94..97f3f1c 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -1166,7 +1166,7 @@
         return;
     }
 
-    if adt.is_union() && !tcx.features().transparent_unions {
+    if adt.is_union() && !tcx.features().transparent_unions() {
         feature_err(
             &tcx.sess,
             sym::transparent_unions,
@@ -1301,7 +1301,7 @@
 
     let repr_type_ty = def.repr().discr_type().to_ty(tcx);
     if repr_type_ty == tcx.types.i128 || repr_type_ty == tcx.types.u128 {
-        if !tcx.features().repr128 {
+        if !tcx.features().repr128() {
             feature_err(
                 &tcx.sess,
                 sym::repr128,
diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
index 7595616..9de96b7 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
@@ -43,14 +43,13 @@
 /// - `impl_m`: type of the method we are checking
 /// - `trait_m`: the method in the trait
 /// - `impl_trait_ref`: the TraitRef corresponding to the trait implementation
+#[instrument(level = "debug", skip(tcx))]
 pub(super) fn compare_impl_method<'tcx>(
     tcx: TyCtxt<'tcx>,
     impl_m: ty::AssocItem,
     trait_m: ty::AssocItem,
     impl_trait_ref: ty::TraitRef<'tcx>,
 ) {
-    debug!("compare_impl_method(impl_trait_ref={:?})", impl_trait_ref);
-
     let _: Result<_, ErrorGuaranteed> = try {
         check_method_is_structurally_compatible(tcx, impl_m, trait_m, impl_trait_ref, false)?;
         compare_method_predicate_entailment(tcx, impl_m, trait_m, impl_trait_ref)?;
@@ -167,8 +166,6 @@
     trait_m: ty::AssocItem,
     impl_trait_ref: ty::TraitRef<'tcx>,
 ) -> Result<(), ErrorGuaranteed> {
-    let trait_to_impl_args = impl_trait_ref.args;
-
     // This node-id should be used for the `body_id` field on each
     // `ObligationCause` (and the `FnCtxt`).
     //
@@ -183,27 +180,18 @@
             kind: impl_m.kind,
         });
 
-    // Create mapping from impl to placeholder.
-    let impl_to_placeholder_args = GenericArgs::identity_for_item(tcx, impl_m.def_id);
-
-    // Create mapping from trait to placeholder.
-    let trait_to_placeholder_args =
-        impl_to_placeholder_args.rebase_onto(tcx, impl_m.container_id(tcx), trait_to_impl_args);
-    debug!("compare_impl_method: trait_to_placeholder_args={:?}", trait_to_placeholder_args);
+    // Create mapping from trait method to impl method.
+    let impl_def_id = impl_m.container_id(tcx);
+    let trait_to_impl_args = GenericArgs::identity_for_item(tcx, impl_m.def_id).rebase_onto(
+        tcx,
+        impl_m.container_id(tcx),
+        impl_trait_ref.args,
+    );
+    debug!(?trait_to_impl_args);
 
     let impl_m_predicates = tcx.predicates_of(impl_m.def_id);
     let trait_m_predicates = tcx.predicates_of(trait_m.def_id);
 
-    // Create obligations for each predicate declared by the impl
-    // definition in the context of the trait's parameter
-    // environment. We can't just use `impl_env.caller_bounds`,
-    // however, because we want to replace all late-bound regions with
-    // region variables.
-    let impl_predicates = tcx.predicates_of(impl_m_predicates.parent.unwrap());
-    let mut hybrid_preds = impl_predicates.instantiate_identity(tcx);
-
-    debug!("compare_impl_method: impl_bounds={:?}", hybrid_preds);
-
     // This is the only tricky bit of the new way we check implementation methods
     // We need to build a set of predicates where only the method-level bounds
     // are from the trait and we assume all other bounds from the implementation
@@ -211,25 +199,43 @@
     //
     // We then register the obligations from the impl_m and check to see
     // if all constraints hold.
-    hybrid_preds.predicates.extend(
-        trait_m_predicates
-            .instantiate_own(tcx, trait_to_placeholder_args)
-            .map(|(predicate, _)| predicate),
+    let impl_predicates = tcx.predicates_of(impl_m_predicates.parent.unwrap());
+    let mut hybrid_preds = impl_predicates.instantiate_identity(tcx).predicates;
+    hybrid_preds.extend(
+        trait_m_predicates.instantiate_own(tcx, trait_to_impl_args).map(|(predicate, _)| predicate),
     );
 
-    // Construct trait parameter environment and then shift it into the placeholder viewpoint.
-    // The key step here is to update the caller_bounds's predicates to be
-    // the new hybrid bounds we computed.
+    // FIXME(effects): This should be replaced with a more dedicated method.
+    let is_conditionally_const = tcx.is_conditionally_const(impl_def_id);
+    if is_conditionally_const {
+        // Augment the hybrid param-env with the const conditions
+        // of the impl header and the trait method.
+        hybrid_preds.extend(
+            tcx.const_conditions(impl_def_id)
+                .instantiate_identity(tcx)
+                .into_iter()
+                .chain(
+                    tcx.const_conditions(trait_m.def_id).instantiate_own(tcx, trait_to_impl_args),
+                )
+                .map(|(trait_ref, _)| {
+                    trait_ref.to_host_effect_clause(tcx, ty::HostPolarity::Maybe)
+                }),
+        );
+    }
+
     let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_def_id);
-    let param_env = ty::ParamEnv::new(tcx.mk_clauses(&hybrid_preds.predicates), Reveal::UserFacing);
+    let param_env = ty::ParamEnv::new(tcx.mk_clauses(&hybrid_preds), Reveal::UserFacing);
     let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause);
+    debug!(caller_bounds=?param_env.caller_bounds());
 
     let infcx = &tcx.infer_ctxt().build();
     let ocx = ObligationCtxt::new_with_diagnostics(infcx);
 
-    debug!("compare_impl_method: caller_bounds={:?}", param_env.caller_bounds());
-
-    let impl_m_own_bounds = impl_m_predicates.instantiate_own(tcx, impl_to_placeholder_args);
+    // Create obligations for each predicate declared by the impl
+    // definition in the context of the hybrid param-env. This makes
+    // sure that the impl's method's where clauses are not more
+    // restrictive than the trait's method (and the impl itself).
+    let impl_m_own_bounds = impl_m_predicates.instantiate_own_identity();
     for (predicate, span) in impl_m_own_bounds {
         let normalize_cause = traits::ObligationCause::misc(span, impl_m_def_id);
         let predicate = ocx.normalize(&normalize_cause, param_env, predicate);
@@ -243,6 +249,34 @@
         ocx.register_obligation(traits::Obligation::new(tcx, cause, param_env, predicate));
     }
 
+    // If we're within a const implementation, we need to make sure that the method
+    // does not assume stronger `~const` bounds than the trait definition.
+    //
+    // This registers the `~const` bounds of the impl method, which we will prove
+    // using the hybrid param-env that we earlier augmented with the const conditions
+    // from the impl header and trait method declaration.
+    if is_conditionally_const {
+        for (const_condition, span) in
+            tcx.const_conditions(impl_m.def_id).instantiate_own_identity()
+        {
+            let normalize_cause = traits::ObligationCause::misc(span, impl_m_def_id);
+            let const_condition = ocx.normalize(&normalize_cause, param_env, const_condition);
+
+            let cause =
+                ObligationCause::new(span, impl_m_def_id, ObligationCauseCode::CompareImplItem {
+                    impl_item_def_id: impl_m_def_id,
+                    trait_item_def_id: trait_m.def_id,
+                    kind: impl_m.kind,
+                });
+            ocx.register_obligation(traits::Obligation::new(
+                tcx,
+                cause,
+                param_env,
+                const_condition.to_host_effect_clause(tcx, ty::HostPolarity::Maybe),
+            ));
+        }
+    }
+
     // We now need to check that the signature of the impl method is
     // compatible with that of the trait method. We do this by
     // checking that `impl_fty <: trait_fty`.
@@ -256,7 +290,6 @@
     // any associated types appearing in the fn arguments or return
     // type.
 
-    // Compute placeholder form of impl and trait method tys.
     let mut wf_tys = FxIndexSet::default();
 
     let unnormalized_impl_sig = infcx.instantiate_binder_with_fresh_vars(
@@ -267,9 +300,9 @@
 
     let norm_cause = ObligationCause::misc(impl_m_span, impl_m_def_id);
     let impl_sig = ocx.normalize(&norm_cause, param_env, unnormalized_impl_sig);
-    debug!("compare_impl_method: impl_fty={:?}", impl_sig);
+    debug!(?impl_sig);
 
-    let trait_sig = tcx.fn_sig(trait_m.def_id).instantiate(tcx, trait_to_placeholder_args);
+    let trait_sig = tcx.fn_sig(trait_m.def_id).instantiate(tcx, trait_to_impl_args);
     let trait_sig = tcx.liberate_late_bound_regions(impl_m.def_id, trait_sig);
 
     // Next, add all inputs and output as well-formed tys. Importantly,
@@ -280,9 +313,7 @@
     // We also have to add the normalized trait signature
     // as we don't normalize during implied bounds computation.
     wf_tys.extend(trait_sig.inputs_and_output.iter());
-    let trait_fty = Ty::new_fn_ptr(tcx, ty::Binder::dummy(trait_sig));
-
-    debug!("compare_impl_method: trait_fty={:?}", trait_fty);
+    debug!(?trait_sig);
 
     // FIXME: We'd want to keep more accurate spans than "the method signature" when
     // processing the comparison between the trait and impl fn, but we sadly lose them
@@ -298,6 +329,7 @@
         let emitted = report_trait_method_mismatch(
             infcx,
             cause,
+            param_env,
             terr,
             (trait_m, trait_sig),
             (impl_m, impl_sig),
@@ -455,8 +487,6 @@
     // just so we don't ICE during instantiation later.
     check_method_is_structurally_compatible(tcx, impl_m, trait_m, impl_trait_ref, true)?;
 
-    let trait_to_impl_args = impl_trait_ref.args;
-
     let impl_m_hir_id = tcx.local_def_id_to_hir_id(impl_m_def_id);
     let return_span = tcx.hir().fn_decl_by_hir_id(impl_m_hir_id).unwrap().output.span();
     let cause =
@@ -466,18 +496,18 @@
             kind: impl_m.kind,
         });
 
-    // Create mapping from impl to placeholder.
-    let impl_to_placeholder_args = GenericArgs::identity_for_item(tcx, impl_m.def_id);
-
-    // Create mapping from trait to placeholder.
-    let trait_to_placeholder_args =
-        impl_to_placeholder_args.rebase_onto(tcx, impl_m.container_id(tcx), trait_to_impl_args);
+    // Create mapping from trait to impl (i.e. impl trait header + impl method identity args).
+    let trait_to_impl_args = GenericArgs::identity_for_item(tcx, impl_m.def_id).rebase_onto(
+        tcx,
+        impl_m.container_id(tcx),
+        impl_trait_ref.args,
+    );
 
     let hybrid_preds = tcx
         .predicates_of(impl_m.container_id(tcx))
         .instantiate_identity(tcx)
         .into_iter()
-        .chain(tcx.predicates_of(trait_m.def_id).instantiate_own(tcx, trait_to_placeholder_args))
+        .chain(tcx.predicates_of(trait_m.def_id).instantiate_own(tcx, trait_to_impl_args))
         .map(|(clause, _)| clause);
     let param_env = ty::ParamEnv::new(tcx.mk_clauses_from_iter(hybrid_preds), Reveal::UserFacing);
     let param_env = traits::normalize_param_env_or_error(
@@ -511,7 +541,7 @@
         .instantiate_binder_with_fresh_vars(
             return_span,
             infer::HigherRankedType,
-            tcx.fn_sig(trait_m.def_id).instantiate(tcx, trait_to_placeholder_args),
+            tcx.fn_sig(trait_m.def_id).instantiate(tcx, trait_to_impl_args),
         )
         .fold_with(&mut collector);
 
@@ -581,7 +611,7 @@
         Err(terr) => {
             let mut diag = struct_span_code_err!(
                 tcx.dcx(),
-                cause.span(),
+                cause.span,
                 E0053,
                 "method `{}` has an incompatible return type for trait",
                 trait_m.name
@@ -593,10 +623,10 @@
                 hir.get_if_local(impl_m.def_id)
                     .and_then(|node| node.fn_decl())
                     .map(|decl| (decl.output.span(), Cow::from("return type in trait"), false)),
-                Some(infer::ValuePairs::Terms(ExpectedFound {
+                Some(param_env.and(infer::ValuePairs::Terms(ExpectedFound {
                     expected: trait_return_ty.into(),
                     found: impl_return_ty.into(),
-                })),
+                }))),
                 terr,
                 false,
             );
@@ -620,6 +650,7 @@
             let emitted = report_trait_method_mismatch(
                 infcx,
                 cause,
+                param_env,
                 terr,
                 (trait_m, trait_sig),
                 (impl_m, impl_sig),
@@ -705,7 +736,7 @@
                 // Also, we only need to account for a difference in trait and impl args,
                 // since we previously enforce that the trait method and impl method have the
                 // same generics.
-                let num_trait_args = trait_to_impl_args.len();
+                let num_trait_args = impl_trait_ref.args.len();
                 let num_impl_args = tcx.generics_of(impl_m.container_id(tcx)).own_params.len();
                 let ty = match ty.try_fold_with(&mut RemapHiddenTyRegions {
                     tcx,
@@ -933,6 +964,7 @@
 fn report_trait_method_mismatch<'tcx>(
     infcx: &InferCtxt<'tcx>,
     mut cause: ObligationCause<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
     terr: TypeError<'tcx>,
     (trait_m, trait_sig): (ty::AssocItem, ty::FnSig<'tcx>),
     (impl_m, impl_sig): (ty::AssocItem, ty::FnSig<'tcx>),
@@ -1018,10 +1050,10 @@
         &mut diag,
         &cause,
         trait_err_span.map(|sp| (sp, Cow::from("type in trait"), false)),
-        Some(infer::ValuePairs::PolySigs(ExpectedFound {
+        Some(param_env.and(infer::ValuePairs::PolySigs(ExpectedFound {
             expected: ty::Binder::dummy(trait_sig),
             found: ty::Binder::dummy(impl_sig),
-        })),
+        }))),
         terr,
         false,
     );
@@ -1041,12 +1073,7 @@
     let trait_generics = tcx.generics_of(trait_m.def_id);
     let trait_params = trait_generics.own_counts().lifetimes;
 
-    debug!(
-        "check_region_bounds_on_impl_item: \
-            trait_generics={:?} \
-            impl_generics={:?}",
-        trait_generics, impl_generics
-    );
+    debug!(?trait_generics, ?impl_generics);
 
     // Must have same number of early-bound lifetime parameters.
     // Unfortunately, if the user screws up the bounds, then this
@@ -1142,7 +1169,7 @@
         TypeError::ArgumentMutability(i) | TypeError::ArgumentSorts(ExpectedFound { .. }, i) => {
             (impl_args.nth(i).unwrap(), trait_args.and_then(|mut args| args.nth(i)))
         }
-        _ => (cause.span(), tcx.hir().span_if_local(trait_m.def_id)),
+        _ => (cause.span, tcx.hir().span_if_local(trait_m.def_id)),
     }
 }
 
@@ -1710,8 +1737,7 @@
     let trait_const_item = tcx.associated_item(trait_const_item_def);
     let impl_trait_ref =
         tcx.impl_trait_ref(impl_const_item.container_id(tcx)).unwrap().instantiate_identity();
-
-    debug!("compare_impl_const(impl_trait_ref={:?})", impl_trait_ref);
+    debug!(?impl_trait_ref);
 
     compare_number_of_generics(tcx, impl_const_item, trait_const_item, false)?;
     compare_generic_param_kinds(tcx, impl_const_item, trait_const_item, false)?;
@@ -1722,6 +1748,7 @@
 /// The equivalent of [compare_method_predicate_entailment], but for associated constants
 /// instead of associated functions.
 // FIXME(generic_const_items): If possible extract the common parts of `compare_{type,const}_predicate_entailment`.
+#[instrument(level = "debug", skip(tcx))]
 fn compare_const_predicate_entailment<'tcx>(
     tcx: TyCtxt<'tcx>,
     impl_ct: ty::AssocItem,
@@ -1736,13 +1763,14 @@
     // because we shouldn't really have to deal with lifetimes or
     // predicates. In fact some of this should probably be put into
     // shared functions because of DRY violations...
-    let impl_args = GenericArgs::identity_for_item(tcx, impl_ct.def_id);
-    let trait_to_impl_args =
-        impl_args.rebase_onto(tcx, impl_ct.container_id(tcx), impl_trait_ref.args);
+    let trait_to_impl_args = GenericArgs::identity_for_item(tcx, impl_ct.def_id).rebase_onto(
+        tcx,
+        impl_ct.container_id(tcx),
+        impl_trait_ref.args,
+    );
 
     // Create a parameter environment that represents the implementation's
-    // method.
-    // Compute placeholder form of impl and trait const tys.
+    // associated const.
     let impl_ty = tcx.type_of(impl_ct_def_id).instantiate_identity();
 
     let trait_ty = tcx.type_of(trait_ct.def_id).instantiate(tcx, trait_to_impl_args);
@@ -1759,14 +1787,14 @@
     // The predicates declared by the impl definition, the trait and the
     // associated const in the trait are assumed.
     let impl_predicates = tcx.predicates_of(impl_ct_predicates.parent.unwrap());
-    let mut hybrid_preds = impl_predicates.instantiate_identity(tcx);
-    hybrid_preds.predicates.extend(
+    let mut hybrid_preds = impl_predicates.instantiate_identity(tcx).predicates;
+    hybrid_preds.extend(
         trait_ct_predicates
             .instantiate_own(tcx, trait_to_impl_args)
             .map(|(predicate, _)| predicate),
     );
 
-    let param_env = ty::ParamEnv::new(tcx.mk_clauses(&hybrid_preds.predicates), Reveal::UserFacing);
+    let param_env = ty::ParamEnv::new(tcx.mk_clauses(&hybrid_preds), Reveal::UserFacing);
     let param_env = traits::normalize_param_env_or_error(
         tcx,
         param_env,
@@ -1776,7 +1804,7 @@
     let infcx = tcx.infer_ctxt().build();
     let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
 
-    let impl_ct_own_bounds = impl_ct_predicates.instantiate_own(tcx, impl_args);
+    let impl_ct_own_bounds = impl_ct_predicates.instantiate_own_identity();
     for (predicate, span) in impl_ct_own_bounds {
         let cause = ObligationCause::misc(span, impl_ct_def_id);
         let predicate = ocx.normalize(&cause, param_env, predicate);
@@ -1787,20 +1815,15 @@
 
     // There is no "body" here, so just pass dummy id.
     let impl_ty = ocx.normalize(&cause, param_env, impl_ty);
-
-    debug!("compare_const_impl: impl_ty={:?}", impl_ty);
+    debug!(?impl_ty);
 
     let trait_ty = ocx.normalize(&cause, param_env, trait_ty);
-
-    debug!("compare_const_impl: trait_ty={:?}", trait_ty);
+    debug!(?trait_ty);
 
     let err = ocx.sup(&cause, param_env, trait_ty, impl_ty);
 
     if let Err(terr) = err {
-        debug!(
-            "checking associated const for compatibility: impl ty {:?}, trait ty {:?}",
-            impl_ty, trait_ty
-        );
+        debug!(?impl_ty, ?trait_ty);
 
         // Locate the Span containing just the type of the offending impl
         let (ty, _) = tcx.hir().expect_impl_item(impl_ct_def_id).expect_const();
@@ -1824,10 +1847,10 @@
             &mut diag,
             &cause,
             trait_c_span.map(|span| (span, Cow::from("type in trait"), false)),
-            Some(infer::ValuePairs::Terms(ExpectedFound {
+            Some(param_env.and(infer::ValuePairs::Terms(ExpectedFound {
                 expected: trait_ty.into(),
                 found: impl_ty.into(),
-            })),
+            }))),
             terr,
             false,
         );
@@ -1845,14 +1868,13 @@
     ocx.resolve_regions_and_report_errors(impl_ct_def_id, &outlives_env)
 }
 
+#[instrument(level = "debug", skip(tcx))]
 pub(super) fn compare_impl_ty<'tcx>(
     tcx: TyCtxt<'tcx>,
     impl_ty: ty::AssocItem,
     trait_ty: ty::AssocItem,
     impl_trait_ref: ty::TraitRef<'tcx>,
 ) {
-    debug!("compare_impl_type(impl_trait_ref={:?})", impl_trait_ref);
-
     let _: Result<(), ErrorGuaranteed> = try {
         compare_number_of_generics(tcx, impl_ty, trait_ty, false)?;
         compare_generic_param_kinds(tcx, impl_ty, trait_ty, false)?;
@@ -1864,20 +1886,25 @@
 
 /// The equivalent of [compare_method_predicate_entailment], but for associated types
 /// instead of associated functions.
+#[instrument(level = "debug", skip(tcx))]
 fn compare_type_predicate_entailment<'tcx>(
     tcx: TyCtxt<'tcx>,
     impl_ty: ty::AssocItem,
     trait_ty: ty::AssocItem,
     impl_trait_ref: ty::TraitRef<'tcx>,
 ) -> Result<(), ErrorGuaranteed> {
-    let impl_args = GenericArgs::identity_for_item(tcx, impl_ty.def_id);
-    let trait_to_impl_args =
-        impl_args.rebase_onto(tcx, impl_ty.container_id(tcx), impl_trait_ref.args);
+    let impl_def_id = impl_ty.container_id(tcx);
+    let trait_to_impl_args = GenericArgs::identity_for_item(tcx, impl_ty.def_id).rebase_onto(
+        tcx,
+        impl_def_id,
+        impl_trait_ref.args,
+    );
 
     let impl_ty_predicates = tcx.predicates_of(impl_ty.def_id);
     let trait_ty_predicates = tcx.predicates_of(trait_ty.def_id);
 
-    let impl_ty_own_bounds = impl_ty_predicates.instantiate_own(tcx, impl_args);
+    let impl_ty_own_bounds = impl_ty_predicates.instantiate_own_identity();
+    // If there are no bounds, then there are no const conditions, so no need to check that here.
     if impl_ty_own_bounds.len() == 0 {
         // Nothing to check.
         return Ok(());
@@ -1887,29 +1914,46 @@
     // `ObligationCause` (and the `FnCtxt`). This is what
     // `regionck_item` expects.
     let impl_ty_def_id = impl_ty.def_id.expect_local();
-    debug!("compare_type_predicate_entailment: trait_to_impl_args={:?}", trait_to_impl_args);
+    debug!(?trait_to_impl_args);
 
     // The predicates declared by the impl definition, the trait and the
     // associated type in the trait are assumed.
     let impl_predicates = tcx.predicates_of(impl_ty_predicates.parent.unwrap());
-    let mut hybrid_preds = impl_predicates.instantiate_identity(tcx);
-    hybrid_preds.predicates.extend(
+    let mut hybrid_preds = impl_predicates.instantiate_identity(tcx).predicates;
+    hybrid_preds.extend(
         trait_ty_predicates
             .instantiate_own(tcx, trait_to_impl_args)
             .map(|(predicate, _)| predicate),
     );
-
-    debug!("compare_type_predicate_entailment: bounds={:?}", hybrid_preds);
+    debug!(?hybrid_preds);
 
     let impl_ty_span = tcx.def_span(impl_ty_def_id);
     let normalize_cause = ObligationCause::misc(impl_ty_span, impl_ty_def_id);
-    let param_env = ty::ParamEnv::new(tcx.mk_clauses(&hybrid_preds.predicates), Reveal::UserFacing);
+
+    let is_conditionally_const = tcx.is_conditionally_const(impl_ty.def_id);
+    if is_conditionally_const {
+        // Augment the hybrid param-env with the const conditions
+        // of the impl header and the trait assoc type.
+        hybrid_preds.extend(
+            tcx.const_conditions(impl_ty_predicates.parent.unwrap())
+                .instantiate_identity(tcx)
+                .into_iter()
+                .chain(
+                    tcx.const_conditions(trait_ty.def_id).instantiate_own(tcx, trait_to_impl_args),
+                )
+                .map(|(trait_ref, _)| {
+                    trait_ref.to_host_effect_clause(tcx, ty::HostPolarity::Maybe)
+                }),
+        );
+    }
+
+    let param_env = ty::ParamEnv::new(tcx.mk_clauses(&hybrid_preds), Reveal::UserFacing);
     let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause);
+    debug!(caller_bounds=?param_env.caller_bounds());
+
     let infcx = tcx.infer_ctxt().build();
     let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
 
-    debug!("compare_type_predicate_entailment: caller_bounds={:?}", param_env.caller_bounds());
-
     for (predicate, span) in impl_ty_own_bounds {
         let cause = ObligationCause::misc(span, impl_ty_def_id);
         let predicate = ocx.normalize(&cause, param_env, predicate);
@@ -1923,6 +1967,29 @@
         ocx.register_obligation(traits::Obligation::new(tcx, cause, param_env, predicate));
     }
 
+    if is_conditionally_const {
+        // Validate the const conditions of the impl associated type.
+        let impl_ty_own_const_conditions =
+            tcx.const_conditions(impl_ty.def_id).instantiate_own_identity();
+        for (const_condition, span) in impl_ty_own_const_conditions {
+            let normalize_cause = traits::ObligationCause::misc(span, impl_ty_def_id);
+            let const_condition = ocx.normalize(&normalize_cause, param_env, const_condition);
+
+            let cause =
+                ObligationCause::new(span, impl_ty_def_id, ObligationCauseCode::CompareImplItem {
+                    impl_item_def_id: impl_ty_def_id,
+                    trait_item_def_id: trait_ty.def_id,
+                    kind: impl_ty.kind,
+                });
+            ocx.register_obligation(traits::Obligation::new(
+                tcx,
+                cause,
+                param_env,
+                const_condition.to_host_effect_clause(tcx, ty::HostPolarity::Maybe),
+            ));
+        }
+    }
+
     // Check that all obligations are satisfied by the implementation's
     // version.
     let errors = ocx.select_all_or_error();
@@ -2005,15 +2072,31 @@
         ObligationCause::new(impl_ty_span, impl_ty_def_id, code)
     };
 
-    let obligations: Vec<_> = tcx
+    let mut obligations: Vec<_> = tcx
         .explicit_item_bounds(trait_ty.def_id)
         .iter_instantiated_copied(tcx, rebased_args)
         .map(|(concrete_ty_bound, span)| {
-            debug!("check_type_bounds: concrete_ty_bound = {:?}", concrete_ty_bound);
+            debug!(?concrete_ty_bound);
             traits::Obligation::new(tcx, mk_cause(span), param_env, concrete_ty_bound)
         })
         .collect();
-    debug!("check_type_bounds: item_bounds={:?}", obligations);
+
+    // Only in a const implementation do we need to check that the `~const` item bounds hold.
+    if tcx.is_conditionally_const(impl_ty_def_id) {
+        obligations.extend(
+            tcx.implied_const_bounds(trait_ty.def_id)
+                .iter_instantiated_copied(tcx, rebased_args)
+                .map(|(c, span)| {
+                    traits::Obligation::new(
+                        tcx,
+                        mk_cause(span),
+                        param_env,
+                        c.to_host_effect_clause(tcx, ty::HostPolarity::Maybe),
+                    )
+                }),
+        );
+    }
+    debug!(item_bounds=?obligations);
 
     // Normalize predicates with the assumption that the GAT may always normalize
     // to its definition type. This should be the param-env we use to *prove* the
@@ -2032,7 +2115,7 @@
         } else {
             ocx.normalize(&normalize_cause, normalize_param_env, obligation.predicate)
         };
-        debug!("compare_projection_bounds: normalized predicate = {:?}", normalized_predicate);
+        debug!(?normalized_predicate);
         obligation.predicate = normalized_predicate;
 
         ocx.register_obligation(obligation);
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
index 06317a3..c75bdce 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
@@ -58,15 +58,9 @@
 
     // the host effect param should be invisible as it shouldn't matter
     // whether effects is enabled for the intrinsic provider crate.
-    let consts_count = if generics.host_effect_index.is_some() {
-        own_counts.consts - 1
-    } else {
-        own_counts.consts
-    };
-
     if gen_count_ok(own_counts.lifetimes, n_lts, "lifetime")
         && gen_count_ok(own_counts.types, n_tps, "type")
-        && gen_count_ok(consts_count, n_cts, "const")
+        && gen_count_ok(own_counts.consts, n_cts, "const")
     {
         let _ = check_function_signature(
             tcx,
diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs
index 959b17b..58210aa 100644
--- a/compiler/rustc_hir_analysis/src/check/mod.rs
+++ b/compiler/rustc_hir_analysis/src/check/mod.rs
@@ -612,7 +612,7 @@
         match err {
             TypeError::ArgumentMutability(i)
             | TypeError::ArgumentSorts(ExpectedFound { .. }, i) => args.nth(i).unwrap(),
-            _ => cause.span(),
+            _ => cause.span,
         }
     }
 
@@ -646,10 +646,10 @@
                 &mut diag,
                 &cause,
                 None,
-                Some(infer::ValuePairs::PolySigs(ExpectedFound {
+                Some(param_env.and(infer::ValuePairs::PolySigs(ExpectedFound {
                     expected: expected_sig,
                     found: actual_sig,
-                })),
+                }))),
                 err,
                 false,
             );
diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs
index 1a5f465..bfa088f 100644
--- a/compiler/rustc_hir_analysis/src/check/region.rs
+++ b/compiler/rustc_hir_analysis/src/check/region.rs
@@ -167,9 +167,7 @@
             }
         }
         if let Some(tail_expr) = blk.expr {
-            if visitor.tcx.features().shorter_tail_lifetimes
-                && blk.span.edition().at_least_rust_2024()
-            {
+            if blk.span.edition().at_least_rust_2024() {
                 visitor.terminating_scopes.insert(tail_expr.hir_id.local_id);
             }
             visitor.visit_expr(tail_expr);
@@ -466,7 +464,8 @@
 
         hir::ExprKind::If(cond, then, Some(otherwise)) => {
             let expr_cx = visitor.cx;
-            let data = if expr.span.at_least_rust_2024() && visitor.tcx.features().if_let_rescope {
+            let data = if expr.span.at_least_rust_2024() && visitor.tcx.features().if_let_rescope()
+            {
                 ScopeData::IfThenRescope
             } else {
                 ScopeData::IfThen
@@ -481,7 +480,8 @@
 
         hir::ExprKind::If(cond, then, None) => {
             let expr_cx = visitor.cx;
-            let data = if expr.span.at_least_rust_2024() && visitor.tcx.features().if_let_rescope {
+            let data = if expr.span.at_least_rust_2024() && visitor.tcx.features().if_let_rescope()
+            {
                 ScopeData::IfThenRescope
             } else {
                 ScopeData::IfThen
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index f788456..499e42d 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -32,7 +32,8 @@
 use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
 use rustc_trait_selection::traits::{
-    self, FulfillmentError, ObligationCause, ObligationCauseCode, ObligationCtxt, WellFormedLoc,
+    self, FulfillmentError, Obligation, ObligationCause, ObligationCauseCode, ObligationCtxt,
+    WellFormedLoc,
 };
 use rustc_type_ir::TypeFlags;
 use rustc_type_ir::solve::NoSolution;
@@ -86,7 +87,7 @@
             self.body_def_id,
             ObligationCauseCode::WellFormed(loc),
         );
-        self.ocx.register_obligation(traits::Obligation::new(
+        self.ocx.register_obligation(Obligation::new(
             self.tcx(),
             cause,
             self.param_env,
@@ -110,7 +111,7 @@
 
     let mut wfcx = WfCheckingCtxt { ocx, span, body_def_id, param_env };
 
-    if !tcx.features().trivial_bounds {
+    if !tcx.features().trivial_bounds() {
         wfcx.check_false_global_bounds()
     }
     f(&mut wfcx)?;
@@ -913,15 +914,10 @@
         hir::GenericParamKind::Lifetime { .. } | hir::GenericParamKind::Type { .. } => Ok(()),
 
         // Const parameters are well formed if their type is structural match.
-        hir::GenericParamKind::Const {
-            ty: hir_ty,
-            default: _,
-            is_host_effect: _,
-            synthetic: _,
-        } => {
+        hir::GenericParamKind::Const { ty: hir_ty, default: _, synthetic: _ } => {
             let ty = tcx.type_of(param.def_id).instantiate_identity();
 
-            if tcx.features().unsized_const_params {
+            if tcx.features().unsized_const_params() {
                 enter_wf_checking_ctxt(tcx, hir_ty.span, param.def_id, |wfcx| {
                     wfcx.register_bound(
                         ObligationCause::new(
@@ -935,7 +931,7 @@
                     );
                     Ok(())
                 })
-            } else if tcx.features().adt_const_params {
+            } else if tcx.features().adt_const_params() {
                 enter_wf_checking_ctxt(tcx, hir_ty.span, param.def_id, |wfcx| {
                     wfcx.register_bound(
                         ObligationCause::new(
@@ -1178,7 +1174,7 @@
                     wfcx.body_def_id,
                     ObligationCauseCode::Misc,
                 );
-                wfcx.register_obligation(traits::Obligation::new(
+                wfcx.register_obligation(Obligation::new(
                     tcx,
                     cause,
                     wfcx.param_env,
@@ -1374,6 +1370,30 @@
                         obligation.cause.span = hir_self_ty.span;
                     }
                 }
+
+                // Ensure that the `~const` where clauses of the trait hold for the impl.
+                if tcx.is_conditionally_const(item.owner_id.def_id) {
+                    for (bound, _) in
+                        tcx.const_conditions(trait_ref.def_id).instantiate(tcx, trait_ref.args)
+                    {
+                        let bound = wfcx.normalize(
+                            item.span,
+                            Some(WellFormedLoc::Ty(item.hir_id().expect_owner().def_id)),
+                            bound,
+                        );
+                        wfcx.register_obligation(Obligation::new(
+                            tcx,
+                            ObligationCause::new(
+                                hir_self_ty.span,
+                                wfcx.body_def_id,
+                                ObligationCauseCode::WellFormed(None),
+                            ),
+                            wfcx.param_env,
+                            bound.to_host_effect_clause(tcx, ty::HostPolarity::Maybe),
+                        ))
+                    }
+                }
+
                 debug!(?obligations);
                 wfcx.register_obligations(obligations);
             }
@@ -1566,7 +1586,7 @@
                 wfcx.body_def_id,
                 ObligationCauseCode::WhereClause(def_id.to_def_id(), DUMMY_SP),
             );
-            traits::Obligation::new(tcx, cause, wfcx.param_env, pred)
+            Obligation::new(tcx, cause, wfcx.param_env, pred)
         });
 
     let predicates = predicates.instantiate_identity(tcx);
@@ -1698,9 +1718,9 @@
         return Ok(());
     }
 
-    let arbitrary_self_types_level = if tcx.features().arbitrary_self_types_pointers {
+    let arbitrary_self_types_level = if tcx.features().arbitrary_self_types_pointers() {
         Some(ArbitrarySelfTypesLevel::WithPointers)
-    } else if tcx.features().arbitrary_self_types {
+    } else if tcx.features().arbitrary_self_types() {
         Some(ArbitrarySelfTypesLevel::Basic)
     } else {
         None
@@ -1801,7 +1821,7 @@
         autoderef = autoderef.include_raw_pointers();
     }
 
-    let receiver_trait_def_id = tcx.require_lang_item(LangItem::Receiver, Some(span));
+    let receiver_trait_def_id = tcx.require_lang_item(LangItem::LegacyReceiver, Some(span));
 
     // Keep dereferencing `receiver_ty` until we get to `self_ty`.
     while let Some((potential_self_ty, _)) = autoderef.next() {
@@ -1857,7 +1877,7 @@
     let tcx = wfcx.tcx();
     let trait_ref = ty::TraitRef::new(tcx, receiver_trait_def_id, [receiver_ty]);
 
-    let obligation = traits::Obligation::new(tcx, cause, wfcx.param_env, trait_ref);
+    let obligation = Obligation::new(tcx, cause, wfcx.param_env, trait_ref);
 
     if wfcx.infcx.predicate_must_hold_modulo_regions(&obligation) {
         true
@@ -2193,7 +2213,7 @@
                         .unwrap_or(obligation_span);
                 }
 
-                let obligation = traits::Obligation::new(
+                let obligation = Obligation::new(
                     tcx,
                     traits::ObligationCause::new(
                         span,
diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
index 76c75d9..b4f6b5a 100644
--- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
@@ -364,6 +364,7 @@
                 .err_ctxt()
                 .report_mismatched_types(
                     &cause,
+                    param_env,
                     mk_ptr(mt_b.ty),
                     target,
                     ty::error::TypeError::Mutability,
diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
index dfb3c08..2afc2ae 100644
--- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
@@ -77,7 +77,7 @@
             return Ok(());
         }
 
-        if self.tcx.features().rustc_attrs {
+        if self.tcx.features().rustc_attrs() {
             let items = self.tcx.associated_item_def_ids(impl_def_id);
 
             if !self.tcx.has_attr(ty_def_id, sym::rustc_has_incoherent_inherent_impls) {
@@ -115,7 +115,7 @@
     ) -> Result<(), ErrorGuaranteed> {
         let items = self.tcx.associated_item_def_ids(impl_def_id);
         if !self.tcx.hir().rustc_coherence_is_core() {
-            if self.tcx.features().rustc_attrs {
+            if self.tcx.features().rustc_attrs() {
                 for &impl_item in items {
                     if !self.tcx.has_attr(impl_item, sym::rustc_allow_incoherent_impl) {
                         let span = self.tcx.def_span(impl_def_id);
diff --git a/compiler/rustc_hir_analysis/src/coherence/mod.rs b/compiler/rustc_hir_analysis/src/coherence/mod.rs
index eea5a16..3aad4ba 100644
--- a/compiler/rustc_hir_analysis/src/coherence/mod.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/mod.rs
@@ -53,7 +53,7 @@
 ) -> Result<(), ErrorGuaranteed> {
     let impl_header_span = tcx.def_span(impl_def_id);
 
-    if tcx.is_lang_item(trait_def_id, LangItem::Freeze) && !tcx.features().freeze_impls {
+    if tcx.is_lang_item(trait_def_id, LangItem::Freeze) && !tcx.features().freeze_impls() {
         feature_err(
             &tcx.sess,
             sym::freeze_impls,
@@ -86,8 +86,8 @@
 
     if let ty::trait_def::TraitSpecializationKind::AlwaysApplicable = trait_def.specialization_kind
     {
-        if !tcx.features().specialization
-            && !tcx.features().min_specialization
+        if !tcx.features().specialization()
+            && !tcx.features().min_specialization()
             && !impl_header_span.allows_unstable(sym::specialization)
             && !impl_header_span.allows_unstable(sym::min_specialization)
         {
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index f63e2d4..3add801 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -77,6 +77,8 @@
         explicit_supertraits_containing_assoc_item:
             predicates_of::explicit_supertraits_containing_assoc_item,
         trait_explicit_predicates_and_bounds: predicates_of::trait_explicit_predicates_and_bounds,
+        const_conditions: predicates_of::const_conditions,
+        implied_const_bounds: predicates_of::implied_const_bounds,
         type_param_predicates: predicates_of::type_param_predicates,
         trait_def,
         adt_def,
@@ -1129,7 +1131,7 @@
     };
 
     let paren_sugar = tcx.has_attr(def_id, sym::rustc_paren_sugar);
-    if paren_sugar && !tcx.features().unboxed_closures {
+    if paren_sugar && !tcx.features().unboxed_closures() {
         tcx.dcx().emit_err(errors::ParenSugarAttribute { span: item.span });
     }
 
@@ -1595,7 +1597,7 @@
     impl_.of_trait.as_ref().map(|ast_trait_ref| {
         let selfty = tcx.type_of(def_id).instantiate_identity();
 
-        check_impl_constness(tcx, tcx.is_const_trait_impl_raw(def_id.to_def_id()), ast_trait_ref);
+        check_impl_constness(tcx, tcx.is_const_trait_impl(def_id.to_def_id()), ast_trait_ref);
 
         let trait_ref = icx.lowerer().lower_impl_trait_ref(ast_trait_ref, selfty);
 
@@ -1696,7 +1698,7 @@
 
     // Feature gate SIMD types in FFI, since I am not sure that the
     // ABIs are handled at all correctly. -huonw
-    if abi != abi::Abi::RustIntrinsic && !tcx.features().simd_ffi {
+    if abi != abi::Abi::RustIntrinsic && !tcx.features().simd_ffi() {
         let check = |hir_ty: &hir::Ty<'_>, ty: Ty<'_>| {
             if ty.is_simd() {
                 let snip = tcx
diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
index 14b6b17..3eec0e1 100644
--- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
@@ -53,7 +53,6 @@
             param_def_id_to_index,
             has_self: opaque_ty_generics.has_self,
             has_late_bound_regions: opaque_ty_generics.has_late_bound_regions,
-            host_effect_index: parent_generics.host_effect_index,
         };
     }
 
@@ -109,7 +108,7 @@
                 // We do not allow generic parameters in anon consts if we are inside
                 // of a const parameter type, e.g. `struct Foo<const N: usize, const M: [u8; N]>` is not allowed.
                 None
-            } else if tcx.features().generic_const_exprs {
+            } else if tcx.features().generic_const_exprs() {
                 let parent_node = tcx.parent_hir_node(hir_id);
                 debug!(?parent_node);
                 if let Node::Variant(Variant { disr_expr: Some(constant), .. }) = parent_node
@@ -161,7 +160,6 @@
                         param_def_id_to_index,
                         has_self: generics.has_self,
                         has_late_bound_regions: generics.has_late_bound_regions,
-                        host_effect_index: None,
                     };
                 } else {
                     // HACK(eddyb) this provides the correct generics when
@@ -292,12 +290,10 @@
     let has_self = opt_self.is_some();
     let mut parent_has_self = false;
     let mut own_start = has_self as u32;
-    let mut host_effect_index = None;
     let parent_count = parent_def_id.map_or(0, |def_id| {
         let generics = tcx.generics_of(def_id);
         assert!(!has_self);
         parent_has_self = generics.has_self;
-        host_effect_index = generics.host_effect_index;
         own_start = generics.count() as u32;
         generics.parent_count + generics.own_params.len()
     });
@@ -361,12 +357,8 @@
                 kind,
             })
         }
-        GenericParamKind::Const { ty: _, default, is_host_effect, synthetic } => {
-            if !matches!(allow_defaults, Defaults::Allowed)
-                && default.is_some()
-                // `host` effect params are allowed to have defaults.
-                && !is_host_effect
-            {
+        GenericParamKind::Const { ty: _, default, synthetic } => {
+            if !matches!(allow_defaults, Defaults::Allowed) && default.is_some() {
                 tcx.dcx().span_err(
                     param.span,
                     "defaults for const parameters are only allowed in \
@@ -376,27 +368,12 @@
 
             let index = next_index();
 
-            if is_host_effect {
-                if let Some(idx) = host_effect_index {
-                    tcx.dcx().span_delayed_bug(
-                        param.span,
-                        format!("parent also has host effect param? index: {idx}, def: {def_id:?}"),
-                    );
-                }
-
-                host_effect_index = Some(index as usize);
-            }
-
             Some(ty::GenericParamDef {
                 index,
                 name: param.name.ident().name,
                 def_id: param.def_id.to_def_id(),
                 pure_wrt_drop: param.pure_wrt_drop,
-                kind: ty::GenericParamDefKind::Const {
-                    has_default: default.is_some(),
-                    is_host_effect,
-                    synthetic,
-                },
+                kind: ty::GenericParamDefKind::Const { has_default: default.is_some(), synthetic },
             })
         }
     }));
@@ -459,7 +436,6 @@
         param_def_id_to_index,
         has_self: has_self || parent_has_self,
         has_late_bound_regions: has_late_bound_regions(tcx, node),
-        host_effect_index,
     }
 }
 
@@ -540,8 +516,7 @@
     type Result = ControlFlow<()>;
 
     fn visit_generic_param(&mut self, p: &'v hir::GenericParam<'v>) -> Self::Result {
-        if let GenericParamKind::Const { ty, default: _, is_host_effect: _, synthetic: _ } = p.kind
-        {
+        if let GenericParamKind::Const { ty, default: _, synthetic: _ } = p.kind {
             let prev = self.in_param_ty;
             self.in_param_ty = true;
             let res = self.visit_ty(ty);
diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
index 69ebd3a..b2ad42b 100644
--- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
+++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
@@ -40,7 +40,16 @@
     let mut bounds = Bounds::default();
     icx.lowerer().lower_bounds(item_ty, hir_bounds, &mut bounds, ty::List::empty(), filter);
     // Associated types are implicitly sized unless a `?Sized` bound is found
-    icx.lowerer().add_sized_bound(&mut bounds, item_ty, hir_bounds, None, span);
+    match filter {
+        PredicateFilter::All
+        | PredicateFilter::SelfOnly
+        | PredicateFilter::SelfThatDefines(_)
+        | PredicateFilter::SelfAndAssociatedTypeBounds => {
+            icx.lowerer().add_sized_bound(&mut bounds, item_ty, hir_bounds, None, span);
+        }
+        // `ConstIfConst` is only interested in `~const` bounds.
+        PredicateFilter::ConstIfConst | PredicateFilter::SelfConstIfConst => {}
+    }
 
     let trait_def_id = tcx.local_parent(assoc_item_def_id);
     let trait_predicates = tcx.trait_explicit_predicates_and_bounds(trait_def_id);
@@ -58,7 +67,7 @@
             )
         });
 
-    let all_bounds = tcx.arena.alloc_from_iter(bounds.clauses(tcx).chain(bounds_from_parent));
+    let all_bounds = tcx.arena.alloc_from_iter(bounds.clauses().chain(bounds_from_parent));
     debug!(
         "associated_type_bounds({}) = {:?}",
         tcx.def_path_str(assoc_item_def_id.to_def_id()),
@@ -109,10 +118,19 @@
             } else {
                 // Only collect *self* type bounds if the filter is for self.
                 match filter {
-                    PredicateFilter::SelfOnly | PredicateFilter::SelfThatDefines(_) => {
+                    PredicateFilter::All => {}
+                    PredicateFilter::SelfOnly => {
                         return None;
                     }
-                    PredicateFilter::All | PredicateFilter::SelfAndAssociatedTypeBounds => {}
+                    PredicateFilter::SelfThatDefines(_)
+                    | PredicateFilter::SelfConstIfConst
+                    | PredicateFilter::SelfAndAssociatedTypeBounds
+                    | PredicateFilter::ConstIfConst => {
+                        unreachable!(
+                            "invalid predicate filter for \
+                            `remap_gat_vars_and_recurse_into_nested_projections`"
+                        )
+                    }
                 }
 
                 clause_ty = alias_ty.self_ty();
@@ -308,10 +326,20 @@
         let mut bounds = Bounds::default();
         icx.lowerer().lower_bounds(item_ty, hir_bounds, &mut bounds, ty::List::empty(), filter);
         // Opaque types are implicitly sized unless a `?Sized` bound is found
-        icx.lowerer().add_sized_bound(&mut bounds, item_ty, hir_bounds, None, span);
+        match filter {
+            PredicateFilter::All
+            | PredicateFilter::SelfOnly
+            | PredicateFilter::SelfThatDefines(_)
+            | PredicateFilter::SelfAndAssociatedTypeBounds => {
+                // Associated types are implicitly sized unless a `?Sized` bound is found
+                icx.lowerer().add_sized_bound(&mut bounds, item_ty, hir_bounds, None, span);
+            }
+            //`ConstIfConst` is only interested in `~const` bounds.
+            PredicateFilter::ConstIfConst | PredicateFilter::SelfConstIfConst => {}
+        }
         debug!(?bounds);
 
-        tcx.arena.alloc_from_iter(bounds.clauses(tcx))
+        tcx.arena.alloc_from_iter(bounds.clauses())
     })
 }
 
diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
index 9bd8c70..644ff0c 100644
--- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
@@ -12,6 +12,7 @@
 use rustc_span::{DUMMY_SP, Span};
 use tracing::{debug, instrument, trace};
 
+use super::item_bounds::explicit_item_bounds_with_filter;
 use crate::bounds::Bounds;
 use crate::collect::ItemCtxt;
 use crate::constrained_generic_params as cgp;
@@ -78,7 +79,6 @@
 #[instrument(level = "trace", skip(tcx), ret)]
 fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::GenericPredicates<'_> {
     use rustc_hir::*;
-    use rustc_middle::ty::Ty;
 
     match tcx.opt_rpitit_info(def_id.to_def_id()) {
         Some(ImplTraitInTraitData::Trait { fn_def_id, .. }) => {
@@ -106,7 +106,6 @@
             return ty::GenericPredicates {
                 parent: Some(tcx.parent(def_id.to_def_id())),
                 predicates: tcx.arena.alloc_from_iter(predicates),
-                effects_min_tys: ty::List::empty(),
             };
         }
 
@@ -128,7 +127,6 @@
             return ty::GenericPredicates {
                 parent: Some(impl_def_id),
                 predicates: tcx.arena.alloc_from_iter(impl_predicates),
-                effects_min_tys: ty::List::empty(),
             };
         }
 
@@ -154,7 +152,6 @@
     // We use an `IndexSet` to preserve order of insertion.
     // Preserving the order of insertion is important here so as not to break UI tests.
     let mut predicates: FxIndexSet<(ty::Clause<'_>, Span)> = FxIndexSet::default();
-    let mut effects_min_tys = Vec::new();
 
     let hir_generics = node.generics().unwrap_or(NO_GENERICS);
     if let Node::Item(item) = node {
@@ -189,8 +186,7 @@
             ty::List::empty(),
             PredicateFilter::All,
         );
-        predicates.extend(bounds.clauses(tcx));
-        effects_min_tys.extend(bounds.effects_min_tys());
+        predicates.extend(bounds.clauses());
     }
 
     // In default impls, we can assume that the self type implements
@@ -223,7 +219,7 @@
                     param.span,
                 );
                 trace!(?bounds);
-                predicates.extend(bounds.clauses(tcx));
+                predicates.extend(bounds.clauses());
                 trace!(?predicates);
             }
             hir::GenericParamKind::Const { .. } => {
@@ -275,8 +271,7 @@
                     bound_vars,
                     PredicateFilter::All,
                 );
-                predicates.extend(bounds.clauses(tcx));
-                effects_min_tys.extend(bounds.effects_min_tys());
+                predicates.extend(bounds.clauses());
             }
 
             hir::WherePredicate::RegionPredicate(region_pred) => {
@@ -308,7 +303,7 @@
         }
     }
 
-    if tcx.features().generic_const_exprs {
+    if tcx.features().generic_const_exprs() {
         predicates.extend(const_evaluatable_predicates_of(tcx, def_id));
     }
 
@@ -345,30 +340,9 @@
         debug!(?predicates);
     }
 
-    // add `Self::Effects: Compat<HOST>` to ensure non-const impls don't get called
-    // in const contexts.
-    if let Node::TraitItem(&TraitItem { kind: TraitItemKind::Fn(..), .. }) = node
-        && let Some(host_effect_index) = generics.host_effect_index
-    {
-        let parent = generics.parent.unwrap();
-        let Some(assoc_def_id) = tcx.associated_type_for_effects(parent) else {
-            bug!("associated_type_for_effects returned None when there is host effect in generics");
-        };
-        let effects =
-            Ty::new_projection(tcx, assoc_def_id, ty::GenericArgs::identity_for_item(tcx, parent));
-        let param = generics.param_at(host_effect_index, tcx);
-        let span = tcx.def_span(param.def_id);
-        let host = ty::Const::new_param(tcx, ty::ParamConst::for_def(param));
-        let compat = tcx.require_lang_item(LangItem::EffectsCompat, Some(span));
-        let trait_ref =
-            ty::TraitRef::new(tcx, compat, [ty::GenericArg::from(effects), host.into()]);
-        predicates.push((ty::Binder::dummy(trait_ref).upcast(tcx), span));
-    }
-
     ty::GenericPredicates {
         parent: generics.parent,
         predicates: tcx.arena.alloc_from_iter(predicates),
-        effects_min_tys: tcx.mk_type_list(&effects_min_tys),
     }
 }
 
@@ -519,12 +493,11 @@
             ty::GenericPredicates {
                 parent: predicates_and_bounds.parent,
                 predicates: tcx.arena.alloc_slice(&predicates),
-                effects_min_tys: predicates_and_bounds.effects_min_tys,
             }
         }
     } else {
         if matches!(def_kind, DefKind::AnonConst)
-            && tcx.features().generic_const_exprs
+            && tcx.features().generic_const_exprs()
             && let Some(defaulted_param_def_id) =
                 tcx.hir().opt_const_param_default_param_def_id(tcx.local_def_id_to_hir_id(def_id))
         {
@@ -571,7 +544,6 @@
             return GenericPredicates {
                 parent: parent_preds.parent,
                 predicates: { tcx.arena.alloc_from_iter(filtered_predicates) },
-                effects_min_tys: parent_preds.effects_min_tys,
             };
         }
         gather_explicit_predicates_of(tcx, def_id)
@@ -650,7 +622,7 @@
 
     // Combine the two lists to form the complete set of superbounds:
     let implied_bounds =
-        &*tcx.arena.alloc_from_iter(bounds.clauses(tcx).chain(where_bounds_that_match));
+        &*tcx.arena.alloc_from_iter(bounds.clauses().chain(where_bounds_that_match));
     debug!(?implied_bounds);
 
     // Now require that immediate supertraits are lowered, which will, in
@@ -706,29 +678,76 @@
                         assert_eq!(
                             trait_predicate.self_ty(),
                             ty,
-                            "expected `Self` predicate when computing `{filter:?}` implied bounds: {clause:?}"
+                            "expected `Self` predicate when computing \
+                            `{filter:?}` implied bounds: {clause:?}"
                         );
                     }
                     ty::ClauseKind::Projection(projection_predicate) => {
                         assert_eq!(
                             projection_predicate.self_ty(),
                             ty,
-                            "expected `Self` predicate when computing `{filter:?}` implied bounds: {clause:?}"
+                            "expected `Self` predicate when computing \
+                            `{filter:?}` implied bounds: {clause:?}"
                         );
                     }
                     ty::ClauseKind::TypeOutlives(outlives_predicate) => {
                         assert_eq!(
                             outlives_predicate.0, ty,
-                            "expected `Self` predicate when computing `{filter:?}` implied bounds: {clause:?}"
+                            "expected `Self` predicate when computing \
+                            `{filter:?}` implied bounds: {clause:?}"
                         );
                     }
 
                     ty::ClauseKind::RegionOutlives(_)
                     | ty::ClauseKind::ConstArgHasType(_, _)
                     | ty::ClauseKind::WellFormed(_)
-                    | ty::ClauseKind::ConstEvaluatable(_) => {
+                    | ty::ClauseKind::ConstEvaluatable(_)
+                    | ty::ClauseKind::HostEffect(..) => {
                         bug!(
-                            "unexpected non-`Self` predicate when computing `{filter:?}` implied bounds: {clause:?}"
+                            "unexpected non-`Self` predicate when computing \
+                            `{filter:?}` implied bounds: {clause:?}"
+                        );
+                    }
+                }
+            }
+        }
+        PredicateFilter::ConstIfConst => {
+            for (clause, _) in bounds {
+                match clause.kind().skip_binder() {
+                    ty::ClauseKind::HostEffect(ty::HostEffectPredicate {
+                        trait_ref: _,
+                        host: ty::HostPolarity::Maybe,
+                    }) => {}
+                    _ => {
+                        bug!(
+                            "unexpected non-`HostEffect` predicate when computing \
+                            `{filter:?}` implied bounds: {clause:?}"
+                        );
+                    }
+                }
+            }
+        }
+        PredicateFilter::SelfConstIfConst => {
+            for (clause, _) in bounds {
+                match clause.kind().skip_binder() {
+                    ty::ClauseKind::HostEffect(pred) => {
+                        assert_eq!(
+                            pred.host,
+                            ty::HostPolarity::Maybe,
+                            "expected `~const` predicate when computing `{filter:?}` \
+                            implied bounds: {clause:?}",
+                        );
+                        assert_eq!(
+                            pred.trait_ref.self_ty(),
+                            ty,
+                            "expected `Self` predicate when computing `{filter:?}` \
+                            implied bounds: {clause:?}"
+                        );
+                    }
+                    _ => {
+                        bug!(
+                            "unexpected non-`HostEffect` predicate when computing \
+                            `{filter:?}` implied bounds: {clause:?}"
                         );
                     }
                 }
@@ -847,6 +866,147 @@
             );
         }
 
-        bounds.clauses(self.tcx).collect()
+        bounds.clauses().collect()
     }
 }
+
+/// Compute the conditions that need to hold for a conditionally-const item to be const.
+/// That is, compute the set of `~const` where clauses for a given item.
+///
+/// This query also computes the `~const` where clauses for associated types, which are
+/// not "const", but which have item bounds which may be `~const`. These must hold for
+/// the `~const` item bound to hold.
+pub(super) fn const_conditions<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    def_id: LocalDefId,
+) -> ty::ConstConditions<'tcx> {
+    if !tcx.is_conditionally_const(def_id) {
+        bug!("const_conditions invoked for item that is not conditionally const: {def_id:?}");
+    }
+
+    let (generics, trait_def_id_and_supertraits, has_parent) = match tcx.hir_node_by_def_id(def_id)
+    {
+        Node::Item(item) => match item.kind {
+            hir::ItemKind::Impl(impl_) => (impl_.generics, None, false),
+            hir::ItemKind::Fn(_, generics, _) => (generics, None, false),
+            hir::ItemKind::Trait(_, _, generics, supertraits, _) => {
+                (generics, Some((item.owner_id.def_id, supertraits)), false)
+            }
+            _ => bug!("const_conditions called on wrong item: {def_id:?}"),
+        },
+        // While associated types are not really const, we do allow them to have `~const`
+        // bounds and where clauses. `const_conditions` is responsible for gathering
+        // these up so we can check them in `compare_type_predicate_entailment`, and
+        // in `HostEffect` goal computation.
+        Node::TraitItem(item) => match item.kind {
+            hir::TraitItemKind::Fn(_, _) | hir::TraitItemKind::Type(_, _) => {
+                (item.generics, None, true)
+            }
+            _ => bug!("const_conditions called on wrong item: {def_id:?}"),
+        },
+        Node::ImplItem(item) => match item.kind {
+            hir::ImplItemKind::Fn(_, _) | hir::ImplItemKind::Type(_) => {
+                (item.generics, None, tcx.is_conditionally_const(tcx.local_parent(def_id)))
+            }
+            _ => bug!("const_conditions called on wrong item: {def_id:?}"),
+        },
+        Node::ForeignItem(item) => match item.kind {
+            hir::ForeignItemKind::Fn(_, _, generics) => (generics, None, false),
+            _ => bug!("const_conditions called on wrong item: {def_id:?}"),
+        },
+        // N.B. Tuple ctors are unconditionally constant.
+        Node::Ctor(hir::VariantData::Tuple { .. }) => return Default::default(),
+        _ => bug!("const_conditions called on wrong item: {def_id:?}"),
+    };
+
+    let icx = ItemCtxt::new(tcx, def_id);
+    let mut bounds = Bounds::default();
+
+    for pred in generics.predicates {
+        match pred {
+            hir::WherePredicate::BoundPredicate(bound_pred) => {
+                let ty = icx.lowerer().lower_ty_maybe_return_type_notation(bound_pred.bounded_ty);
+                let bound_vars = tcx.late_bound_vars(bound_pred.hir_id);
+                icx.lowerer().lower_bounds(
+                    ty,
+                    bound_pred.bounds.iter(),
+                    &mut bounds,
+                    bound_vars,
+                    PredicateFilter::ConstIfConst,
+                );
+            }
+            _ => {}
+        }
+    }
+
+    if let Some((def_id, supertraits)) = trait_def_id_and_supertraits {
+        bounds.push_const_bound(
+            tcx,
+            ty::Binder::dummy(ty::TraitRef::identity(tcx, def_id.to_def_id())),
+            ty::HostPolarity::Maybe,
+            DUMMY_SP,
+        );
+
+        icx.lowerer().lower_bounds(
+            tcx.types.self_param,
+            supertraits.into_iter(),
+            &mut bounds,
+            ty::List::empty(),
+            PredicateFilter::ConstIfConst,
+        );
+    }
+
+    ty::ConstConditions {
+        parent: has_parent.then(|| tcx.local_parent(def_id).to_def_id()),
+        predicates: tcx.arena.alloc_from_iter(bounds.clauses().map(|(clause, span)| {
+            (
+                clause.kind().map_bound(|clause| match clause {
+                    ty::ClauseKind::HostEffect(ty::HostEffectPredicate {
+                        trait_ref,
+                        host: ty::HostPolarity::Maybe,
+                    }) => trait_ref,
+                    _ => bug!("converted {clause:?}"),
+                }),
+                span,
+            )
+        })),
+    }
+}
+
+pub(super) fn implied_const_bounds<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    def_id: LocalDefId,
+) -> ty::EarlyBinder<'tcx, &'tcx [(ty::PolyTraitRef<'tcx>, Span)]> {
+    if !tcx.is_conditionally_const(def_id) {
+        bug!("const_conditions invoked for item that is not conditionally const: {def_id:?}");
+    }
+
+    let bounds = match tcx.hir_node_by_def_id(def_id) {
+        Node::Item(hir::Item { kind: hir::ItemKind::Trait(..), .. }) => {
+            implied_predicates_with_filter(
+                tcx,
+                def_id.to_def_id(),
+                PredicateFilter::SelfConstIfConst,
+            )
+        }
+        Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Type(..), .. }) => {
+            explicit_item_bounds_with_filter(tcx, def_id, PredicateFilter::ConstIfConst)
+        }
+        _ => bug!("implied_const_bounds called on wrong item: {def_id:?}"),
+    };
+
+    bounds.map_bound(|bounds| {
+        &*tcx.arena.alloc_from_iter(bounds.iter().copied().map(|(clause, span)| {
+            (
+                clause.kind().map_bound(|clause| match clause {
+                    ty::ClauseKind::HostEffect(ty::HostEffectPredicate {
+                        trait_ref,
+                        host: ty::HostPolarity::Maybe,
+                    }) => trait_ref,
+                    _ => bug!("converted {clause:?}"),
+                }),
+                span,
+            )
+        }))
+    })
+}
diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
index cb7f090..f7daef3 100644
--- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
+++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
@@ -33,18 +33,12 @@
 
 #[extension(trait RegionExt)]
 impl ResolvedArg {
-    fn early(param: &GenericParam<'_>) -> (LocalDefId, ResolvedArg) {
-        debug!("ResolvedArg::early: def_id={:?}", param.def_id);
-        (param.def_id, ResolvedArg::EarlyBound(param.def_id))
+    fn early(param: &GenericParam<'_>) -> ResolvedArg {
+        ResolvedArg::EarlyBound(param.def_id)
     }
 
-    fn late(idx: u32, param: &GenericParam<'_>) -> (LocalDefId, ResolvedArg) {
-        let depth = ty::INNERMOST;
-        debug!(
-            "ResolvedArg::late: idx={:?}, param={:?} depth={:?} def_id={:?}",
-            idx, param, depth, param.def_id,
-        );
-        (param.def_id, ResolvedArg::LateBound(depth, idx, param.def_id))
+    fn late(idx: u32, param: &GenericParam<'_>) -> ResolvedArg {
+        ResolvedArg::LateBound(ty::INNERMOST, idx, param.def_id)
     }
 
     fn id(&self) -> Option<LocalDefId> {
@@ -282,24 +276,33 @@
 
 fn late_arg_as_bound_arg<'tcx>(
     tcx: TyCtxt<'tcx>,
-    arg: &ResolvedArg,
     param: &GenericParam<'tcx>,
 ) -> ty::BoundVariableKind {
-    match arg {
-        ResolvedArg::LateBound(_, _, def_id) => {
-            let def_id = def_id.to_def_id();
-            let name = tcx.item_name(def_id);
-            match param.kind {
-                GenericParamKind::Lifetime { .. } => {
-                    ty::BoundVariableKind::Region(ty::BrNamed(def_id, name))
-                }
-                GenericParamKind::Type { .. } => {
-                    ty::BoundVariableKind::Ty(ty::BoundTyKind::Param(def_id, name))
-                }
-                GenericParamKind::Const { .. } => ty::BoundVariableKind::Const,
-            }
+    let def_id = param.def_id.to_def_id();
+    let name = tcx.item_name(def_id);
+    match param.kind {
+        GenericParamKind::Lifetime { .. } => {
+            ty::BoundVariableKind::Region(ty::BrNamed(def_id, name))
         }
-        _ => bug!("{:?} is not a late argument", arg),
+        GenericParamKind::Type { .. } => {
+            ty::BoundVariableKind::Ty(ty::BoundTyKind::Param(def_id, name))
+        }
+        GenericParamKind::Const { .. } => ty::BoundVariableKind::Const,
+    }
+}
+
+/// Turn a [`ty::GenericParamDef`] into a bound arg. Generally, this should only
+/// be used when turning early-bound vars into late-bound vars when lowering
+/// return type notation.
+fn generic_param_def_as_bound_arg(param: &ty::GenericParamDef) -> ty::BoundVariableKind {
+    match param.kind {
+        ty::GenericParamDefKind::Lifetime => {
+            ty::BoundVariableKind::Region(ty::BoundRegionKind::BrNamed(param.def_id, param.name))
+        }
+        ty::GenericParamDefKind::Type { .. } => {
+            ty::BoundVariableKind::Ty(ty::BoundTyKind::Param(param.def_id, param.name))
+        }
+        ty::GenericParamDefKind::Const { .. } => ty::BoundVariableKind::Const,
     }
 }
 
@@ -360,10 +363,9 @@
         let mut bound_vars: FxIndexMap<LocalDefId, ResolvedArg> = FxIndexMap::default();
         let binders_iter =
             trait_ref.bound_generic_params.iter().enumerate().map(|(late_bound_idx, param)| {
-                let pair = ResolvedArg::late(initial_bound_vars + late_bound_idx as u32, param);
-                let r = late_arg_as_bound_arg(self.tcx, &pair.1, param);
-                bound_vars.insert(pair.0, pair.1);
-                r
+                let arg = ResolvedArg::late(initial_bound_vars + late_bound_idx as u32, param);
+                bound_vars.insert(param.def_id, arg);
+                late_arg_as_bound_arg(self.tcx, param)
             });
         binders.extend(binders_iter);
 
@@ -458,9 +460,10 @@
                     .iter()
                     .enumerate()
                     .map(|(late_bound_idx, param)| {
-                        let pair = ResolvedArg::late(late_bound_idx as u32, param);
-                        let r = late_arg_as_bound_arg(self.tcx, &pair.1, param);
-                        (pair, r)
+                        (
+                            (param.def_id, ResolvedArg::late(late_bound_idx as u32, param)),
+                            late_arg_as_bound_arg(self.tcx, param),
+                        )
                     })
                     .unzip();
 
@@ -492,8 +495,8 @@
         let mut bound_vars = FxIndexMap::default();
         debug!(?opaque.generics.params);
         for param in opaque.generics.params {
-            let (def_id, reg) = ResolvedArg::early(param);
-            bound_vars.insert(def_id, reg);
+            let arg = ResolvedArg::early(param);
+            bound_vars.insert(param.def_id, arg);
         }
 
         let hir_id = self.tcx.local_def_id_to_hir_id(opaque.def_id);
@@ -618,9 +621,10 @@
                     .iter()
                     .enumerate()
                     .map(|(late_bound_idx, param)| {
-                        let pair = ResolvedArg::late(late_bound_idx as u32, param);
-                        let r = late_arg_as_bound_arg(self.tcx, &pair.1, param);
-                        (pair, r)
+                        (
+                            (param.def_id, ResolvedArg::late(late_bound_idx as u32, param)),
+                            late_arg_as_bound_arg(self.tcx, param),
+                        )
                     })
                     .unzip();
 
@@ -870,9 +874,10 @@
                         .iter()
                         .enumerate()
                         .map(|(late_bound_idx, param)| {
-                            let pair = ResolvedArg::late(late_bound_idx as u32, param);
-                            let r = late_arg_as_bound_arg(self.tcx, &pair.1, param);
-                            (pair, r)
+                            (
+                                (param.def_id, ResolvedArg::late(late_bound_idx as u32, param)),
+                                late_arg_as_bound_arg(self.tcx, param),
+                            )
                         })
                         .unzip();
 
@@ -1052,19 +1057,21 @@
         let bound_vars: FxIndexMap<LocalDefId, ResolvedArg> = generics
             .params
             .iter()
-            .map(|param| match param.kind {
-                GenericParamKind::Lifetime { .. } => {
-                    if self.tcx.is_late_bound(param.hir_id) {
-                        let late_bound_idx = named_late_bound_vars;
-                        named_late_bound_vars += 1;
-                        ResolvedArg::late(late_bound_idx, param)
-                    } else {
+            .map(|param| {
+                (param.def_id, match param.kind {
+                    GenericParamKind::Lifetime { .. } => {
+                        if self.tcx.is_late_bound(param.hir_id) {
+                            let late_bound_idx = named_late_bound_vars;
+                            named_late_bound_vars += 1;
+                            ResolvedArg::late(late_bound_idx, param)
+                        } else {
+                            ResolvedArg::early(param)
+                        }
+                    }
+                    GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
                         ResolvedArg::early(param)
                     }
-                }
-                GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
-                    ResolvedArg::early(param)
-                }
+                })
             })
             .collect();
 
@@ -1075,11 +1082,7 @@
                 matches!(param.kind, GenericParamKind::Lifetime { .. })
                     && self.tcx.is_late_bound(param.hir_id)
             })
-            .enumerate()
-            .map(|(late_bound_idx, param)| {
-                let pair = ResolvedArg::late(late_bound_idx as u32, param);
-                late_arg_as_bound_arg(self.tcx, &pair.1, param)
-            })
+            .map(|param| late_arg_as_bound_arg(self.tcx, param))
             .collect();
         self.record_late_bound_vars(hir_id, binders);
         let scope = Scope::Binder {
@@ -1096,7 +1099,8 @@
     where
         F: for<'b, 'c> FnOnce(&'b mut BoundVarContext<'c, 'tcx>),
     {
-        let bound_vars = generics.params.iter().map(ResolvedArg::early).collect();
+        let bound_vars =
+            generics.params.iter().map(|param| (param.def_id, ResolvedArg::early(param))).collect();
         self.record_late_bound_vars(hir_id, vec![]);
         let scope = Scope::Binder {
             hir_id,
@@ -1161,7 +1165,7 @@
                         && let Some(param) = generics.params.iter().find(|p| p.def_id == param_id)
                         && param.is_elided_lifetime()
                         && !self.tcx.asyncness(lifetime_ref.hir_id.owner.def_id).is_async()
-                        && !self.tcx.features().anonymous_lifetime_in_impl_trait
+                        && !self.tcx.features().anonymous_lifetime_in_impl_trait()
                     {
                         let mut diag: rustc_errors::Diag<'_> = rustc_session::parse::feature_err(
                             &self.tcx.sess,
@@ -1639,17 +1643,13 @@
                         constraint.ident,
                         ty::AssocKind::Fn,
                     ) {
-                    bound_vars.extend(self.tcx.generics_of(assoc_fn.def_id).own_params.iter().map(
-                        |param| match param.kind {
-                            ty::GenericParamDefKind::Lifetime => ty::BoundVariableKind::Region(
-                                ty::BoundRegionKind::BrNamed(param.def_id, param.name),
-                            ),
-                            ty::GenericParamDefKind::Type { .. } => ty::BoundVariableKind::Ty(
-                                ty::BoundTyKind::Param(param.def_id, param.name),
-                            ),
-                            ty::GenericParamDefKind::Const { .. } => ty::BoundVariableKind::Const,
-                        },
-                    ));
+                    bound_vars.extend(
+                        self.tcx
+                            .generics_of(assoc_fn.def_id)
+                            .own_params
+                            .iter()
+                            .map(|param| generic_param_def_as_bound_arg(param)),
+                    );
                     bound_vars.extend(
                         self.tcx.fn_sig(assoc_fn.def_id).instantiate_identity().bound_vars(),
                     );
@@ -1968,17 +1968,13 @@
         // Append the early-bound vars on the function, and then the late-bound ones.
         // We actually turn type parameters into higher-ranked types here, but we
         // deny them later in HIR lowering.
-        bound_vars.extend(self.tcx.generics_of(item_def_id).own_params.iter().map(|param| {
-            match param.kind {
-                ty::GenericParamDefKind::Lifetime => ty::BoundVariableKind::Region(
-                    ty::BoundRegionKind::BrNamed(param.def_id, param.name),
-                ),
-                ty::GenericParamDefKind::Type { .. } => {
-                    ty::BoundVariableKind::Ty(ty::BoundTyKind::Param(param.def_id, param.name))
-                }
-                ty::GenericParamDefKind::Const { .. } => ty::BoundVariableKind::Const,
-            }
-        }));
+        bound_vars.extend(
+            self.tcx
+                .generics_of(item_def_id)
+                .own_params
+                .iter()
+                .map(|param| generic_param_def_as_bound_arg(param)),
+        );
         bound_vars.extend(self.tcx.fn_sig(item_def_id).instantiate_identity().bound_vars());
 
         // SUBTLE: Stash the old bound vars onto the *item segment* before appending
@@ -2239,7 +2235,7 @@
             format!("late-bound {what} parameter not allowed on {where_}"),
         );
 
-        let guar = diag.emit_unless(!tcx.features().non_lifetime_binders || !first);
+        let guar = diag.emit_unless(!tcx.features().non_lifetime_binders() || !first);
 
         first = false;
         *arg = ResolvedArg::Error(guar);
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs
index 470bcae..84161ec 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs
@@ -699,7 +699,7 @@
 }
 
 fn check_feature_inherent_assoc_ty(tcx: TyCtxt<'_>, span: Span) {
-    if !tcx.features().inherent_associated_types {
+    if !tcx.features().inherent_associated_types() {
         use rustc_session::parse::feature_err;
         use rustc_span::symbol::sym;
         feature_err(
@@ -714,7 +714,7 @@
 
 pub(crate) fn type_alias_is_lazy<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> bool {
     use hir::intravisit::Visitor;
-    if tcx.features().lazy_type_alias {
+    if tcx.features().lazy_type_alias() {
         return true;
     }
     struct HasTait;
diff --git a/compiler/rustc_hir_analysis/src/delegation.rs b/compiler/rustc_hir_analysis/src/delegation.rs
index 1ccb7fa..e65420e 100644
--- a/compiler/rustc_hir_analysis/src/delegation.rs
+++ b/compiler/rustc_hir_analysis/src/delegation.rs
@@ -186,7 +186,6 @@
             param_def_id_to_index,
             has_self,
             has_late_bound_regions: sig_generics.has_late_bound_regions,
-            host_effect_index: sig_generics.host_effect_index,
         }
     }
 }
@@ -279,8 +278,6 @@
         ty::GenericPredicates {
             parent: self.parent,
             predicates: self.tcx.arena.alloc_from_iter(preds),
-            // FIXME(fn_delegation): Support effects.
-            effects_min_tys: ty::List::empty(),
         }
     }
 }
@@ -472,10 +469,6 @@
         }));
     };
 
-    if tcx.has_host_param(sig_id) {
-        emit("delegation to a function with effect parameter is not supported yet");
-    }
-
     if let Some(local_sig_id) = sig_id.as_local()
         && tcx.hir().opt_delegation_sig_id(local_sig_id).is_some()
     {
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
index 4721a3a..a570908 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
@@ -45,23 +45,22 @@
                 let hir::GenericBound::Trait(ptr) = hir_bound else {
                     continue;
                 };
-                match ptr.modifiers {
-                    hir::TraitBoundModifier::Maybe => unbounds.push(ptr),
-                    hir::TraitBoundModifier::Negative => {
+                match ptr.modifiers.polarity {
+                    hir::BoundPolarity::Maybe(_) => unbounds.push(ptr),
+                    hir::BoundPolarity::Negative(_) => {
                         if let Some(sized_def_id) = sized_def_id
                             && ptr.trait_ref.path.res == Res::Def(DefKind::Trait, sized_def_id)
                         {
                             seen_negative_sized_bound = true;
                         }
                     }
-                    hir::TraitBoundModifier::None => {
+                    hir::BoundPolarity::Positive => {
                         if let Some(sized_def_id) = sized_def_id
                             && ptr.trait_ref.path.res == Res::Def(DefKind::Trait, sized_def_id)
                         {
                             seen_positive_sized_bound = true;
                         }
                     }
-                    _ => {}
                 }
             }
         };
@@ -89,7 +88,7 @@
             };
             if seen_repeat {
                 self.dcx().emit_err(err);
-            } else if !tcx.features().more_maybe_bounds {
+            } else if !tcx.features().more_maybe_bounds() {
                 self.tcx().sess.create_feature_err(err, sym::more_maybe_bounds).emit();
             };
         }
@@ -155,7 +154,6 @@
         for hir_bound in hir_bounds {
             // In order to avoid cycles, when we're lowering `SelfThatDefines`,
             // we skip over any traits that don't define the given associated type.
-
             if let PredicateFilter::SelfThatDefines(assoc_name) = predicate_filter {
                 if let Some(trait_ref) = hir_bound.trait_ref()
                     && let Some(trait_did) = trait_ref.trait_def_id()
@@ -169,20 +167,13 @@
 
             match hir_bound {
                 hir::GenericBound::Trait(poly_trait_ref) => {
-                    let (constness, polarity) = match poly_trait_ref.modifiers {
-                        hir::TraitBoundModifier::Const => {
-                            (Some(ty::BoundConstness::Const), ty::PredicatePolarity::Positive)
-                        }
-                        hir::TraitBoundModifier::MaybeConst => (
-                            Some(ty::BoundConstness::ConstIfConst),
-                            ty::PredicatePolarity::Positive,
-                        ),
-                        hir::TraitBoundModifier::None => (None, ty::PredicatePolarity::Positive),
-                        hir::TraitBoundModifier::Negative => {
-                            (None, ty::PredicatePolarity::Negative)
-                        }
-                        hir::TraitBoundModifier::Maybe => continue,
+                    let hir::TraitBoundModifiers { constness, polarity } = poly_trait_ref.modifiers;
+                    let polarity = match polarity {
+                        rustc_ast::BoundPolarity::Positive => ty::PredicatePolarity::Positive,
+                        rustc_ast::BoundPolarity::Negative(_) => ty::PredicatePolarity::Negative,
+                        rustc_ast::BoundPolarity::Maybe(_) => continue,
                     };
+
                     let _ = self.lower_poly_trait_ref(
                         &poly_trait_ref.trait_ref,
                         poly_trait_ref.span,
@@ -194,6 +185,14 @@
                     );
                 }
                 hir::GenericBound::Outlives(lifetime) => {
+                    // `ConstIfConst` is only interested in `~const` bounds.
+                    if matches!(
+                        predicate_filter,
+                        PredicateFilter::ConstIfConst | PredicateFilter::SelfConstIfConst
+                    ) {
+                        continue;
+                    }
+
                     let region = self.lower_lifetime(lifetime, RegionInferReason::OutlivesBound);
                     bounds.push_region_bound(
                         self.tcx(),
@@ -393,21 +392,31 @@
                     },
                 );
 
-                bounds.push_projection_bound(
-                    tcx,
-                    projection_term.map_bound(|projection_term| ty::ProjectionPredicate {
-                        projection_term,
-                        term,
-                    }),
-                    constraint.span,
-                );
+                match predicate_filter {
+                    PredicateFilter::All
+                    | PredicateFilter::SelfOnly
+                    | PredicateFilter::SelfThatDefines(_)
+                    | PredicateFilter::SelfAndAssociatedTypeBounds => {
+                        bounds.push_projection_bound(
+                            tcx,
+                            projection_term.map_bound(|projection_term| ty::ProjectionPredicate {
+                                projection_term,
+                                term,
+                            }),
+                            constraint.span,
+                        );
+                    }
+                    // `ConstIfConst` is only interested in `~const` bounds.
+                    PredicateFilter::ConstIfConst | PredicateFilter::SelfConstIfConst => {}
+                }
             }
             // Lower a constraint like `Item: Debug` as found in HIR bound `T: Iterator<Item: Debug>`
             // to a bound involving a projection: `<T as Iterator>::Item: Debug`.
             hir::AssocItemConstraintKind::Bound { bounds: hir_bounds } => {
                 match predicate_filter {
-                    PredicateFilter::SelfOnly | PredicateFilter::SelfThatDefines(_) => {}
-                    PredicateFilter::All | PredicateFilter::SelfAndAssociatedTypeBounds => {
+                    PredicateFilter::All
+                    | PredicateFilter::SelfAndAssociatedTypeBounds
+                    | PredicateFilter::ConstIfConst => {
                         let projection_ty = projection_term
                             .map_bound(|projection_term| projection_term.expect_ty(self.tcx()));
                         // Calling `skip_binder` is okay, because `lower_bounds` expects the `param_ty`
@@ -422,6 +431,9 @@
                             predicate_filter,
                         );
                     }
+                    PredicateFilter::SelfOnly
+                    | PredicateFilter::SelfThatDefines(_)
+                    | PredicateFilter::SelfConstIfConst => {}
                 }
             }
         }
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
index a1ee120..f2ee4b0 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
@@ -40,8 +40,7 @@
         let mut potential_assoc_types = Vec::new();
         let dummy_self = self.tcx().types.trait_object_dummy_self;
         for trait_bound in hir_trait_bounds.iter().rev() {
-            // FIXME: This doesn't handle `? const`.
-            if trait_bound.modifiers == hir::TraitBoundModifier::Maybe {
+            if let hir::BoundPolarity::Maybe(_) = trait_bound.modifiers.polarity {
                 continue;
             }
             if let GenericArgCountResult {
@@ -51,7 +50,7 @@
             } = self.lower_poly_trait_ref(
                 &trait_bound.trait_ref,
                 trait_bound.span,
-                None,
+                hir::BoundConstness::Never,
                 ty::PredicatePolarity::Positive,
                 dummy_self,
                 &mut bounds,
@@ -63,7 +62,7 @@
 
         let mut trait_bounds = vec![];
         let mut projection_bounds = vec![];
-        for (pred, span) in bounds.clauses(tcx) {
+        for (pred, span) in bounds.clauses() {
             let bound_pred = pred.kind();
             match bound_pred.skip_binder() {
                 ty::ClauseKind::Trait(trait_pred) => {
@@ -79,7 +78,8 @@
                 ty::ClauseKind::RegionOutlives(_)
                 | ty::ClauseKind::ConstArgHasType(..)
                 | ty::ClauseKind::WellFormed(_)
-                | ty::ClauseKind::ConstEvaluatable(_) => {
+                | ty::ClauseKind::ConstEvaluatable(_)
+                | ty::ClauseKind::HostEffect(..) => {
                     span_bug!(span, "did not expect {pred} clause in object bounds");
                 }
             }
@@ -259,7 +259,6 @@
                         }
                     })
                     .collect();
-                let args = tcx.mk_args(&args);
 
                 let span = i.bottom().1;
                 let empty_generic_args = hir_trait_bounds.iter().any(|hir_bound| {
@@ -292,7 +291,7 @@
                     .emit();
                 }
 
-                ty::ExistentialTraitRef { def_id: trait_ref.def_id, args }
+                ty::ExistentialTraitRef::new(tcx, trait_ref.def_id, args)
             })
         });
 
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
index 01768c8..dd0f250 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
@@ -63,7 +63,7 @@
         trait_segment: &'_ hir::PathSegment<'_>,
         is_impl: bool,
     ) {
-        if self.tcx().features().unboxed_closures {
+        if self.tcx().features().unboxed_closures() {
             return;
         }
 
@@ -343,7 +343,7 @@
             && let Some(hir_ty) = constraint.ty()
             && let ty = self.lower_ty(hir_ty)
             && (ty.is_enum() || ty.references_error())
-            && tcx.features().associated_const_equality
+            && tcx.features().associated_const_equality()
         {
             Some(errors::AssocKindMismatchWrapInBracesSugg {
                 lo: hir_ty.span.shrink_to_lo(),
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
index fe0cd57..0891642 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
@@ -81,6 +81,12 @@
     /// For example, given `Self: Tr<A: B>`, this would expand to `Self: Tr`
     /// and `<Self as Tr>::A: B`.
     SelfAndAssociatedTypeBounds,
+
+    /// Filter only the `~const` bounds, which are lowered into `HostEffect` clauses.
+    ConstIfConst,
+
+    /// Filter only the `~const` bounds which are *also* in the supertrait position.
+    SelfConstIfConst,
 }
 
 #[derive(Debug)]
@@ -652,7 +658,7 @@
         &self,
         trait_ref: &hir::TraitRef<'tcx>,
         span: Span,
-        constness: Option<ty::BoundConstness>,
+        constness: hir::BoundConstness,
         polarity: ty::PredicatePolarity,
         self_ty: Ty<'tcx>,
         bounds: &mut Bounds<'tcx>,
@@ -675,11 +681,11 @@
             Some(self_ty),
         );
 
-        if let Some(constness) = constness
+        if let hir::BoundConstness::Always(span) | hir::BoundConstness::Maybe(span) = constness
             && !self.tcx().is_const_trait(trait_def_id)
         {
             self.dcx().emit_err(crate::errors::ConstBoundForNonConstTrait {
-                span: trait_ref.path.span,
+                span,
                 modifier: constness.as_str(),
             });
         }
@@ -693,16 +699,49 @@
             bound_vars,
         );
 
-        debug!(?poly_trait_ref);
-        bounds.push_trait_bound(
-            tcx,
-            self.item_def_id().to_def_id(),
-            poly_trait_ref,
-            span,
-            polarity,
-            constness,
-            predicate_filter,
-        );
+        match predicate_filter {
+            PredicateFilter::All
+            | PredicateFilter::SelfOnly
+            | PredicateFilter::SelfThatDefines(..)
+            | PredicateFilter::SelfAndAssociatedTypeBounds => {
+                debug!(?poly_trait_ref);
+                bounds.push_trait_bound(tcx, poly_trait_ref, span, polarity);
+
+                match constness {
+                    hir::BoundConstness::Always(span) => {
+                        if polarity == ty::PredicatePolarity::Positive {
+                            bounds.push_const_bound(
+                                tcx,
+                                poly_trait_ref,
+                                ty::HostPolarity::Const,
+                                span,
+                            );
+                        }
+                    }
+                    hir::BoundConstness::Maybe(_) => {
+                        // We don't emit a const bound here, since that would mean that we
+                        // unconditionally need to prove a `HostEffect` predicate, even when
+                        // the predicates are being instantiated in a non-const context. This
+                        // is instead handled in the `const_conditions` query.
+                    }
+                    hir::BoundConstness::Never => {}
+                }
+            }
+            // On the flip side, when filtering `ConstIfConst` bounds, we only need to convert
+            // `~const` bounds. All other predicates are handled in their respective queries.
+            //
+            // Note that like `PredicateFilter::SelfOnly`, we don't need to do any filtering
+            // here because we only call this on self bounds, and deal with the recursive case
+            // in `lower_assoc_item_constraint`.
+            PredicateFilter::ConstIfConst | PredicateFilter::SelfConstIfConst => match constness {
+                hir::BoundConstness::Maybe(span) => {
+                    if polarity == ty::PredicatePolarity::Positive {
+                        bounds.push_const_bound(tcx, poly_trait_ref, ty::HostPolarity::Maybe, span);
+                    }
+                }
+                hir::BoundConstness::Always(_) | hir::BoundConstness::Never => {}
+            },
+        }
 
         let mut dup_constraints = FxIndexMap::default();
         for constraint in trait_segment.args().constraints {
@@ -1164,15 +1203,6 @@
                     err.emit()
                 } else if let Err(reported) = qself_ty.error_reported() {
                     reported
-                } else if let ty::Alias(ty::Opaque, alias_ty) = qself_ty.kind() {
-                    // `<impl Trait as OtherTrait>::Assoc` makes no sense.
-                    struct_span_code_err!(
-                        self.dcx(),
-                        tcx.def_span(alias_ty.def_id),
-                        E0667,
-                        "`impl Trait` is not allowed in path parameters"
-                    )
-                    .emit() // Already reported in an earlier stage.
                 } else {
                     self.maybe_report_similar_assoc_fn(span, qself_ty, qself)?;
 
@@ -1241,7 +1271,7 @@
         // selection during HIR ty lowering instead of in the trait solver), IATs can lead to cycle
         // errors (#108491) which mask the feature-gate error, needlessly confusing users
         // who use IATs by accident (#113265).
-        if !tcx.features().inherent_associated_types {
+        if !tcx.features().inherent_associated_types() {
             return Ok(None);
         }
 
diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check.rs b/compiler/rustc_hir_analysis/src/impl_wf_check.rs
index 7f18332..d9c70c3 100644
--- a/compiler/rustc_hir_analysis/src/impl_wf_check.rs
+++ b/compiler/rustc_hir_analysis/src/impl_wf_check.rs
@@ -57,7 +57,7 @@
     tcx: TyCtxt<'_>,
     impl_def_id: LocalDefId,
 ) -> Result<(), ErrorGuaranteed> {
-    let min_specialization = tcx.features().min_specialization;
+    let min_specialization = tcx.features().min_specialization();
     let mut res = Ok(());
     debug_assert_matches!(tcx.def_kind(impl_def_id), DefKind::Impl { .. });
     res = res.and(enforce_impl_params_are_constrained(tcx, impl_def_id));
diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
index 0355adf..a394fc2 100644
--- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
+++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
@@ -530,6 +530,7 @@
         | ty::ClauseKind::Projection(_)
         | ty::ClauseKind::ConstArgHasType(..)
         | ty::ClauseKind::WellFormed(_)
-        | ty::ClauseKind::ConstEvaluatable(..) => None,
+        | ty::ClauseKind::ConstEvaluatable(..)
+        | ty::ClauseKind::HostEffect(..) => None,
     }
 }
diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs
index 71ee77f..3ad3516 100644
--- a/compiler/rustc_hir_analysis/src/lib.rs
+++ b/compiler/rustc_hir_analysis/src/lib.rs
@@ -116,7 +116,7 @@
         return;
     }
 
-    let extended_abi_support = tcx.features().extended_varargs_abi_support;
+    let extended_abi_support = tcx.features().extended_varargs_abi_support();
     let conventions = match (extended_abi_support, abi.supports_varargs()) {
         // User enabled additional ABI support for varargs and function ABI matches those ones.
         (true, true) => return,
@@ -155,7 +155,7 @@
 
     // FIXME(effects): remove once effects is implemented in old trait solver
     // or if the next solver is stabilized.
-    if tcx.features().effects && !tcx.next_trait_solver_globally() {
+    if tcx.features().effects() && !tcx.next_trait_solver_globally() {
         tcx.dcx().emit_err(errors::EffectsWithoutNextSolver);
     }
 
@@ -172,7 +172,7 @@
         let _ = tcx.ensure().crate_inherent_impls_overlap_check(());
     });
 
-    if tcx.features().rustc_attrs {
+    if tcx.features().rustc_attrs() {
         tcx.sess.time("outlives_dumping", || outlives::dump::inferred_outlives(tcx));
         tcx.sess.time("variance_dumping", || variance::dump::variances(tcx));
         collect::dump::opaque_hidden_types(tcx);
diff --git a/compiler/rustc_hir_analysis/src/outlives/explicit.rs b/compiler/rustc_hir_analysis/src/outlives/explicit.rs
index f576499..2c1d443 100644
--- a/compiler/rustc_hir_analysis/src/outlives/explicit.rs
+++ b/compiler/rustc_hir_analysis/src/outlives/explicit.rs
@@ -53,7 +53,8 @@
                     | ty::ClauseKind::Projection(_)
                     | ty::ClauseKind::ConstArgHasType(_, _)
                     | ty::ClauseKind::WellFormed(_)
-                    | ty::ClauseKind::ConstEvaluatable(_) => {}
+                    | ty::ClauseKind::ConstEvaluatable(_)
+                    | ty::ClauseKind::HostEffect(..) => {}
                 }
             }
 
diff --git a/compiler/rustc_hir_analysis/src/outlives/mod.rs b/compiler/rustc_hir_analysis/src/outlives/mod.rs
index e3cdb1b..c439176 100644
--- a/compiler/rustc_hir_analysis/src/outlives/mod.rs
+++ b/compiler/rustc_hir_analysis/src/outlives/mod.rs
@@ -23,7 +23,7 @@
             let crate_map = tcx.inferred_outlives_crate(());
             crate_map.predicates.get(&item_def_id.to_def_id()).copied().unwrap_or(&[])
         }
-        DefKind::AnonConst if tcx.features().generic_const_exprs => {
+        DefKind::AnonConst if tcx.features().generic_const_exprs() => {
             let id = tcx.local_def_id_to_hir_id(item_def_id);
             if tcx.hir().opt_const_param_default_param_def_id(id).is_some() {
                 // In `generics_of` we set the generics' parent to be our parent's parent which means that
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 9ebfd4f..61214b9 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -16,7 +16,6 @@
 use rustc_hir::{
     BindingMode, ByRef, ConstArgKind, GenericArg, GenericBound, GenericParam, GenericParamKind,
     HirId, LifetimeParamKind, Node, PatKind, PreciseCapturingArg, RangeEnd, Term,
-    TraitBoundModifier,
 };
 use rustc_span::FileName;
 use rustc_span::source_map::SourceMap;
@@ -676,9 +675,16 @@
     }
 
     fn print_poly_trait_ref(&mut self, t: &hir::PolyTraitRef<'_>) {
-        // FIXME: This isn't correct!
-        if t.modifiers == TraitBoundModifier::Maybe {
-            self.word("?");
+        let hir::TraitBoundModifiers { constness, polarity } = t.modifiers;
+        match constness {
+            hir::BoundConstness::Never => {}
+            hir::BoundConstness::Always(_) => self.word("const"),
+            hir::BoundConstness::Maybe(_) => self.word("~const"),
+        }
+        match polarity {
+            hir::BoundPolarity::Positive => {}
+            hir::BoundPolarity::Negative(_) => self.word("!"),
+            hir::BoundPolarity::Maybe(_) => self.word("?"),
         }
         self.print_formal_generic_params(t.bound_generic_params);
         self.print_trait_ref(&t.trait_ref);
@@ -2128,7 +2134,7 @@
                     self.print_type(default);
                 }
             }
-            GenericParamKind::Const { ty, ref default, is_host_effect: _, synthetic: _ } => {
+            GenericParamKind::Const { ty, ref default, synthetic: _ } => {
                 self.word_space(":");
                 self.print_type(ty);
                 if let Some(default) = default {
diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs
index e68caa3..3372cae 100644
--- a/compiler/rustc_hir_typeck/src/_match.rs
+++ b/compiler/rustc_hir_typeck/src/_match.rs
@@ -94,14 +94,11 @@
                 (None, arm.body.span)
             };
 
-            let (span, code) = match prior_arm {
+            let code = match prior_arm {
                 // The reason for the first arm to fail is not that the match arms diverge,
                 // but rather that there's a prior obligation that doesn't hold.
-                None => {
-                    (arm_span, ObligationCauseCode::BlockTailExpression(arm.body.hir_id, match_src))
-                }
-                Some((prior_arm_block_id, prior_arm_ty, prior_arm_span)) => (
-                    expr.span,
+                None => ObligationCauseCode::BlockTailExpression(arm.body.hir_id, match_src),
+                Some((prior_arm_block_id, prior_arm_ty, prior_arm_span)) => {
                     ObligationCauseCode::MatchExpressionArm(Box::new(MatchExpressionArmCause {
                         arm_block_id,
                         arm_span,
@@ -110,13 +107,14 @@
                         prior_arm_ty,
                         prior_arm_span,
                         scrut_span: scrut.span,
+                        expr_span: expr.span,
                         source: match_src,
                         prior_non_diverging_arms: prior_non_diverging_arms.clone(),
                         tail_defines_return_position_impl_trait,
-                    })),
-                ),
+                    }))
+                }
             };
-            let cause = self.cause(span, code);
+            let cause = self.cause(arm_span, code);
 
             // This is the moral equivalent of `coercion.coerce(self, cause, arm.body, arm_ty)`.
             // We use it this way to be able to expand on the potential error and detect when a
diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs
index fa6a86c..ed56bb9 100644
--- a/compiler/rustc_hir_typeck/src/callee.rs
+++ b/compiler/rustc_hir_typeck/src/callee.rs
@@ -20,7 +20,7 @@
 use rustc_trait_selection::error_reporting::traits::DefIdOrName;
 use rustc_trait_selection::infer::InferCtxtExt as _;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
-use tracing::{debug, instrument, trace};
+use tracing::{debug, instrument};
 
 use super::method::MethodCallee;
 use super::method::probe::ProbeScope;
@@ -537,7 +537,7 @@
                 //
                 // This check is here because there is currently no way to express a trait bound for `FnDef` types only.
                 if let ty::FnDef(def_id, _args) = *arg_ty.kind() {
-                    if idx == 0 && !self.tcx.is_const_fn_raw(def_id) {
+                    if idx == 0 && !self.tcx.is_const_fn(def_id) {
                         self.dcx().emit_err(errors::ConstSelectMustBeConst { span });
                     }
                 } else {
@@ -843,27 +843,38 @@
         callee_did: DefId,
         callee_args: GenericArgsRef<'tcx>,
     ) {
-        let tcx = self.tcx;
+        // FIXME(effects): We should be enforcing these effects unconditionally.
+        // This can be done as soon as we convert the standard library back to
+        // using const traits, since if we were to enforce these conditions now,
+        // we'd fail on basically every builtin trait call (i.e. `1 + 2`).
+        if !self.tcx.features().effects() {
+            return;
+        }
 
-        // fast-reject if callee doesn't have the host effect param (non-const)
-        let generics = tcx.generics_of(callee_did);
-        let Some(host_effect_index) = generics.host_effect_index else { return };
-
-        let effect = tcx.expected_host_effect_param_for_body(self.body_id);
-
-        trace!(?effect, ?generics, ?callee_args);
-
-        let param = callee_args.const_at(host_effect_index);
-        let cause = self.misc(span);
-        // We know the type of `effect` to be `bool`, there will be no opaque type inference.
-        match self.at(&cause, self.param_env).eq(infer::DefineOpaqueTypes::Yes, effect, param) {
-            Ok(infer::InferOk { obligations, value: () }) => {
-                self.register_predicates(obligations);
+        let host = match self.tcx.hir().body_const_context(self.body_id) {
+            Some(hir::ConstContext::Const { .. } | hir::ConstContext::Static(_)) => {
+                ty::HostPolarity::Const
             }
-            Err(e) => {
-                // FIXME(effects): better diagnostic
-                self.err_ctxt().report_mismatched_consts(&cause, effect, param, e).emit();
+            Some(hir::ConstContext::ConstFn) => ty::HostPolarity::Maybe,
+            None => return,
+        };
+
+        // FIXME(effects): Should this be `is_const_fn_raw`? It depends on if we move
+        // const stability checking here too, I guess.
+        if self.tcx.is_conditionally_const(callee_did) {
+            let q = self.tcx.const_conditions(callee_did);
+            // FIXME(effects): Use this span with a better cause code.
+            for (cond, _) in q.instantiate(self.tcx, callee_args) {
+                self.register_predicate(Obligation::new(
+                    self.tcx,
+                    self.misc(span),
+                    self.param_env,
+                    cond.to_host_effect_clause(self.tcx, host),
+                ));
             }
+        } else {
+            // FIXME(effects): This should eventually be caught here.
+            // For now, though, we defer some const checking to MIR.
         }
     }
 
diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs
index 8fa6ab8..483a8d1 100644
--- a/compiler/rustc_hir_typeck/src/cast.rs
+++ b/compiler/rustc_hir_typeck/src/cast.rs
@@ -721,7 +721,7 @@
         use rustc_middle::ty::cast::IntTy::*;
 
         if self.cast_ty.is_dyn_star() {
-            if fcx.tcx.features().dyn_star {
+            if fcx.tcx.features().dyn_star() {
                 span_bug!(self.span, "should be handled by `coerce`");
             } else {
                 // Report "casting is invalid" rather than "non-primitive cast"
@@ -876,20 +876,14 @@
                     // A<dyn Src<...> + SrcAuto> -> B<dyn Dst<...> + DstAuto>. need to make sure
                     // - `Src` and `Dst` traits are the same
                     // - traits have the same generic arguments
-                    // - `SrcAuto` is a superset of `DstAuto`
-                    (Some(src_principal), Some(dst_principal)) => {
+                    // - projections are the same
+                    // - `SrcAuto` (+auto traits implied by `Src`) is a superset of `DstAuto`
+                    //
+                    // Note that trait upcasting goes through a different mechanism (`coerce_unsized`)
+                    // and is unaffected by this check.
+                    (Some(src_principal), Some(_)) => {
                         let tcx = fcx.tcx;
 
-                        // Check that the traits are actually the same.
-                        // The `dyn Src = dyn Dst` check below would suffice,
-                        // but this may produce a better diagnostic.
-                        //
-                        // Note that trait upcasting goes through a different mechanism (`coerce_unsized`)
-                        // and is unaffected by this check.
-                        if src_principal.def_id() != dst_principal.def_id() {
-                            return Err(CastError::DifferingKinds { src_kind, dst_kind });
-                        }
-
                         // We need to reconstruct trait object types.
                         // `m_src` and `m_dst` won't work for us here because they will potentially
                         // contain wrappers, which we do not care about.
@@ -912,8 +906,8 @@
                             ty::Dyn,
                         ));
 
-                        // `dyn Src = dyn Dst`, this checks for matching traits/generics
-                        // This is `demand_eqtype`, but inlined to give a better error.
+                        // `dyn Src = dyn Dst`, this checks for matching traits/generics/projections
+                        // This is `fcx.demand_eqtype`, but inlined to give a better error.
                         let cause = fcx.misc(self.span);
                         if fcx
                             .at(&cause, fcx.param_env)
@@ -965,8 +959,35 @@
                     // dyn Auto -> dyn Auto'? ok.
                     (None, None) => Ok(CastKind::PtrPtrCast),
 
-                    // dyn Trait -> dyn Auto? should be ok, but we used to not allow it.
-                    // FIXME: allow this
+                    // dyn Trait -> dyn Auto? not ok (for now).
+                    //
+                    // Although dropping the principal is already allowed for unsizing coercions
+                    // (e.g. `*const (dyn Trait + Auto)` to `*const dyn Auto`), dropping it is
+                    // currently **NOT** allowed for (non-coercion) ptr-to-ptr casts (e.g
+                    // `*const Foo` to `*const Bar` where `Foo` has a `dyn Trait + Auto` tail
+                    // and `Bar` has a `dyn Auto` tail), because the underlying MIR operations
+                    // currently work very differently:
+                    //
+                    // * A MIR unsizing coercion on raw pointers to trait objects (`*const dyn Src`
+                    //   to `*const dyn Dst`) is currently equivalent to downcasting the source to
+                    //   the concrete sized type that it was originally unsized from first (via a
+                    //   ptr-to-ptr cast from `*const Src` to `*const T` with `T: Sized`) and then
+                    //   unsizing this thin pointer to the target type (unsizing `*const T` to
+                    //   `*const Dst`). In particular, this means that the pointer's metadata
+                    //   (vtable) will semantically change, e.g. for const eval and miri, even
+                    //   though the vtables will always be merged for codegen.
+                    //
+                    // * A MIR ptr-to-ptr cast is currently equivalent to a transmute and does not
+                    //   change the pointer metadata (vtable) at all.
+                    //
+                    // In addition to this potentially surprising difference between coercion and
+                    // non-coercion casts, casting away the principal with a MIR ptr-to-ptr cast
+                    // is currently considered undefined behavior:
+                    //
+                    // As a validity invariant of pointers to trait objects, we currently require
+                    // that the principal of the vtable in the pointer metadata exactly matches
+                    // the principal of the pointee type, where "no principal" is also considered
+                    // a kind of principal.
                     (Some(_), None) => Err(CastError::DifferingKinds { src_kind, dst_kind }),
 
                     // dyn Auto -> dyn Trait? not ok.
diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs
index 406d668..6fa958d 100644
--- a/compiler/rustc_hir_typeck/src/coercion.rs
+++ b/compiler/rustc_hir_typeck/src/coercion.rs
@@ -223,11 +223,11 @@
             ty::Ref(r_b, _, mutbl_b) => {
                 return self.coerce_borrowed_pointer(a, b, r_b, mutbl_b);
             }
-            ty::Dynamic(predicates, region, ty::DynStar) if self.tcx.features().dyn_star => {
+            ty::Dynamic(predicates, region, ty::DynStar) if self.tcx.features().dyn_star() => {
                 return self.coerce_dyn_star(a, b, predicates, region);
             }
             ty::Adt(pin, _)
-                if self.tcx.features().pin_ergonomics
+                if self.tcx.features().pin_ergonomics()
                     && self.tcx.is_lang_item(pin.did(), hir::LangItem::Pin) =>
             {
                 return self.coerce_pin(a, b);
@@ -698,7 +698,7 @@
         }
 
         if let Some((sub, sup)) = has_trait_upcasting_coercion
-            && !self.tcx().features().trait_upcasting
+            && !self.tcx().features().trait_upcasting()
         {
             // Renders better when we erase regions, since they're not really the point here.
             let (sub, sup) = self.tcx.erase_regions((sub, sup));
@@ -712,7 +712,7 @@
             err.emit();
         }
 
-        if has_unsized_tuple_coercion && !self.tcx.features().unsized_tuple_coercion {
+        if has_unsized_tuple_coercion && !self.tcx.features().unsized_tuple_coercion() {
             feature_err(
                 &self.tcx.sess,
                 sym::unsized_tuple_coercion,
@@ -732,7 +732,7 @@
         predicates: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
         b_region: ty::Region<'tcx>,
     ) -> CoerceResult<'tcx> {
-        if !self.tcx.features().dyn_star {
+        if !self.tcx.features().dyn_star() {
             return Err(TypeError::Mismatch);
         }
 
@@ -1695,7 +1695,7 @@
                             blk_id,
                             expression,
                         );
-                        if !fcx.tcx.features().unsized_locals {
+                        if !fcx.tcx.features().unsized_locals() {
                             unsized_return = self.is_return_ty_definitely_unsized(fcx);
                         }
                     }
@@ -1709,7 +1709,7 @@
                             return_expr_id,
                             expression,
                         );
-                        if !fcx.tcx.features().unsized_locals {
+                        if !fcx.tcx.features().unsized_locals() {
                             unsized_return = self.is_return_ty_definitely_unsized(fcx);
                         }
                     }
@@ -1723,6 +1723,7 @@
                     }) => {
                         err = fcx.err_ctxt().report_mismatched_types(
                             cause,
+                            fcx.param_env,
                             expected,
                             found,
                             coercion_error,
@@ -1752,6 +1753,7 @@
                     }) => {
                         err = fcx.err_ctxt().report_mismatched_types(
                             cause,
+                            fcx.param_env,
                             expected,
                             found,
                             coercion_error,
@@ -1787,6 +1789,7 @@
                     _ => {
                         err = fcx.err_ctxt().report_mismatched_types(
                             cause,
+                            fcx.param_env,
                             expected,
                             found,
                             coercion_error,
@@ -1897,7 +1900,8 @@
         block_or_return_id: hir::HirId,
         expression: Option<&'tcx hir::Expr<'tcx>>,
     ) -> Diag<'infcx> {
-        let mut err = fcx.err_ctxt().report_mismatched_types(cause, expected, found, ty_err);
+        let mut err =
+            fcx.err_ctxt().report_mismatched_types(cause, fcx.param_env, expected, found, ty_err);
 
         let due_to_block = matches!(fcx.tcx.hir_node(block_or_return_id), hir::Node::Block(..));
 
diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs
index 777248f..3399a9f 100644
--- a/compiler/rustc_hir_typeck/src/demand.rs
+++ b/compiler/rustc_hir_typeck/src/demand.rs
@@ -191,7 +191,9 @@
         self.at(cause, self.param_env)
             .sup(DefineOpaqueTypes::Yes, expected, actual)
             .map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
-            .map_err(|e| self.err_ctxt().report_mismatched_types(cause, expected, actual, e))
+            .map_err(|e| {
+                self.err_ctxt().report_mismatched_types(cause, self.param_env, expected, actual, e)
+            })
     }
 
     pub(crate) fn demand_eqtype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) {
@@ -218,7 +220,9 @@
         self.at(cause, self.param_env)
             .eq(DefineOpaqueTypes::Yes, expected, actual)
             .map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
-            .map_err(|e| self.err_ctxt().report_mismatched_types(cause, expected, actual, e))
+            .map_err(|e| {
+                self.err_ctxt().report_mismatched_types(cause, self.param_env, expected, actual, e)
+            })
     }
 
     pub(crate) fn demand_coerce(
@@ -271,7 +275,8 @@
         let expr = expr.peel_drop_temps();
         let cause = self.misc(expr.span);
         let expr_ty = self.resolve_vars_if_possible(checked_ty);
-        let mut err = self.err_ctxt().report_mismatched_types(&cause, expected, expr_ty, e);
+        let mut err =
+            self.err_ctxt().report_mismatched_types(&cause, self.param_env, expected, expr_ty, e);
 
         self.emit_coerce_suggestions(&mut err, expr, expr_ty, expected, expected_ty_expr, Some(e));
 
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index f4d7b59..d6e5fab 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -10,7 +10,8 @@
 use rustc_data_structures::unord::UnordMap;
 use rustc_errors::codes::*;
 use rustc_errors::{
-    Applicability, Diag, ErrorGuaranteed, StashKey, Subdiagnostic, pluralize, struct_span_code_err,
+    Applicability, Diag, ErrorGuaranteed, MultiSpan, StashKey, Subdiagnostic, pluralize,
+    struct_span_code_err,
 };
 use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::def_id::DefId;
@@ -734,7 +735,7 @@
                 // be known if explicitly specified via turbofish).
                 self.deferred_transmute_checks.borrow_mut().push((*from, to, expr.hir_id));
             }
-            if !tcx.features().unsized_fn_params {
+            if !tcx.features().unsized_fn_params() {
                 // We want to remove some Sized bounds from std functions,
                 // but don't want to expose the removal to stable Rust.
                 // i.e., we don't want to allow
@@ -1750,7 +1751,7 @@
         // to tell them that in the diagnostic. Does not affect typeck.
         let is_constable = match element.kind {
             hir::ExprKind::Call(func, _args) => match *self.node_ty(func.hir_id).kind() {
-                ty::FnDef(def_id, _) if tcx.is_const_fn(def_id) => traits::IsConstable::Fn,
+                ty::FnDef(def_id, _) if tcx.is_stable_const_fn(def_id) => traits::IsConstable::Fn,
                 _ => traits::IsConstable::No,
             },
             hir::ExprKind::Path(qpath) => {
@@ -1995,7 +1996,7 @@
         if let Some(base_expr) = base_expr {
             // FIXME: We are currently creating two branches here in order to maintain
             // consistency. But they should be merged as much as possible.
-            let fru_tys = if self.tcx.features().type_changing_struct_update {
+            let fru_tys = if self.tcx.features().type_changing_struct_update() {
                 if adt.is_struct() {
                     // Make some fresh generic parameters for our ADT type.
                     let fresh_args = self.fresh_args_for_item(base_expr.span, adt.did());
@@ -2026,7 +2027,7 @@
                                     }
                                     Err(_) => {
                                         span_bug!(
-                                            cause.span(),
+                                            cause.span,
                                             "subtyping remaining fields of type changing FRU failed: {target_ty} != {fru_ty}: {}::{}",
                                             variant.name,
                                             ident.name,
@@ -2763,12 +2764,25 @@
             field_ident.span,
             "field not available in `impl Future`, but it is available in its `Output`",
         );
-        err.span_suggestion_verbose(
-            base.span.shrink_to_hi(),
-            "consider `await`ing on the `Future` and access the field of its `Output`",
-            ".await",
-            Applicability::MaybeIncorrect,
-        );
+        match self.tcx.coroutine_kind(self.body_id) {
+            Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)) => {
+                err.span_suggestion_verbose(
+                    base.span.shrink_to_hi(),
+                    "consider `await`ing on the `Future` to access the field",
+                    ".await",
+                    Applicability::MaybeIncorrect,
+                );
+            }
+            _ => {
+                let mut span: MultiSpan = base.span.into();
+                span.push_span_label(self.tcx.def_span(self.body_id), "this is not `async`");
+                err.span_note(
+                    span,
+                    "this implements `Future` and its output type has the field, \
+                    but the future cannot be awaited in a synchronous function",
+                );
+            }
+        }
     }
 
     fn ban_nonexisting_field(
@@ -3538,7 +3552,7 @@
                     let (ident, _def_scope) =
                         self.tcx.adjust_ident_and_get_scope(field, container_def.did(), block);
 
-                    if !self.tcx.features().offset_of_enum {
+                    if !self.tcx.features().offset_of_enum() {
                         rustc_session::parse::feature_err(
                             &self.tcx.sess,
                             sym::offset_of_enum,
@@ -3628,7 +3642,7 @@
                     {
                         let field_ty = self.field_ty(expr.span, field, args);
 
-                        if self.tcx.features().offset_of_slice {
+                        if self.tcx.features().offset_of_slice() {
                             self.require_type_has_static_alignment(
                                 field_ty,
                                 expr.span,
@@ -3661,7 +3675,7 @@
                         && field.name == sym::integer(index)
                     {
                         if let Some(&field_ty) = tys.get(index) {
-                            if self.tcx.features().offset_of_slice {
+                            if self.tcx.features().offset_of_slice() {
                                 self.require_type_has_static_alignment(
                                     field_ty,
                                     expr.span,
diff --git a/compiler/rustc_hir_typeck/src/fallback.rs b/compiler/rustc_hir_typeck/src/fallback.rs
index 4fd508a..68776c5 100644
--- a/compiler/rustc_hir_typeck/src/fallback.rs
+++ b/compiler/rustc_hir_typeck/src/fallback.rs
@@ -7,8 +7,6 @@
 use rustc_hir as hir;
 use rustc_hir::HirId;
 use rustc_hir::intravisit::Visitor;
-use rustc_infer::infer::{DefineOpaqueTypes, InferOk};
-use rustc_middle::bug;
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable};
 use rustc_session::lint;
 use rustc_span::def_id::LocalDefId;
@@ -48,7 +46,7 @@
             self.fulfillment_cx.borrow_mut().pending_obligations()
         );
 
-        let fallback_occurred = self.fallback_types() | self.fallback_effects();
+        let fallback_occurred = self.fallback_types();
 
         if !fallback_occurred {
             return;
@@ -103,31 +101,6 @@
         fallback_occurred
     }
 
-    fn fallback_effects(&self) -> bool {
-        let unsolved_effects = self.unsolved_effects();
-
-        if unsolved_effects.is_empty() {
-            return false;
-        }
-
-        // not setting the `fallback_has_occurred` field here because
-        // that field is only used for type fallback diagnostics.
-        for effect in unsolved_effects {
-            let expected = self.tcx.consts.true_;
-            let cause = self.misc(DUMMY_SP);
-            match self.at(&cause, self.param_env).eq(DefineOpaqueTypes::Yes, expected, effect) {
-                Ok(InferOk { obligations, value: () }) => {
-                    self.register_predicates(obligations);
-                }
-                Err(e) => {
-                    bug!("cannot eq unsolved effect: {e:?}")
-                }
-            }
-        }
-
-        true
-    }
-
     // Tries to apply a fallback to `ty` if it is an unsolved variable.
     //
     // - Unconstrained ints are replaced with `i32`.
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index 2bc84d1..0fc566c 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -1262,15 +1262,8 @@
                     (GenericParamDefKind::Type { .. }, GenericArg::Infer(inf)) => {
                         self.fcx.ty_infer(Some(param), inf.span).into()
                     }
-                    (
-                        &GenericParamDefKind::Const { has_default, is_host_effect, .. },
-                        GenericArg::Infer(inf),
-                    ) => {
-                        if has_default && is_host_effect {
-                            self.fcx.var_for_effect(param)
-                        } else {
-                            self.fcx.ct_infer(Some(param), inf.span).into()
-                        }
+                    (&GenericParamDefKind::Const { .. }, GenericArg::Infer(inf)) => {
+                        self.fcx.ct_infer(Some(param), inf.span).into()
                     }
                     _ => unreachable!(),
                 }
@@ -1305,20 +1298,9 @@
                             self.fcx.var_for_def(self.span, param)
                         }
                     }
-                    GenericParamDefKind::Const { has_default, is_host_effect, .. } => {
+                    GenericParamDefKind::Const { has_default, .. } => {
                         if has_default {
-                            // N.B. this is a bit of a hack. `infer_args` is passed depending on
-                            // whether the user has provided generic args. E.g. for `Vec::new`
-                            // we would have to infer the generic types. However, for `Vec::<T>::new`
-                            // where the allocator param `A` has a default we will *not* infer. But
-                            // for effect params this is a different story: if the user has not written
-                            // anything explicit for the effect param, we always need to try to infer
-                            // it before falling back to default, such that a `const fn` such as
-                            // `needs_drop::<()>` can still be called in const contexts. (if we defaulted
-                            // instead of inferred, typeck would error)
-                            if is_host_effect {
-                                return self.fcx.var_for_effect(param);
-                            } else if !infer_args {
+                            if !infer_args {
                                 return tcx
                                     .const_param_default(param.def_id)
                                     .instantiate(tcx, preceding_args)
@@ -1486,7 +1468,7 @@
                     return ty::Const::new_error(self.tcx, guar);
                 }
             }
-        } else if self.tcx.features().generic_const_exprs {
+        } else if self.tcx.features().generic_const_exprs() {
             ct.normalize_internal(self.tcx, self.param_env)
         } else {
             ct
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index f29d619..a6c249d 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -827,6 +827,7 @@
                                 formal_and_expected_inputs[mismatch_idx.into()],
                                 provided_arg_tys[mismatch_idx.into()].0,
                             ),
+                            self.param_env,
                             terr,
                         );
                         err.span_label(
@@ -912,7 +913,8 @@
             let trace =
                 mk_trace(provided_span, formal_and_expected_inputs[*expected_idx], provided_ty);
             if !matches!(trace.cause.as_failure_code(*e), FailureCode::Error0308) {
-                let mut err = self.err_ctxt().report_and_explain_type_error(trace, *e);
+                let mut err =
+                    self.err_ctxt().report_and_explain_type_error(trace, self.param_env, *e);
                 suggest_confusable(&mut err);
                 reported = Some(err.emit());
                 return false;
@@ -940,7 +942,8 @@
             let (formal_ty, expected_ty) = formal_and_expected_inputs[*expected_idx];
             let (provided_ty, provided_arg_span) = provided_arg_tys[*provided_idx];
             let trace = mk_trace(provided_arg_span, (formal_ty, expected_ty), provided_ty);
-            let mut err = self.err_ctxt().report_and_explain_type_error(trace, *err);
+            let mut err =
+                self.err_ctxt().report_and_explain_type_error(trace, self.param_env, *err);
             self.emit_coerce_suggestions(
                 &mut err,
                 provided_args[*provided_idx],
@@ -1113,7 +1116,7 @@
                                 &mut err,
                                 &trace.cause,
                                 None,
-                                Some(trace.values),
+                                Some(self.param_env.and(trace.values)),
                                 e,
                                 true,
                             );
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs
index 693cb44..eb5fe3a 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs
@@ -52,6 +52,7 @@
             | ty::PredicateKind::AliasRelate(..)
             | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..))
             | ty::PredicateKind::ConstEquate(..)
+            | ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(..))
             | ty::PredicateKind::Ambiguous => false,
         }
     }
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
index e60bd1a..3940d13 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
@@ -247,12 +247,6 @@
     fn ct_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Const<'tcx> {
         // FIXME ideally this shouldn't use unwrap
         match param {
-            Some(
-                param @ ty::GenericParamDef {
-                    kind: ty::GenericParamDefKind::Const { is_host_effect: true, .. },
-                    ..
-                },
-            ) => self.var_for_effect(param).as_const().unwrap(),
             Some(param) => self.var_for_def(span, param).as_const().unwrap(),
             None => self.next_const_var(span),
         }
@@ -404,7 +398,7 @@
     }
 
     // `feature(never_type_fallback)`: fallback to `!` or `()` trying to not break stuff
-    if tcx.features().never_type_fallback {
+    if tcx.features().never_type_fallback() {
         return DivergingFallbackBehavior::ContextDependent;
     }
 
diff --git a/compiler/rustc_hir_typeck/src/gather_locals.rs b/compiler/rustc_hir_typeck/src/gather_locals.rs
index 5ae8d22..f427b0b 100644
--- a/compiler/rustc_hir_typeck/src/gather_locals.rs
+++ b/compiler/rustc_hir_typeck/src/gather_locals.rs
@@ -141,7 +141,7 @@
             let var_ty = self.assign(p.span, p.hir_id, None);
 
             if let Some((ty_span, hir_id)) = self.outermost_fn_param_pat {
-                if !self.fcx.tcx.features().unsized_fn_params {
+                if !self.fcx.tcx.features().unsized_fn_params() {
                     self.fcx.require_type_is_sized(
                         var_ty,
                         ty_span,
@@ -158,7 +158,7 @@
                         ),
                     );
                 }
-            } else if !self.fcx.tcx.features().unsized_locals {
+            } else if !self.fcx.tcx.features().unsized_locals() {
                 self.fcx.require_type_is_sized(
                     var_ty,
                     p.span,
diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs
index 85ee0a5..85e11ff 100644
--- a/compiler/rustc_hir_typeck/src/lib.rs
+++ b/compiler/rustc_hir_typeck/src/lib.rs
@@ -161,7 +161,7 @@
         let fn_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), fn_sig);
         let fn_sig = fcx.normalize(body.value.span, fn_sig);
 
-        check_fn(&mut fcx, fn_sig, None, decl, def_id, body, tcx.features().unsized_fn_params);
+        check_fn(&mut fcx, fn_sig, None, decl, def_id, body, tcx.features().unsized_fn_params());
     } else {
         let expected_type = infer_type_if_missing(&fcx, node);
         let expected_type = expected_type.unwrap_or_else(fallback);
diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs
index 1d7b343..f2b55d3 100644
--- a/compiler/rustc_hir_typeck/src/method/confirm.rs
+++ b/compiler/rustc_hir_typeck/src/method/confirm.rs
@@ -536,15 +536,21 @@
                 // FIXME(arbitrary_self_types): We probably should limit the
                 // situations where this can occur by adding additional restrictions
                 // to the feature, like the self type can't reference method args.
-                if self.tcx.features().arbitrary_self_types {
+                if self.tcx.features().arbitrary_self_types() {
                     self.err_ctxt()
-                        .report_mismatched_types(&cause, method_self_ty, self_ty, terr)
+                        .report_mismatched_types(
+                            &cause,
+                            self.param_env,
+                            method_self_ty,
+                            self_ty,
+                            terr,
+                        )
                         .emit();
                 } else {
                     // This has/will have errored in wfcheck, which we cannot depend on from here, as typeck on functions
                     // may run before wfcheck if the function is used in const eval.
                     self.dcx().span_delayed_bug(
-                        cause.span(),
+                        cause.span,
                         format!("{self_ty} was a subtype of {method_self_ty} but now is not?"),
                     );
                 }
diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs
index 69b9be0..e20a0cb 100644
--- a/compiler/rustc_hir_typeck/src/method/mod.rs
+++ b/compiler/rustc_hir_typeck/src/method/mod.rs
@@ -369,17 +369,6 @@
     ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
         let (obligation, args) =
             self.obligation_for_method(cause, trait_def_id, self_ty, opt_input_types);
-        // FIXME(effects) find a better way to do this
-        // Operators don't have generic methods, but making them `#[const_trait]` gives them
-        // `const host: bool`.
-        let args = if self.tcx.is_const_trait(trait_def_id) {
-            self.tcx.mk_args_from_iter(
-                args.iter()
-                    .chain([self.tcx.expected_host_effect_param_for_body(self.body_id).into()]),
-            )
-        } else {
-            args
-        };
         self.construct_obligation_for_trait(m_name, trait_def_id, obligation, args)
     }
 
diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs
index 1be7118..569fdea 100644
--- a/compiler/rustc_hir_typeck/src/method/probe.rs
+++ b/compiler/rustc_hir_typeck/src/method/probe.rs
@@ -404,7 +404,7 @@
                     mode,
                 }));
             } else if bad_ty.reached_raw_pointer
-                && !self.tcx.features().arbitrary_self_types_pointers
+                && !self.tcx.features().arbitrary_self_types_pointers()
                 && !self.tcx.sess.at_least_rust_2018()
             {
                 // this case used to be allowed by the compiler,
@@ -429,8 +429,8 @@
                 let ty = self.resolve_vars_if_possible(ty.value);
                 let guar = match *ty.kind() {
                     ty::Infer(ty::TyVar(_)) => {
-                        let raw_ptr_call =
-                            bad_ty.reached_raw_pointer && !self.tcx.features().arbitrary_self_types;
+                        let raw_ptr_call = bad_ty.reached_raw_pointer
+                            && !self.tcx.features().arbitrary_self_types();
                         let mut err = self.err_ctxt().emit_inference_failure_err(
                             self.body_id,
                             span,
@@ -813,7 +813,8 @@
                 | ty::ClauseKind::Projection(_)
                 | ty::ClauseKind::ConstArgHasType(_, _)
                 | ty::ClauseKind::WellFormed(_)
-                | ty::ClauseKind::ConstEvaluatable(_) => None,
+                | ty::ClauseKind::ConstEvaluatable(_)
+                | ty::ClauseKind::HostEffect(..) => None,
             }
         });
 
@@ -1146,7 +1147,7 @@
                     }
 
                     ty::Adt(def, args)
-                        if self.tcx.features().pin_ergonomics
+                        if self.tcx.features().pin_ergonomics()
                             && self.tcx.is_lang_item(def.did(), hir::LangItem::Pin) =>
                     {
                         // make sure this is a pinned reference (and not a `Pin<Box>` or something)
@@ -1195,7 +1196,7 @@
         self_ty: Ty<'tcx>,
         unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
     ) -> Option<PickResult<'tcx>> {
-        if !self.tcx.features().pin_ergonomics {
+        if !self.tcx.features().pin_ergonomics() {
             return None;
         }
 
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index 9dd5954..eaf40a1 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -537,7 +537,7 @@
                     && binding_id != self.binding_id
                 {
                     if self.check_and_add_sugg_binding(LetStmt {
-                        ty_hir_id_opt: if let Some(ty) = ty { Some(ty.hir_id) } else { None },
+                        ty_hir_id_opt: ty.map(|ty| ty.hir_id),
                         binding_id,
                         span: pat.span,
                         init_hir_id: init.hir_id,
diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs
index e961752..cba6586 100644
--- a/compiler/rustc_hir_typeck/src/pat.rs
+++ b/compiler/rustc_hir_typeck/src/pat.rs
@@ -442,7 +442,8 @@
         }
 
         let features = self.tcx.features();
-        if features.ref_pat_eat_one_layer_2024 || features.ref_pat_eat_one_layer_2024_structural {
+        if features.ref_pat_eat_one_layer_2024() || features.ref_pat_eat_one_layer_2024_structural()
+        {
             def_br = def_br.cap_ref_mutability(max_ref_mutbl.as_mutbl());
             if def_br == ByRef::Yes(Mutability::Not) {
                 max_ref_mutbl = MutblCap::Not;
@@ -490,7 +491,7 @@
             }
         }
 
-        if self.tcx.features().string_deref_patterns
+        if self.tcx.features().string_deref_patterns()
             && let hir::ExprKind::Lit(Spanned { node: ast::LitKind::Str(..), .. }) = lt.kind
         {
             let tcx = self.tcx;
@@ -675,10 +676,10 @@
         let bm = match user_bind_annot {
             BindingMode(ByRef::No, Mutability::Mut) if matches!(def_br, ByRef::Yes(_)) => {
                 if pat.span.at_least_rust_2024()
-                    && (self.tcx.features().ref_pat_eat_one_layer_2024
-                        || self.tcx.features().ref_pat_eat_one_layer_2024_structural)
+                    && (self.tcx.features().ref_pat_eat_one_layer_2024()
+                        || self.tcx.features().ref_pat_eat_one_layer_2024_structural())
                 {
-                    if !self.tcx.features().mut_ref {
+                    if !self.tcx.features().mut_ref() {
                         feature_err(
                             &self.tcx.sess,
                             sym::mut_ref,
@@ -2152,8 +2153,9 @@
     ) -> Ty<'tcx> {
         let tcx = self.tcx;
         let features = tcx.features();
-        let ref_pat_eat_one_layer_2024 = features.ref_pat_eat_one_layer_2024;
-        let ref_pat_eat_one_layer_2024_structural = features.ref_pat_eat_one_layer_2024_structural;
+        let ref_pat_eat_one_layer_2024 = features.ref_pat_eat_one_layer_2024();
+        let ref_pat_eat_one_layer_2024_structural =
+            features.ref_pat_eat_one_layer_2024_structural();
 
         let no_ref_mut_behind_and =
             ref_pat_eat_one_layer_2024 || ref_pat_eat_one_layer_2024_structural;
diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs
index 63cf483..8898266 100644
--- a/compiler/rustc_hir_typeck/src/upvar.rs
+++ b/compiler/rustc_hir_typeck/src/upvar.rs
@@ -488,7 +488,7 @@
         let final_upvar_tys = self.final_upvar_tys(closure_def_id);
         debug!(?closure_hir_id, ?args, ?final_upvar_tys);
 
-        if self.tcx.features().unsized_locals || self.tcx.features().unsized_fn_params {
+        if self.tcx.features().unsized_locals() || self.tcx.features().unsized_fn_params() {
             for capture in
                 self.typeck_results.borrow().closure_min_captures_flattened(closure_def_id)
             {
@@ -2457,7 +2457,7 @@
 ) -> (Place<'_>, ty::UpvarCapture) {
     let is_shared_ref = |ty: Ty<'_>| matches!(ty.kind(), ty::Ref(.., hir::Mutability::Not));
 
-    // Find the right-most deref (if any). All the projections that come after this
+    // Find the rightmost deref (if any). All the projections that come after this
     // are fields or other "in-place pointer adjustments"; these refer therefore to
     // data owned by whatever pointer is being dereferenced here.
     let idx = place.projections.iter().rposition(|proj| ProjectionKind::Deref == proj.kind);
diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs
index d3d092b..391e640 100644
--- a/compiler/rustc_hir_typeck/src/writeback.rs
+++ b/compiler/rustc_hir_typeck/src/writeback.rs
@@ -830,7 +830,7 @@
         value = tcx.fold_regions(value, |_, _| tcx.lifetimes.re_erased);
 
         // Normalize consts in writeback, because GCE doesn't normalize eagerly.
-        if tcx.features().generic_const_exprs {
+        if tcx.features().generic_const_exprs() {
             value =
                 value.fold_with(&mut EagerlyNormalizeConsts { tcx, param_env: self.fcx.param_env });
         }
diff --git a/compiler/rustc_incremental/src/assert_dep_graph.rs b/compiler/rustc_incremental/src/assert_dep_graph.rs
index a006786..1f46155 100644
--- a/compiler/rustc_incremental/src/assert_dep_graph.rs
+++ b/compiler/rustc_incremental/src/assert_dep_graph.rs
@@ -68,7 +68,7 @@
         // if the `rustc_attrs` feature is not enabled, then the
         // attributes we are interested in cannot be present anyway, so
         // skip the walk.
-        if !tcx.features().rustc_attrs {
+        if !tcx.features().rustc_attrs() {
             return;
         }
 
diff --git a/compiler/rustc_incremental/src/persist/dirty_clean.rs b/compiler/rustc_incremental/src/persist/dirty_clean.rs
index d25fe42..2075d42 100644
--- a/compiler/rustc_incremental/src/persist/dirty_clean.rs
+++ b/compiler/rustc_incremental/src/persist/dirty_clean.rs
@@ -140,7 +140,7 @@
     }
 
     // can't add `#[rustc_clean]` etc without opting into this feature
-    if !tcx.features().rustc_attrs {
+    if !tcx.features().rustc_attrs() {
         return;
     }
 
diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
index e3519df..90d0796 100644
--- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
+++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
@@ -489,17 +489,6 @@
                     }
                 }
             }
-            ty::ConstKind::Infer(InferConst::EffectVar(vid)) => {
-                match self.infcx.unwrap().probe_effect_var(vid) {
-                    Some(value) => return self.fold_const(value),
-                    None => {
-                        return self.canonicalize_const_var(
-                            CanonicalVarInfo { kind: CanonicalVarKind::Effect },
-                            ct,
-                        );
-                    }
-                }
-            }
             ty::ConstKind::Infer(InferConst::Fresh(_)) => {
                 bug!("encountered a fresh const during canonicalization")
             }
@@ -700,8 +689,7 @@
             .iter()
             .map(|v| CanonicalVarInfo {
                 kind: match v.kind {
-                    CanonicalVarKind::Ty(CanonicalTyVarKind::Int | CanonicalTyVarKind::Float)
-                    | CanonicalVarKind::Effect => {
+                    CanonicalVarKind::Ty(CanonicalTyVarKind::Int | CanonicalTyVarKind::Float) => {
                         return *v;
                     }
                     CanonicalVarKind::Ty(CanonicalTyVarKind::General(u)) => {
diff --git a/compiler/rustc_infer/src/infer/canonical/mod.rs b/compiler/rustc_infer/src/infer/canonical/mod.rs
index 8caedcd..fb5fc3a 100644
--- a/compiler/rustc_infer/src/infer/canonical/mod.rs
+++ b/compiler/rustc_infer/src/infer/canonical/mod.rs
@@ -24,7 +24,6 @@
 pub use instantiate::CanonicalExt;
 use rustc_index::IndexVec;
 pub use rustc_middle::infer::canonical::*;
-use rustc_middle::infer::unify_key::EffectVarValue;
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::{self, GenericArg, List, Ty, TyCtxt};
 use rustc_span::Span;
@@ -145,15 +144,6 @@
             CanonicalVarKind::Const(ui) => {
                 self.next_const_var_in_universe(span, universe_map(ui)).into()
             }
-            CanonicalVarKind::Effect => {
-                let vid = self
-                    .inner
-                    .borrow_mut()
-                    .effect_unification_table()
-                    .new_key(EffectVarValue::Unknown)
-                    .vid;
-                ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(vid)).into()
-            }
             CanonicalVarKind::PlaceholderConst(ty::PlaceholderConst { universe, bound }) => {
                 let universe_mapped = universe_map(universe);
                 let placeholder_mapped = ty::PlaceholderConst { universe: universe_mapped, bound };
diff --git a/compiler/rustc_infer/src/infer/context.rs b/compiler/rustc_infer/src/infer/context.rs
index 5700775..0c151a1 100644
--- a/compiler/rustc_infer/src/infer/context.rs
+++ b/compiler/rustc_infer/src/infer/context.rs
@@ -1,6 +1,5 @@
 ///! Definition of `InferCtxtLike` from the librarified type layer.
 use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_middle::infer::unify_key::EffectVarValue;
 use rustc_middle::traits::ObligationCause;
 use rustc_middle::traits::solve::SolverMode;
 use rustc_middle::ty::fold::TypeFoldable;
@@ -88,15 +87,6 @@
         }
     }
 
-    fn opportunistic_resolve_effect_var(&self, vid: ty::EffectVid) -> ty::Const<'tcx> {
-        match self.probe_effect_var(vid) {
-            Some(ct) => ct,
-            None => {
-                ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(self.root_effect_var(vid)))
-            }
-        }
-    }
-
     fn opportunistic_resolve_lt_var(&self, vid: ty::RegionVid) -> ty::Region<'tcx> {
         self.inner.borrow_mut().unwrap_region_constraints().opportunistic_resolve_var(self.tcx, vid)
     }
@@ -152,10 +142,6 @@
         self.inner.borrow_mut().const_unification_table().union(a, b);
     }
 
-    fn equate_effect_vids_raw(&self, a: rustc_type_ir::EffectVid, b: rustc_type_ir::EffectVid) {
-        self.inner.borrow_mut().effect_unification_table().union(a, b);
-    }
-
     fn instantiate_ty_var_raw<R: PredicateEmittingRelation<Self>>(
         &self,
         relation: &mut R,
@@ -189,13 +175,6 @@
         self.inner.borrow_mut().float_unification_table().union_value(vid, value);
     }
 
-    fn instantiate_effect_var_raw(&self, vid: rustc_type_ir::EffectVid, value: ty::Const<'tcx>) {
-        self.inner
-            .borrow_mut()
-            .effect_unification_table()
-            .union_value(vid, EffectVarValue::Known(value));
-    }
-
     fn instantiate_const_var_raw<R: PredicateEmittingRelation<Self>>(
         &self,
         relation: &mut R,
diff --git a/compiler/rustc_infer/src/infer/freshen.rs b/compiler/rustc_infer/src/infer/freshen.rs
index c429411..28eac5b 100644
--- a/compiler/rustc_infer/src/infer/freshen.rs
+++ b/compiler/rustc_infer/src/infer/freshen.rs
@@ -153,15 +153,6 @@
                 drop(inner);
                 self.freshen_const(input, ty::InferConst::Fresh)
             }
-            ty::ConstKind::Infer(ty::InferConst::EffectVar(v)) => {
-                let mut inner = self.infcx.inner.borrow_mut();
-                let input =
-                    inner.effect_unification_table().probe_value(v).known().ok_or_else(|| {
-                        ty::InferConst::EffectVar(inner.effect_unification_table().find(v).vid)
-                    });
-                drop(inner);
-                self.freshen_const(input, ty::InferConst::Fresh)
-            }
             ty::ConstKind::Infer(ty::InferConst::Fresh(i)) => {
                 if i >= self.const_freshen_count {
                     bug!(
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index 5afdf3c..be43cba 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -26,9 +26,7 @@
 use rustc_macros::extension;
 pub use rustc_macros::{TypeFoldable, TypeVisitable};
 use rustc_middle::infer::canonical::{CanonicalQueryInput, CanonicalVarValues};
-use rustc_middle::infer::unify_key::{
-    ConstVariableOrigin, ConstVariableValue, ConstVidKey, EffectVarValue, EffectVidKey,
-};
+use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableValue, ConstVidKey};
 use rustc_middle::mir::ConstraintCategory;
 use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult};
 use rustc_middle::traits::select;
@@ -39,7 +37,7 @@
 };
 use rustc_middle::ty::visit::TypeVisitableExt;
 use rustc_middle::ty::{
-    self, ConstVid, EffectVid, FloatVid, GenericArg, GenericArgKind, GenericArgs, GenericArgsRef,
+    self, ConstVid, FloatVid, GenericArg, GenericArgKind, GenericArgs, GenericArgsRef,
     GenericParamDefKind, InferConst, IntVid, Ty, TyCtxt, TyVid,
 };
 use rustc_middle::{bug, span_bug};
@@ -117,9 +115,6 @@
     /// Map from floating variable to the kind of float it represents.
     float_unification_storage: ut::UnificationTableStorage<ty::FloatVid>,
 
-    /// Map from effect variable to the effect param it represents.
-    effect_unification_storage: ut::UnificationTableStorage<EffectVidKey<'tcx>>,
-
     /// Tracks the set of region variables and the constraints between them.
     ///
     /// This is initially `Some(_)` but when
@@ -176,7 +171,6 @@
             const_unification_storage: Default::default(),
             int_unification_storage: Default::default(),
             float_unification_storage: Default::default(),
-            effect_unification_storage: Default::default(),
             region_constraint_storage: Some(Default::default()),
             region_obligations: vec![],
             opaque_type_storage: Default::default(),
@@ -228,10 +222,6 @@
         self.const_unification_storage.with_log(&mut self.undo_log)
     }
 
-    fn effect_unification_table(&mut self) -> UnificationTable<'_, 'tcx, EffectVidKey<'tcx>> {
-        self.effect_unification_storage.with_log(&mut self.undo_log)
-    }
-
     #[inline]
     pub fn unwrap_region_constraints(&mut self) -> RegionConstraintCollector<'_, 'tcx> {
         self.region_constraint_storage
@@ -524,7 +514,6 @@
             ),
             Ty(_) => write!(f, "unconstrained type"),
             Const(_) => write!(f, "unconstrained const value"),
-            Effect(_) => write!(f, "unconstrained effect value"),
         }
     }
 }
@@ -726,17 +715,6 @@
         vars
     }
 
-    pub fn unsolved_effects(&self) -> Vec<ty::Const<'tcx>> {
-        let mut inner = self.inner.borrow_mut();
-        let mut table = inner.effect_unification_table();
-
-        (0..table.len())
-            .map(|i| ty::EffectVid::from_usize(i))
-            .filter(|&vid| table.probe_value(vid).is_unknown())
-            .map(|v| ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(v)))
-            .collect()
-    }
-
     #[instrument(skip(self), level = "debug")]
     pub fn sub_regions(
         &self,
@@ -899,13 +877,6 @@
         ty::Const::new_var(self.tcx, vid)
     }
 
-    fn next_effect_var(&self) -> ty::Const<'tcx> {
-        let effect_vid =
-            self.inner.borrow_mut().effect_unification_table().new_key(EffectVarValue::Unknown).vid;
-
-        ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(effect_vid))
-    }
-
     pub fn next_int_var(&self) -> Ty<'tcx> {
         let next_int_var_id =
             self.inner.borrow_mut().int_unification_table().new_key(ty::IntVarValue::Unknown);
@@ -991,10 +962,7 @@
 
                 Ty::new_var(self.tcx, ty_var_id).into()
             }
-            GenericParamDefKind::Const { is_host_effect, .. } => {
-                if is_host_effect {
-                    return self.var_for_effect(param);
-                }
+            GenericParamDefKind::Const { .. } => {
                 let origin = ConstVariableOrigin { param_def_id: Some(param.def_id), span };
                 let const_var_id = self
                     .inner
@@ -1007,16 +975,6 @@
         }
     }
 
-    pub fn var_for_effect(&self, param: &ty::GenericParamDef) -> GenericArg<'tcx> {
-        let ty = self
-            .tcx
-            .type_of(param.def_id)
-            .no_bound_vars()
-            .expect("const parameter types cannot be generic");
-        debug_assert_eq!(self.tcx.types.bool, ty);
-        self.next_effect_var().into()
-    }
-
     /// Given a set of generics defined on a type or impl, returns the generic parameters mapping
     /// each type/region parameter to a fresh inference variable.
     pub fn fresh_args_for_item(&self, span: Span, def_id: DefId) -> GenericArgsRef<'tcx> {
@@ -1142,13 +1100,6 @@
                     .probe_value(vid)
                     .known()
                     .unwrap_or(ct),
-                InferConst::EffectVar(vid) => self
-                    .inner
-                    .borrow_mut()
-                    .effect_unification_table()
-                    .probe_value(vid)
-                    .known()
-                    .unwrap_or(ct),
                 InferConst::Fresh(_) => ct,
             },
             ty::ConstKind::Param(_)
@@ -1169,10 +1120,6 @@
         self.inner.borrow_mut().const_unification_table().find(var).vid
     }
 
-    pub fn root_effect_var(&self, var: ty::EffectVid) -> ty::EffectVid {
-        self.inner.borrow_mut().effect_unification_table().find(var).vid
-    }
-
     /// Resolves an int var to a rigid int type, if it was constrained to one,
     /// or else the root int var in the unification table.
     pub fn opportunistic_resolve_int_var(&self, vid: ty::IntVid) -> Ty<'tcx> {
@@ -1238,10 +1185,6 @@
         }
     }
 
-    pub fn probe_effect_var(&self, vid: EffectVid) -> Option<ty::Const<'tcx>> {
-        self.inner.borrow_mut().effect_unification_table().probe_value(vid).known()
-    }
-
     /// Attempts to resolve all type/region/const variables in
     /// `value`. Region inference must have been run already (e.g.,
     /// by calling `resolve_regions_and_report_errors`). If some
@@ -1511,14 +1454,6 @@
                     ConstVariableValue::Known { .. } => true,
                 }
             }
-
-            TyOrConstInferVar::Effect(v) => {
-                // If `probe_value` returns `Some`, it never equals
-                // `ty::ConstKind::Infer(ty::InferConst::Effect(v))`.
-                //
-                // Not `inlined_probe_value(v)` because this call site is colder.
-                self.probe_effect_var(v).is_some()
-            }
         }
     }
 
@@ -1545,8 +1480,6 @@
 
     /// Equivalent to `ty::ConstKind::Infer(ty::InferConst::Var(_))`.
     Const(ConstVid),
-    /// Equivalent to `ty::ConstKind::Infer(ty::InferConst::EffectVar(_))`.
-    Effect(EffectVid),
 }
 
 impl<'tcx> TyOrConstInferVar {
@@ -1577,7 +1510,6 @@
     fn maybe_from_const(ct: ty::Const<'tcx>) -> Option<Self> {
         match ct.kind() {
             ty::ConstKind::Infer(InferConst::Var(v)) => Some(TyOrConstInferVar::Const(v)),
-            ty::ConstKind::Infer(InferConst::EffectVar(v)) => Some(TyOrConstInferVar::Effect(v)),
             _ => None,
         }
     }
diff --git a/compiler/rustc_infer/src/infer/outlives/mod.rs b/compiler/rustc_infer/src/infer/outlives/mod.rs
index e23bb1a..1afe50e 100644
--- a/compiler/rustc_infer/src/infer/outlives/mod.rs
+++ b/compiler/rustc_infer/src/infer/outlives/mod.rs
@@ -24,19 +24,9 @@
     param_env
         .caller_bounds()
         .into_iter()
-        .map(ty::Clause::kind)
+        .filter_map(ty::Clause::as_region_outlives_clause)
         .filter_map(ty::Binder::no_bound_vars)
-        .filter_map(move |kind| match kind {
-            ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(r_a, r_b)) => {
-                Some(OutlivesBound::RegionSubRegion(r_b, r_a))
-            }
-            ty::ClauseKind::Trait(_)
-            | ty::ClauseKind::TypeOutlives(_)
-            | ty::ClauseKind::Projection(_)
-            | ty::ClauseKind::ConstArgHasType(_, _)
-            | ty::ClauseKind::WellFormed(_)
-            | ty::ClauseKind::ConstEvaluatable(_) => None,
-        })
+        .map(|ty::OutlivesPredicate(r_a, r_b)| OutlivesBound::RegionSubRegion(r_b, r_a))
 }
 
 impl<'tcx> InferCtxt<'tcx> {
diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs
index 7049444..32817db 100644
--- a/compiler/rustc_infer/src/infer/relate/generalize.rs
+++ b/compiler/rustc_infer/src/infer/relate/generalize.rs
@@ -660,7 +660,6 @@
                     }
                 }
             }
-            ty::ConstKind::Infer(InferConst::EffectVar(_)) => Ok(c),
             // FIXME: Unevaluated constants are also not rigid, so the current
             // approach of always relating them structurally is incomplete.
             //
diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs
index 64cc76f..6ec2e01 100644
--- a/compiler/rustc_infer/src/infer/resolve.rs
+++ b/compiler/rustc_infer/src/infer/resolve.rs
@@ -176,9 +176,6 @@
                 ty::ConstKind::Infer(InferConst::Fresh(_)) => {
                     bug!("Unexpected const in full const resolver: {:?}", c);
                 }
-                ty::ConstKind::Infer(InferConst::EffectVar(evid)) => {
-                    return Err(FixupError { unresolved: super::TyOrConstInferVar::Effect(evid) });
-                }
                 _ => {}
             }
             c.try_super_fold_with(self)
diff --git a/compiler/rustc_infer/src/infer/snapshot/fudge.rs b/compiler/rustc_infer/src/infer/snapshot/fudge.rs
index 613cebc2..394e07a 100644
--- a/compiler/rustc_infer/src/infer/snapshot/fudge.rs
+++ b/compiler/rustc_infer/src/infer/snapshot/fudge.rs
@@ -4,7 +4,6 @@
 use rustc_middle::infer::unify_key::{ConstVariableValue, ConstVidKey};
 use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
 use rustc_middle::ty::{self, ConstVid, FloatVid, IntVid, RegionVid, Ty, TyCtxt, TyVid};
-use rustc_type_ir::EffectVid;
 use rustc_type_ir::visit::TypeVisitableExt;
 use tracing::instrument;
 use ut::UnifyKey;
@@ -129,7 +128,6 @@
     int_vars: Range<IntVid>,
     float_vars: Range<FloatVid>,
     const_vars: (Range<ConstVid>, Vec<ConstVariableOrigin>),
-    effect_vars: Range<EffectVid>,
 }
 
 impl SnapshotVarData {
@@ -148,30 +146,16 @@
             &mut inner.const_unification_table(),
             vars_pre_snapshot.const_var_len,
         );
-        let effect_vars = vars_since_snapshot(
-            &inner.effect_unification_table(),
-            vars_pre_snapshot.effect_var_len,
-        );
-        let effect_vars = effect_vars.start.vid..effect_vars.end.vid;
-
-        SnapshotVarData { region_vars, type_vars, int_vars, float_vars, const_vars, effect_vars }
+        SnapshotVarData { region_vars, type_vars, int_vars, float_vars, const_vars }
     }
 
     fn is_empty(&self) -> bool {
-        let SnapshotVarData {
-            region_vars,
-            type_vars,
-            int_vars,
-            float_vars,
-            const_vars,
-            effect_vars,
-        } = self;
+        let SnapshotVarData { region_vars, type_vars, int_vars, float_vars, const_vars } = self;
         region_vars.0.is_empty()
             && type_vars.0.is_empty()
             && int_vars.is_empty()
             && float_vars.is_empty()
             && const_vars.0.is_empty()
-            && effect_vars.is_empty()
     }
 }
 
@@ -258,13 +242,6 @@
                         ct
                     }
                 }
-                ty::InferConst::EffectVar(vid) => {
-                    if self.snapshot_vars.effect_vars.contains(&vid) {
-                        self.infcx.next_effect_var()
-                    } else {
-                        ct
-                    }
-                }
                 ty::InferConst::Fresh(_) => {
                     unreachable!("unexpected fresh infcx var")
                 }
diff --git a/compiler/rustc_infer/src/infer/snapshot/mod.rs b/compiler/rustc_infer/src/infer/snapshot/mod.rs
index fa81350..b16c80c 100644
--- a/compiler/rustc_infer/src/infer/snapshot/mod.rs
+++ b/compiler/rustc_infer/src/infer/snapshot/mod.rs
@@ -23,7 +23,6 @@
     int_var_len: usize,
     float_var_len: usize,
     const_var_len: usize,
-    effect_var_len: usize,
 }
 
 impl<'tcx> InferCtxt<'tcx> {
@@ -35,7 +34,6 @@
             int_var_len: inner.int_unification_table().len(),
             float_var_len: inner.float_unification_table().len(),
             const_var_len: inner.const_unification_table().len(),
-            effect_var_len: inner.effect_unification_table().len(),
         }
     }
 
diff --git a/compiler/rustc_infer/src/infer/snapshot/undo_log.rs b/compiler/rustc_infer/src/infer/snapshot/undo_log.rs
index 79ea091..713389f 100644
--- a/compiler/rustc_infer/src/infer/snapshot/undo_log.rs
+++ b/compiler/rustc_infer/src/infer/snapshot/undo_log.rs
@@ -2,7 +2,7 @@
 
 use rustc_data_structures::undo_log::{Rollback, UndoLogs};
 use rustc_data_structures::{snapshot_vec as sv, unify as ut};
-use rustc_middle::infer::unify_key::{ConstVidKey, EffectVidKey, RegionVidKey};
+use rustc_middle::infer::unify_key::{ConstVidKey, RegionVidKey};
 use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey};
 use tracing::debug;
 
@@ -22,7 +22,6 @@
     ConstUnificationTable(sv::UndoLog<ut::Delegate<ConstVidKey<'tcx>>>),
     IntUnificationTable(sv::UndoLog<ut::Delegate<ty::IntVid>>),
     FloatUnificationTable(sv::UndoLog<ut::Delegate<ty::FloatVid>>),
-    EffectUnificationTable(sv::UndoLog<ut::Delegate<EffectVidKey<'tcx>>>),
     RegionConstraintCollector(region_constraints::UndoLog<'tcx>),
     RegionUnificationTable(sv::UndoLog<ut::Delegate<RegionVidKey<'tcx>>>),
     ProjectionCache(traits::UndoLog<'tcx>),
@@ -50,7 +49,6 @@
     FloatUnificationTable(sv::UndoLog<ut::Delegate<ty::FloatVid>>),
 
     ConstUnificationTable(sv::UndoLog<ut::Delegate<ConstVidKey<'tcx>>>),
-    EffectUnificationTable(sv::UndoLog<ut::Delegate<EffectVidKey<'tcx>>>),
 
     RegionUnificationTable(sv::UndoLog<ut::Delegate<RegionVidKey<'tcx>>>),
     ProjectionCache(traits::UndoLog<'tcx>),
@@ -65,7 +63,6 @@
             UndoLog::ConstUnificationTable(undo) => self.const_unification_storage.reverse(undo),
             UndoLog::IntUnificationTable(undo) => self.int_unification_storage.reverse(undo),
             UndoLog::FloatUnificationTable(undo) => self.float_unification_storage.reverse(undo),
-            UndoLog::EffectUnificationTable(undo) => self.effect_unification_storage.reverse(undo),
             UndoLog::RegionConstraintCollector(undo) => {
                 self.region_constraint_storage.as_mut().unwrap().reverse(undo)
             }
diff --git a/compiler/rustc_infer/src/infer/type_variable.rs b/compiler/rustc_infer/src/infer/type_variable.rs
index 779ce97..2086483 100644
--- a/compiler/rustc_infer/src/infer/type_variable.rs
+++ b/compiler/rustc_infer/src/infer/type_variable.rs
@@ -187,10 +187,7 @@
         value_count: usize,
     ) -> (Range<TyVid>, Vec<TypeVariableOrigin>) {
         let range = TyVid::from_usize(value_count)..TyVid::from_usize(self.num_vars());
-        (
-            range.start..range.end,
-            (range.start..range.end).map(|index| self.var_origin(index)).collect(),
-        )
+        (range.clone(), range.map(|index| self.var_origin(index)).collect())
     }
 
     /// Returns indices of all variables that are not yet
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index 3189620..d3762e7 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -836,6 +836,7 @@
     tracked!(profile_emit, Some(PathBuf::from("abc")));
     tracked!(profile_sample_use, Some(PathBuf::from("abc")));
     tracked!(profiler_runtime, "abc".to_string());
+    tracked!(regparm, Some(3));
     tracked!(relax_elf_relocations, Some(true));
     tracked!(remap_cwd_prefix, Some(PathBuf::from("abc")));
     tracked!(sanitizer, SanitizerSet::ADDRESS);
diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl
index c4d709aa..3fa4329 100644
--- a/compiler/rustc_lint/messages.ftl
+++ b/compiler/rustc_lint/messages.ftl
@@ -203,14 +203,14 @@
     .current_use = this identifier can be confused with `{$existing_sym}`
     .other_use = other identifier used here
 
-lint_cstring_ptr = getting the inner pointer of a temporary `CString`
-    .as_ptr_label = this pointer will be invalid
-    .unwrap_label = this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
-    .note = pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
-    .help = for more information, see https://doc.rust-lang.org/reference/destructors.html
-
 lint_custom_inner_attribute_unstable = custom inner attributes are unstable
 
+lint_dangling_pointers_from_temporaries = a dangling pointer will be produced because the temporary `{$ty}` will be dropped
+    .label_ptr = this pointer will immediately be invalid
+    .label_temporary = this `{$ty}` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+    .note = pointers do not have a lifetime; when calling `{$callee}` the `{$ty}` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+    .help = for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
 lint_default_hash_types = prefer `{$preferred}` over `{$used}`, it has better performance
     .note = a `use rustc_data_structures::fx::{$preferred}` may be necessary
 
diff --git a/compiler/rustc_lint/src/async_fn_in_trait.rs b/compiler/rustc_lint/src/async_fn_in_trait.rs
index 63a8a94..9923f05 100644
--- a/compiler/rustc_lint/src/async_fn_in_trait.rs
+++ b/compiler/rustc_lint/src/async_fn_in_trait.rs
@@ -95,7 +95,7 @@
             && let hir::IsAsync::Async(async_span) = sig.header.asyncness
         {
             // RTN can be used to bound `async fn` in traits in a better way than "always"
-            if cx.tcx.features().return_type_notation {
+            if cx.tcx.features().return_type_notation() {
                 return;
             }
 
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index ef8100d..dbb8c66 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -4,21 +4,14 @@
 //! AST visitor. Also see `rustc_session::lint::builtin`, which contains the
 //! definitions of lints that are emitted directly inside the main compiler.
 //!
-//! To add a new lint to rustc, declare it here using `declare_lint!()`.
+//! To add a new lint to rustc, declare it here using [`declare_lint!`].
 //! Then add code to emit the new lint in the appropriate circumstances.
-//! You can do that in an existing `LintPass` if it makes sense, or in a
-//! new `LintPass`, or using `Session::add_lint` elsewhere in the
-//! compiler. Only do the latter if the check can't be written cleanly as a
-//! `LintPass` (also, note that such lints will need to be defined in
-//! `rustc_session::lint::builtin`, not here).
 //!
-//! If you define a new `EarlyLintPass`, you will also need to add it to the
-//! `add_early_builtin!` or `add_early_builtin_with_new!` invocation in
-//! `lib.rs`. Use the former for unit-like structs and the latter for structs
-//! with a `pub fn new()`.
+//! If you define a new [`EarlyLintPass`], you will also need to add it to the
+//! [`crate::early_lint_methods!`] invocation in `lib.rs`.
 //!
-//! If you define a new `LateLintPass`, you will also need to add it to the
-//! `late_lint_methods!` invocation in `lib.rs`.
+//! If you define a new [`LateLintPass`], you will also need to add it to the
+//! [`crate::late_lint_methods!`] invocation in `lib.rs`.
 
 use std::fmt::Write;
 
@@ -73,7 +66,6 @@
     EarlyContext, EarlyLintPass, LateContext, LateLintPass, Level, LintContext,
     fluent_generated as fluent,
 };
-
 declare_lint! {
     /// The `while_true` lint detects `while true { }`.
     ///
@@ -241,7 +233,8 @@
     /// behavior.
     UNSAFE_CODE,
     Allow,
-    "usage of `unsafe` code and other potentially unsound constructs"
+    "usage of `unsafe` code and other potentially unsound constructs",
+    @eval_always = true
 }
 
 declare_lint_pass!(UnsafeCode => [UNSAFE_CODE]);
@@ -389,6 +382,7 @@
     report_in_external_macro
 }
 
+#[derive(Default)]
 pub struct MissingDoc;
 
 impl_lint_pass!(MissingDoc => [MISSING_DOCS]);
@@ -819,8 +813,8 @@
 
 impl_lint_pass!(DeprecatedAttr => []);
 
-impl DeprecatedAttr {
-    pub fn new() -> DeprecatedAttr {
+impl Default for DeprecatedAttr {
+    fn default() -> Self {
         DeprecatedAttr { depr_attrs: deprecated_attributes() }
     }
 }
@@ -1235,7 +1229,7 @@
         def_id: LocalDefId,
     ) {
         if fn_kind.asyncness().is_async()
-            && !cx.tcx.features().async_fn_track_caller
+            && !cx.tcx.features().async_fn_track_caller()
             // Now, check if the function has the `#[track_caller]` attribute
             && let Some(attr) = cx.tcx.get_attr(def_id, sym::track_caller)
         {
@@ -1424,7 +1418,7 @@
         // See also `tests/ui/const-generics/generic_const_exprs/type-alias-bounds.rs`.
         let ty = cx.tcx.type_of(item.owner_id).instantiate_identity();
         if ty.has_type_flags(ty::TypeFlags::HAS_CT_PROJECTION)
-            && cx.tcx.features().generic_const_exprs
+            && cx.tcx.features().generic_const_exprs()
         {
             return;
         }
@@ -1538,7 +1532,7 @@
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
         use rustc_middle::ty::ClauseKind;
 
-        if cx.tcx.features().trivial_bounds {
+        if cx.tcx.features().trivial_bounds() {
             let predicates = cx.tcx.predicates_of(item.owner_id);
             for &(predicate, span) in predicates.predicates {
                 let predicate_kind_name = match predicate.kind().skip_binder() {
@@ -1554,7 +1548,9 @@
                     // Ignore bounds that a user can't type
                     | ClauseKind::WellFormed(..)
                     // FIXME(generic_const_exprs): `ConstEvaluatable` can be written
-                    | ClauseKind::ConstEvaluatable(..)  => continue,
+                    | ClauseKind::ConstEvaluatable(..)
+                    // Users don't write this directly, only via another trait ref.
+                    | ty::ClauseKind::HostEffect(..) => continue,
                 };
                 if predicate.is_global() {
                     cx.emit_span_lint(TRIVIAL_BOUNDS, span, BuiltinTrivialBounds {
@@ -1892,11 +1888,11 @@
     fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &ast::MacCall) {
         self.check_tokens(cx, &mac.args.tokens);
     }
-    fn check_ident(&mut self, cx: &EarlyContext<'_>, ident: Ident) {
+    fn check_ident(&mut self, cx: &EarlyContext<'_>, ident: &Ident) {
         if ident.name.as_str().starts_with('\'') {
             self.check_ident_token(cx, UnderMacro(false), ident.without_first_quote(), "'");
         } else {
-            self.check_ident_token(cx, UnderMacro(false), ident, "");
+            self.check_ident_token(cx, UnderMacro(false), *ident, "");
         }
     }
 }
@@ -2287,13 +2283,15 @@
 impl EarlyLintPass for IncompleteInternalFeatures {
     fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &ast::Crate) {
         let features = cx.builder.features();
-        features
-            .declared_lang_features
-            .iter()
-            .map(|(name, span, _)| (name, span))
-            .chain(features.declared_lib_features.iter().map(|(name, span)| (name, span)))
-            .filter(|(&name, _)| features.incomplete(name) || features.internal(name))
-            .for_each(|(&name, &span)| {
+        let lang_features =
+            features.enabled_lang_features().iter().map(|feat| (feat.gate_name, feat.attr_sp));
+        let lib_features =
+            features.enabled_lib_features().iter().map(|feat| (feat.gate_name, feat.attr_sp));
+
+        lang_features
+            .chain(lib_features)
+            .filter(|(name, _)| features.incomplete(*name) || features.internal(*name))
+            .for_each(|(name, span)| {
                 if features.incomplete(name) {
                     let note = rustc_feature::find_feature_issue(name, GateIssue::Language)
                         .map(|n| BuiltinFeatureIssueNote { n });
@@ -2657,8 +2655,8 @@
     ///
     /// ### Explanation
     ///
-    /// Dereferencing a null pointer causes [undefined behavior] even as a place expression,
-    /// like `&*(0 as *const i32)` or `addr_of!(*(0 as *const i32))`.
+    /// Dereferencing a null pointer causes [undefined behavior] if it is accessed
+    /// (loaded from or stored to).
     ///
     /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
     pub DEREF_NULLPTR,
@@ -2673,14 +2671,14 @@
         /// test if expression is a null ptr
         fn is_null_ptr(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
             match &expr.kind {
-                rustc_hir::ExprKind::Cast(expr, ty) => {
-                    if let rustc_hir::TyKind::Ptr(_) = ty.kind {
+                hir::ExprKind::Cast(expr, ty) => {
+                    if let hir::TyKind::Ptr(_) = ty.kind {
                         return is_zero(expr) || is_null_ptr(cx, expr);
                     }
                 }
                 // check for call to `core::ptr::null` or `core::ptr::null_mut`
-                rustc_hir::ExprKind::Call(path, _) => {
-                    if let rustc_hir::ExprKind::Path(ref qpath) = path.kind {
+                hir::ExprKind::Call(path, _) => {
+                    if let hir::ExprKind::Path(ref qpath) = path.kind {
                         if let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id() {
                             return matches!(
                                 cx.tcx.get_diagnostic_name(def_id),
@@ -2697,7 +2695,7 @@
         /// test if expression is the literal `0`
         fn is_zero(expr: &hir::Expr<'_>) -> bool {
             match &expr.kind {
-                rustc_hir::ExprKind::Lit(lit) => {
+                hir::ExprKind::Lit(lit) => {
                     if let LitKind::Int(a, _) = lit.node {
                         return a == 0;
                     }
@@ -2707,8 +2705,16 @@
             false
         }
 
-        if let rustc_hir::ExprKind::Unary(rustc_hir::UnOp::Deref, expr_deref) = expr.kind {
-            if is_null_ptr(cx, expr_deref) {
+        if let hir::ExprKind::Unary(hir::UnOp::Deref, expr_deref) = expr.kind
+            && is_null_ptr(cx, expr_deref)
+        {
+            if let hir::Node::Expr(hir::Expr {
+                kind: hir::ExprKind::AddrOf(hir::BorrowKind::Raw, ..),
+                ..
+            }) = cx.tcx.parent_hir_node(expr.hir_id)
+            {
+                // `&raw *NULL` is ok.
+            } else {
                 cx.emit_span_lint(DEREF_NULLPTR, expr.span, BuiltinDerefNullptr {
                     label: expr.span,
                 });
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index 39f90a8..4af1fd1 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -1,18 +1,7 @@
-//! Implementation of lint checking.
+//! Basic types for managing and implementing lints.
 //!
-//! The lint checking is mostly consolidated into one pass which runs
-//! after all other analyses. Throughout compilation, lint warnings
-//! can be added via the `add_lint` method on the Session structure. This
-//! requires a span and an ID of the node that the lint is being added to. The
-//! lint isn't actually emitted at that time because it is unknown what the
-//! actual lint level at that location is.
-//!
-//! To actually emit lint warnings/errors, a separate pass is used.
-//! A context keeps track of the current state of all lint levels.
-//! Upon entering a node of the ast which can modify the lint settings, the
-//! previous lint state is pushed onto a stack and the ast is then recursed
-//! upon. As the ast is traversed, this keeps track of the current lint level
-//! for all lint attributes.
+//! See <https://rustc-dev-guide.rust-lang.org/diagnostics.html> for an
+//! overview of how lints are implemented.
 
 use std::cell::Cell;
 use std::{iter, slice};
@@ -52,9 +41,6 @@
     dyn for<'tcx> Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx> + sync::DynSend + sync::DynSync;
 
 /// Information about the registered lints.
-///
-/// This is basically the subset of `Context` that we can
-/// build early in the compile pipeline.
 pub struct LintStore {
     /// Registered lints.
     lints: Vec<&'static Lint>,
diff --git a/compiler/rustc_lint/src/dangling.rs b/compiler/rustc_lint/src/dangling.rs
new file mode 100644
index 0000000..a34c3e2
--- /dev/null
+++ b/compiler/rustc_lint/src/dangling.rs
@@ -0,0 +1,223 @@
+use rustc_ast::visit::{visit_opt, walk_list};
+use rustc_hir::def_id::LocalDefId;
+use rustc_hir::intravisit::{FnKind, Visitor, walk_expr};
+use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, LangItem};
+use rustc_middle::ty::{Ty, TyCtxt};
+use rustc_session::{declare_lint, impl_lint_pass};
+use rustc_span::Span;
+use rustc_span::symbol::sym;
+
+use crate::lints::DanglingPointersFromTemporaries;
+use crate::{LateContext, LateLintPass};
+
+declare_lint! {
+    /// The `dangling_pointers_from_temporaries` lint detects getting a pointer to data
+    /// of a temporary that will immediately get dropped.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// # #![allow(unused)]
+    /// # unsafe fn use_data(ptr: *const u8) { }
+    /// fn gather_and_use(bytes: impl Iterator<Item = u8>) {
+    ///     let x: *const u8 = bytes.collect::<Vec<u8>>().as_ptr();
+    ///     unsafe { use_data(x) }
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Getting a pointer from a temporary value will not prolong its lifetime,
+    /// which means that the value can be dropped and the allocation freed
+    /// while the pointer still exists, making the pointer dangling.
+    /// This is not an error (as far as the type system is concerned)
+    /// but probably is not what the user intended either.
+    ///
+    /// If you need stronger guarantees, consider using references instead,
+    /// as they are statically verified by the borrow-checker to never dangle.
+    pub DANGLING_POINTERS_FROM_TEMPORARIES,
+    Warn,
+    "detects getting a pointer from a temporary"
+}
+
+/// FIXME: false negatives (i.e. the lint is not emitted when it should be)
+/// 1. Method calls that are not checked for:
+///    - [`temporary_unsafe_cell.get()`][`core::cell::UnsafeCell::get()`]
+///    - [`temporary_sync_unsafe_cell.get()`][`core::cell::SyncUnsafeCell::get()`]
+/// 2. Ways to get a temporary that are not recognized:
+///    - `owning_temporary.field`
+///    - `owning_temporary[index]`
+/// 3. No checks for ref-to-ptr conversions:
+///    - `&raw [mut] temporary`
+///    - `&temporary as *(const|mut) _`
+///    - `ptr::from_ref(&temporary)` and friends
+#[derive(Clone, Copy, Default)]
+pub(crate) struct DanglingPointers;
+
+impl_lint_pass!(DanglingPointers => [DANGLING_POINTERS_FROM_TEMPORARIES]);
+
+// This skips over const blocks, but they cannot use or return a dangling pointer anyways.
+impl<'tcx> LateLintPass<'tcx> for DanglingPointers {
+    fn check_fn(
+        &mut self,
+        cx: &LateContext<'tcx>,
+        _: FnKind<'tcx>,
+        _: &'tcx FnDecl<'tcx>,
+        body: &'tcx Body<'tcx>,
+        _: Span,
+        _: LocalDefId,
+    ) {
+        DanglingPointerSearcher { cx, inside_call_args: false }.visit_body(body)
+    }
+}
+
+/// This produces a dangling pointer:
+/// ```ignore (example)
+/// let ptr = CString::new("hello").unwrap().as_ptr();
+/// foo(ptr)
+/// ```
+///
+/// But this does not:
+/// ```ignore (example)
+/// foo(CString::new("hello").unwrap().as_ptr())
+/// ```
+///
+/// But this does:
+/// ```ignore (example)
+/// foo({ let ptr = CString::new("hello").unwrap().as_ptr(); ptr })
+/// ```
+///
+/// So we have to keep track of when we are inside of a function/method call argument.
+struct DanglingPointerSearcher<'lcx, 'tcx> {
+    cx: &'lcx LateContext<'tcx>,
+    /// Keeps track of whether we are inside of function/method call arguments,
+    /// where this lint should not be emitted.
+    ///
+    /// See [the main doc][`Self`] for examples.
+    inside_call_args: bool,
+}
+
+impl Visitor<'_> for DanglingPointerSearcher<'_, '_> {
+    fn visit_expr(&mut self, expr: &Expr<'_>) -> Self::Result {
+        if !self.inside_call_args {
+            lint_expr(self.cx, expr)
+        }
+        match expr.kind {
+            ExprKind::Call(lhs, args) | ExprKind::MethodCall(_, lhs, args, _) => {
+                self.visit_expr(lhs);
+                self.with_inside_call_args(true, |this| walk_list!(this, visit_expr, args))
+            }
+            ExprKind::Block(&Block { stmts, expr, .. }, _) => {
+                self.with_inside_call_args(false, |this| walk_list!(this, visit_stmt, stmts));
+                visit_opt!(self, visit_expr, expr)
+            }
+            _ => walk_expr(self, expr),
+        }
+    }
+}
+
+impl DanglingPointerSearcher<'_, '_> {
+    fn with_inside_call_args<R>(
+        &mut self,
+        inside_call_args: bool,
+        callback: impl FnOnce(&mut Self) -> R,
+    ) -> R {
+        let old = core::mem::replace(&mut self.inside_call_args, inside_call_args);
+        let result = callback(self);
+        self.inside_call_args = old;
+        result
+    }
+}
+
+fn lint_expr(cx: &LateContext<'_>, expr: &Expr<'_>) {
+    if let ExprKind::MethodCall(method, receiver, _args, _span) = expr.kind
+        && matches!(method.ident.name, sym::as_ptr | sym::as_mut_ptr)
+        && is_temporary_rvalue(receiver)
+        && let ty = cx.typeck_results().expr_ty(receiver)
+        && is_interesting(cx.tcx, ty)
+    {
+        // FIXME: use `emit_node_lint` when `#[primary_span]` is added.
+        cx.tcx.emit_node_span_lint(
+            DANGLING_POINTERS_FROM_TEMPORARIES,
+            expr.hir_id,
+            method.ident.span,
+            DanglingPointersFromTemporaries {
+                callee: method.ident.name,
+                ty,
+                ptr_span: method.ident.span,
+                temporary_span: receiver.span,
+            },
+        )
+    }
+}
+
+fn is_temporary_rvalue(expr: &Expr<'_>) -> bool {
+    match expr.kind {
+        // Const is not temporary.
+        ExprKind::ConstBlock(..) | ExprKind::Repeat(..) | ExprKind::Lit(..) => false,
+
+        // This is literally lvalue.
+        ExprKind::Path(..) => false,
+
+        // Calls return rvalues.
+        ExprKind::Call(..) | ExprKind::MethodCall(..) | ExprKind::Binary(..) => true,
+
+        // Inner blocks are rvalues.
+        ExprKind::If(..) | ExprKind::Loop(..) | ExprKind::Match(..) | ExprKind::Block(..) => true,
+
+        // FIXME: these should probably recurse and typecheck along the way.
+        //        Some false negatives are possible for now.
+        ExprKind::Index(..) | ExprKind::Field(..) | ExprKind::Unary(..) => false,
+
+        ExprKind::Struct(..) => true,
+
+        // FIXME: this has false negatives, but I do not want to deal with 'static/const promotion just yet.
+        ExprKind::Array(..) => false,
+
+        // These typecheck to `!`
+        ExprKind::Break(..) | ExprKind::Continue(..) | ExprKind::Ret(..) | ExprKind::Become(..) => {
+            false
+        }
+
+        // These typecheck to `()`
+        ExprKind::Assign(..) | ExprKind::AssignOp(..) | ExprKind::Yield(..) => false,
+
+        // Compiler-magic macros
+        ExprKind::AddrOf(..) | ExprKind::OffsetOf(..) | ExprKind::InlineAsm(..) => false,
+
+        // We are not interested in these
+        ExprKind::Cast(..)
+        | ExprKind::Closure(..)
+        | ExprKind::Tup(..)
+        | ExprKind::DropTemps(..)
+        | ExprKind::Let(..) => false,
+
+        // Not applicable
+        ExprKind::Type(..) | ExprKind::Err(..) => false,
+    }
+}
+
+// Array, Vec, String, CString, MaybeUninit, Cell, Box<[_]>, Box<str>, Box<CStr>,
+// or any of the above in arbitrary many nested Box'es.
+fn is_interesting(tcx: TyCtxt<'_>, ty: Ty<'_>) -> bool {
+    if ty.is_array() {
+        true
+    } else if let Some(inner) = ty.boxed_ty() {
+        inner.is_slice()
+            || inner.is_str()
+            || inner.ty_adt_def().is_some_and(|def| tcx.is_lang_item(def.did(), LangItem::CStr))
+            || is_interesting(tcx, inner)
+    } else if let Some(def) = ty.ty_adt_def() {
+        for lang_item in [LangItem::String, LangItem::MaybeUninit] {
+            if tcx.is_lang_item(def.did(), lang_item) {
+                return true;
+            }
+        }
+        tcx.get_diagnostic_name(def.did())
+            .is_some_and(|name| matches!(name, sym::cstring_type | sym::Vec | sym::Cell))
+    } else {
+        false
+    }
+}
diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs
index 2285877..acccff7 100644
--- a/compiler/rustc_lint/src/early.rs
+++ b/compiler/rustc_lint/src/early.rs
@@ -1,18 +1,8 @@
-//! Implementation of lint checking.
+//! Implementation of the early lint pass.
 //!
-//! The lint checking is mostly consolidated into one pass which runs
-//! after all other analyses. Throughout compilation, lint warnings
-//! can be added via the `add_lint` method on the Session structure. This
-//! requires a span and an ID of the node that the lint is being added to. The
-//! lint isn't actually emitted at that time because it is unknown what the
-//! actual lint level at that location is.
-//!
-//! To actually emit lint warnings/errors, a separate pass is used.
-//! A context keeps track of the current state of all lint levels.
-//! Upon entering a node of the ast which can modify the lint settings, the
-//! previous lint state is pushed onto a stack and the ast is then recursed
-//! upon. As the ast is traversed, this keeps track of the current lint level
-//! for all lint attributes.
+//! The early lint pass works on AST nodes after macro expansion and name
+//! resolution, just before AST lowering. These lints are for purely
+//! syntactical lints.
 
 use rustc_ast::ptr::P;
 use rustc_ast::visit::{self as ast_visit, Visitor, walk_list};
@@ -121,6 +111,18 @@
         self.with_lint_attrs(e.id, &e.attrs, |cx| {
             lint_callback!(cx, check_expr, e);
             ast_visit::walk_expr(cx, e);
+            // Explicitly check for lints associated with 'closure_id', since
+            // it does not have a corresponding AST node
+            match e.kind {
+                ast::ExprKind::Closure(box ast::Closure {
+                    coroutine_kind: Some(coroutine_kind),
+                    ..
+                }) => {
+                    cx.check_id(coroutine_kind.closure_id());
+                }
+                _ => {}
+            }
+            lint_callback!(cx, check_expr_post, e);
         })
     }
 
@@ -190,7 +192,7 @@
         ast_visit::walk_ty(self, t);
     }
 
-    fn visit_ident(&mut self, ident: Ident) {
+    fn visit_ident(&mut self, ident: &Ident) {
         lint_callback!(self, check_ident, ident);
     }
 
@@ -214,21 +216,6 @@
         })
     }
 
-    fn visit_expr_post(&mut self, e: &'a ast::Expr) {
-        // Explicitly check for lints associated with 'closure_id', since
-        // it does not have a corresponding AST node
-        match e.kind {
-            ast::ExprKind::Closure(box ast::Closure {
-                coroutine_kind: Some(coroutine_kind),
-                ..
-            }) => {
-                self.check_id(coroutine_kind.closure_id());
-            }
-            _ => {}
-        }
-        lint_callback!(self, check_expr_post, e);
-    }
-
     fn visit_generic_arg(&mut self, arg: &'a ast::GenericArg) {
         lint_callback!(self, check_generic_arg, arg);
         ast_visit::walk_generic_arg(self, arg);
@@ -312,6 +299,9 @@
     fn name(&self) -> &'static str {
         panic!()
     }
+    fn get_lints(&self) -> crate::LintVec {
+        panic!()
+    }
 }
 
 macro_rules! impl_early_lint_pass {
diff --git a/compiler/rustc_lint/src/if_let_rescope.rs b/compiler/rustc_lint/src/if_let_rescope.rs
index 58fd11f..bdfcc2c 100644
--- a/compiler/rustc_lint/src/if_let_rescope.rs
+++ b/compiler/rustc_lint/src/if_let_rescope.rs
@@ -243,7 +243,7 @@
 
 impl<'tcx> LateLintPass<'tcx> for IfLetRescope {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
-        if expr.span.edition().at_least_rust_2024() || !cx.tcx.features().if_let_rescope {
+        if expr.span.edition().at_least_rust_2024() || !cx.tcx.features().if_let_rescope() {
             return;
         }
         if let (Level::Allow, _) = cx.tcx.lint_level_at_node(IF_LET_RESCOPE, expr.hir_id) {
diff --git a/compiler/rustc_lint/src/impl_trait_overcaptures.rs b/compiler/rustc_lint/src/impl_trait_overcaptures.rs
index d029ad9..cc40b67 100644
--- a/compiler/rustc_lint/src/impl_trait_overcaptures.rs
+++ b/compiler/rustc_lint/src/impl_trait_overcaptures.rs
@@ -263,8 +263,8 @@
             && parent == self.parent_def_id
         {
             let opaque_span = self.tcx.def_span(opaque_def_id);
-            let new_capture_rules =
-                opaque_span.at_least_rust_2024() || self.tcx.features().lifetime_capture_rules_2024;
+            let new_capture_rules = opaque_span.at_least_rust_2024()
+                || self.tcx.features().lifetime_capture_rules_2024();
             if !new_capture_rules
                 && !opaque.bounds.iter().any(|bound| matches!(bound, hir::GenericBound::Use(..)))
             {
diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs
index 94cc58e..2f338f4 100644
--- a/compiler/rustc_lint/src/internal.rs
+++ b/compiler/rustc_lint/src/internal.rs
@@ -427,9 +427,10 @@
     /// More details on translatable diagnostics can be found
     /// [here](https://rustc-dev-guide.rust-lang.org/diagnostics/translation.html).
     pub rustc::UNTRANSLATABLE_DIAGNOSTIC,
-    Deny,
+    Allow,
     "prevent creation of diagnostics which cannot be translated",
-    report_in_external_macro: true
+    report_in_external_macro: true,
+    @eval_always = true
 }
 
 declare_tool_lint! {
@@ -440,9 +441,10 @@
     /// More details on diagnostics implementations can be found
     /// [here](https://rustc-dev-guide.rust-lang.org/diagnostics/diagnostic-structs.html).
     pub rustc::DIAGNOSTIC_OUTSIDE_OF_IMPL,
-    Deny,
+    Allow,
     "prevent diagnostic creation outside of `Diagnostic`/`Subdiagnostic`/`LintDiagnostic` impls",
-    report_in_external_macro: true
+    report_in_external_macro: true,
+    @eval_always = true
 }
 
 declare_lint_pass!(Diagnostics => [UNTRANSLATABLE_DIAGNOSTIC, DIAGNOSTIC_OUTSIDE_OF_IMPL]);
diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs
index 6d5903a..9d35ce1 100644
--- a/compiler/rustc_lint/src/late.rs
+++ b/compiler/rustc_lint/src/late.rs
@@ -1,18 +1,7 @@
-//! Implementation of lint checking.
+//! Implementation of the late lint pass.
 //!
-//! The lint checking is mostly consolidated into one pass which runs
-//! after all other analyses. Throughout compilation, lint warnings
-//! can be added via the `add_lint` method on the Session structure. This
-//! requires a span and an ID of the node that the lint is being added to. The
-//! lint isn't actually emitted at that time because it is unknown what the
-//! actual lint level at that location is.
-//!
-//! To actually emit lint warnings/errors, a separate pass is used.
-//! A context keeps track of the current state of all lint levels.
-//! Upon entering a node of the ast which can modify the lint settings, the
-//! previous lint state is pushed onto a stack and the ast is then recursed
-//! upon. As the ast is traversed, this keeps track of the current lint level
-//! for all lint attributes.
+//! The late lint pass Works on HIR nodes, towards the end of analysis (after
+//! borrow checking, etc.). These lints have full type information available.
 
 use std::any::Any;
 use std::cell::Cell;
@@ -26,11 +15,12 @@
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_session::Session;
 use rustc_session::lint::LintPass;
+use rustc_session::lint::builtin::HardwiredLints;
 use rustc_span::Span;
 use tracing::debug;
 
 use crate::passes::LateLintPassObject;
-use crate::{LateContext, LateLintPass, LintStore};
+use crate::{LateContext, LateLintPass, LintId, LintStore};
 
 /// Extract the [`LintStore`] from [`Session`].
 ///
@@ -326,6 +316,9 @@
     fn name(&self) -> &'static str {
         panic!()
     }
+    fn get_lints(&self) -> crate::LintVec {
+        panic!()
+    }
 }
 
 macro_rules! impl_late_lint_pass {
@@ -361,13 +354,20 @@
     // Note: `passes` is often empty. In that case, it's faster to run
     // `builtin_lints` directly rather than bundling it up into the
     // `RuntimeCombinedLateLintPass`.
-    let late_module_passes = &unerased_lint_store(tcx.sess).late_module_passes;
-    if late_module_passes.is_empty() {
+    let store = unerased_lint_store(tcx.sess);
+
+    if store.late_module_passes.is_empty() {
         late_lint_mod_inner(tcx, module_def_id, context, builtin_lints);
     } else {
-        let mut passes: Vec<_> = late_module_passes.iter().map(|mk_pass| (mk_pass)(tcx)).collect();
-        passes.push(Box::new(builtin_lints));
-        let pass = RuntimeCombinedLateLintPass { passes: &mut passes[..] };
+        let builtin_lints = Box::new(builtin_lints) as Box<dyn LateLintPass<'tcx>>;
+        let mut binding = store
+            .late_module_passes
+            .iter()
+            .map(|mk_pass| (mk_pass)(tcx))
+            .chain(std::iter::once(builtin_lints))
+            .collect::<Vec<_>>();
+
+        let pass = RuntimeCombinedLateLintPass { passes: binding.as_mut_slice() };
         late_lint_mod_inner(tcx, module_def_id, context, pass);
     }
 }
@@ -398,7 +398,7 @@
 
 fn late_lint_crate<'tcx>(tcx: TyCtxt<'tcx>) {
     // Note: `passes` is often empty.
-    let mut passes: Vec<_> =
+    let passes: Vec<_> =
         unerased_lint_store(tcx.sess).late_passes.iter().map(|mk_pass| (mk_pass)(tcx)).collect();
 
     if passes.is_empty() {
@@ -416,7 +416,18 @@
         only_module: false,
     };
 
-    let pass = RuntimeCombinedLateLintPass { passes: &mut passes[..] };
+    let lints_that_dont_need_to_run = tcx.lints_that_dont_need_to_run(());
+
+    let mut filtered_passes: Vec<Box<dyn LateLintPass<'tcx>>> = passes
+        .into_iter()
+        .filter(|pass| {
+            let lints = (**pass).get_lints();
+            !lints.iter().all(|lint| lints_that_dont_need_to_run.contains(&LintId::of(lint)))
+        })
+        .collect();
+
+    filtered_passes.push(Box::new(HardwiredLints));
+    let pass = RuntimeCombinedLateLintPass { passes: &mut filtered_passes[..] };
     late_lint_crate_inner(tcx, context, pass);
 }
 
diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs
index 95a8e76..97a9578 100644
--- a/compiler/rustc_lint/src/levels.rs
+++ b/compiler/rustc_lint/src/levels.rs
@@ -1,9 +1,9 @@
 use rustc_ast_pretty::pprust;
-use rustc_data_structures::fx::FxIndexMap;
+use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
 use rustc_errors::{Diag, LintDiagnostic, MultiSpan};
 use rustc_feature::{Features, GateIssue};
-use rustc_hir::HirId;
 use rustc_hir::intravisit::{self, Visitor};
+use rustc_hir::{CRATE_HIR_ID, HirId};
 use rustc_index::IndexVec;
 use rustc_middle::bug;
 use rustc_middle::hir::nested_filter;
@@ -115,6 +115,38 @@
     }
 }
 
+fn lints_that_dont_need_to_run(tcx: TyCtxt<'_>, (): ()) -> FxIndexSet<LintId> {
+    let store = unerased_lint_store(&tcx.sess);
+
+    let map = tcx.shallow_lint_levels_on(rustc_hir::CRATE_OWNER_ID);
+
+    let dont_need_to_run: FxIndexSet<LintId> = store
+        .get_lints()
+        .into_iter()
+        .filter_map(|lint| {
+            if !lint.eval_always {
+                let lint_level = map.lint_level_id_at_node(tcx, LintId::of(lint), CRATE_HIR_ID);
+                if matches!(lint_level, (Level::Allow, ..))
+                    || (matches!(lint_level, (.., LintLevelSource::Default)))
+                        && lint.default_level(tcx.sess.edition()) == Level::Allow
+                {
+                    Some(LintId::of(lint))
+                } else {
+                    None
+                }
+            } else {
+                None
+            }
+        })
+        .collect();
+
+    let mut visitor = LintLevelMaximum { tcx, dont_need_to_run };
+    visitor.process_opts();
+    tcx.hir().walk_attributes(&mut visitor);
+
+    visitor.dont_need_to_run
+}
+
 #[instrument(level = "trace", skip(tcx), ret)]
 fn shallow_lint_levels_on(tcx: TyCtxt<'_>, owner: hir::OwnerId) -> ShallowLintLevelMap {
     let store = unerased_lint_store(tcx.sess);
@@ -301,6 +333,83 @@
     }
 }
 
+/// Visitor with the only function of visiting every item-like in a crate and
+/// computing the highest level that every lint gets put to.
+///
+/// E.g., if a crate has a global #![allow(lint)] attribute, but a single item
+/// uses #[warn(lint)], this visitor will set that lint level as `Warn`
+struct LintLevelMaximum<'tcx> {
+    tcx: TyCtxt<'tcx>,
+    /// The actual list of detected lints.
+    dont_need_to_run: FxIndexSet<LintId>,
+}
+
+impl<'tcx> LintLevelMaximum<'tcx> {
+    fn process_opts(&mut self) {
+        let store = unerased_lint_store(self.tcx.sess);
+        for (lint_group, level) in &self.tcx.sess.opts.lint_opts {
+            if *level != Level::Allow {
+                let Ok(lints) = store.find_lints(lint_group) else {
+                    return;
+                };
+                for lint in lints {
+                    self.dont_need_to_run.swap_remove(&lint);
+                }
+            }
+        }
+    }
+}
+
+impl<'tcx> Visitor<'tcx> for LintLevelMaximum<'tcx> {
+    type NestedFilter = nested_filter::All;
+
+    fn nested_visit_map(&mut self) -> Self::Map {
+        self.tcx.hir()
+    }
+
+    /// FIXME(blyxyas): In a future revision, we should also graph #![allow]s,
+    /// but that is handled with more care
+    fn visit_attribute(&mut self, attribute: &'tcx ast::Attribute) {
+        if matches!(
+            Level::from_attr(attribute),
+            Some(
+                Level::Warn
+                    | Level::Deny
+                    | Level::Forbid
+                    | Level::Expect(..)
+                    | Level::ForceWarn(..),
+            )
+        ) {
+            let store = unerased_lint_store(self.tcx.sess);
+            let Some(meta) = attribute.meta() else { return };
+            // Lint attributes are always a metalist inside a
+            // metalist (even with just one lint).
+            let Some(meta_item_list) = meta.meta_item_list() else { return };
+
+            for meta_list in meta_item_list {
+                // Convert Path to String
+                let Some(meta_item) = meta_list.meta_item() else { return };
+                let ident: &str = &meta_item
+                    .path
+                    .segments
+                    .iter()
+                    .map(|segment| segment.ident.as_str())
+                    .collect::<Vec<&str>>()
+                    .join("::");
+                let Ok(lints) = store.find_lints(
+                    // Lint attributes can only have literals
+                    ident,
+                ) else {
+                    return;
+                };
+                for lint in lints {
+                    self.dont_need_to_run.swap_remove(&lint);
+                }
+            }
+        }
+    }
+}
+
 pub struct LintLevelsBuilder<'s, P> {
     sess: &'s Session,
     features: &'s Features,
@@ -858,7 +967,7 @@
     #[track_caller]
     fn check_gated_lint(&self, lint_id: LintId, span: Span, lint_from_cli: bool) -> bool {
         let feature = if let Some(feature) = lint_id.lint.feature_gate
-            && !self.features.active(feature)
+            && !self.features.enabled(feature)
         {
             // Lint is behind a feature that is not enabled; eventually return false.
             feature
@@ -934,7 +1043,7 @@
 }
 
 pub(crate) fn provide(providers: &mut Providers) {
-    *providers = Providers { shallow_lint_levels_on, ..*providers };
+    *providers = Providers { shallow_lint_levels_on, lints_that_dont_need_to_run, ..*providers };
 }
 
 pub(crate) fn parse_lint_and_tool_name(lint_name: &str) -> (Option<Symbol>, &str) {
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index a7faab0..8611227 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -6,20 +6,14 @@
 //! other phases of the compiler, which are generally required to hold in order
 //! to compile the program at all.
 //!
-//! Most lints can be written as [LintPass] instances. These run after
+//! Most lints can be written as [`LintPass`] instances. These run after
 //! all other analyses. The `LintPass`es built into rustc are defined
 //! within [rustc_session::lint::builtin],
 //! which has further comments on how to add such a lint.
 //! rustc can also load external lint plugins, as is done for Clippy.
 //!
-//! Some of rustc's lints are defined elsewhere in the compiler and work by
-//! calling `add_lint()` on the overall `Session` object. This works when
-//! it happens before the main lint pass, which emits the lints stored by
-//! `add_lint()`. To emit lints after the main lint pass (from codegen, for
-//! example) requires more effort. See `emit_lint` and `GatherNodeLevels`
-//! in `context.rs`.
-//!
-//! Some code also exists in [rustc_session::lint], [rustc_middle::lint].
+//! See <https://rustc-dev-guide.rust-lang.org/diagnostics.html> for an
+//! overview of how lints are implemented.
 //!
 //! ## Note
 //!
@@ -46,6 +40,7 @@
 mod async_fn_in_trait;
 pub mod builtin;
 mod context;
+mod dangling;
 mod deref_into_dyn_supertrait;
 mod drop_forget_useless;
 mod early;
@@ -65,7 +60,6 @@
 mod lints;
 mod macro_expr_fragment_specifier_2024_migration;
 mod map_unit_fn;
-mod methods;
 mod multiple_supertrait_upcastable;
 mod non_ascii_idents;
 mod non_fmt_panic;
@@ -91,6 +85,7 @@
 use async_closures::AsyncClosureUsage;
 use async_fn_in_trait::AsyncFnInTrait;
 use builtin::*;
+use dangling::*;
 use deref_into_dyn_supertrait::*;
 use drop_forget_useless::*;
 use enum_intrinsics_non_enums::EnumIntrinsicsNonEnums;
@@ -103,7 +98,6 @@
 use let_underscore::*;
 use macro_expr_fragment_specifier_2024_migration::*;
 use map_unit_fn::*;
-use methods::*;
 use multiple_supertrait_upcastable::*;
 use non_ascii_idents::*;
 use non_fmt_panic::NonPanicFmt;
@@ -170,7 +164,7 @@
     [
         pub BuiltinCombinedEarlyLintPass,
         [
-            UnusedParens: UnusedParens::new(),
+            UnusedParens: UnusedParens::default(),
             UnusedBraces: UnusedBraces,
             UnusedImportBraces: UnusedImportBraces,
             UnsafeCode: UnsafeCode,
@@ -178,7 +172,7 @@
             AnonymousParameters: AnonymousParameters,
             EllipsisInclusiveRangePatterns: EllipsisInclusiveRangePatterns::default(),
             NonCamelCaseTypes: NonCamelCaseTypes,
-            DeprecatedAttr: DeprecatedAttr::new(),
+            DeprecatedAttr: DeprecatedAttr::default(),
             WhileTrue: WhileTrue,
             NonAsciiIdents: NonAsciiIdents,
             HiddenUnicodeCodepoints: HiddenUnicodeCodepoints,
@@ -199,7 +193,6 @@
             ForLoopsOverFallibles: ForLoopsOverFallibles,
             DerefIntoDynSupertrait: DerefIntoDynSupertrait,
             DropForgetUseless: DropForgetUseless,
-            HardwiredLints: HardwiredLints,
             ImproperCTypesDeclarations: ImproperCTypesDeclarations,
             ImproperCTypesDefinitions: ImproperCTypesDefinitions,
             InvalidFromUtf8: InvalidFromUtf8,
@@ -232,7 +225,7 @@
             UngatedAsyncFnTrackCaller: UngatedAsyncFnTrackCaller,
             ShadowedIntoIter: ShadowedIntoIter,
             DropTraitConstraints: DropTraitConstraints,
-            TemporaryCStringAsPtr: TemporaryCStringAsPtr,
+            DanglingPointers: DanglingPointers,
             NonPanicFmt: NonPanicFmt,
             NoopMethodCall: NoopMethodCall,
             EnumIntrinsicsNonEnums: EnumIntrinsicsNonEnums,
@@ -280,6 +273,7 @@
     store.register_lints(&BuiltinCombinedEarlyLintPass::get_lints());
     store.register_lints(&BuiltinCombinedModuleLateLintPass::get_lints());
     store.register_lints(&foreign_modules::get_lints());
+    store.register_lints(&HardwiredLints::lint_vec());
 
     add_lint_group!(
         "nonstandard_style",
@@ -356,6 +350,7 @@
     store.register_renamed("non_fmt_panic", "non_fmt_panics");
     store.register_renamed("unused_tuple_struct_fields", "dead_code");
     store.register_renamed("static_mut_ref", "static_mut_refs");
+    store.register_renamed("temporary_cstring_as_ptr", "dangling_pointers_from_temporaries");
 
     // These were moved to tool lints, but rustc still sees them when compiling normally, before
     // tool lints are registered, so `check_tool_name_for_backwards_compat` doesn't work. Use
@@ -602,25 +597,25 @@
 }
 
 fn register_internals(store: &mut LintStore) {
-    store.register_lints(&LintPassImpl::get_lints());
+    store.register_lints(&LintPassImpl::lint_vec());
     store.register_early_pass(|| Box::new(LintPassImpl));
-    store.register_lints(&DefaultHashTypes::get_lints());
+    store.register_lints(&DefaultHashTypes::lint_vec());
     store.register_late_mod_pass(|_| Box::new(DefaultHashTypes));
-    store.register_lints(&QueryStability::get_lints());
+    store.register_lints(&QueryStability::lint_vec());
     store.register_late_mod_pass(|_| Box::new(QueryStability));
-    store.register_lints(&ExistingDocKeyword::get_lints());
+    store.register_lints(&ExistingDocKeyword::lint_vec());
     store.register_late_mod_pass(|_| Box::new(ExistingDocKeyword));
-    store.register_lints(&TyTyKind::get_lints());
+    store.register_lints(&TyTyKind::lint_vec());
     store.register_late_mod_pass(|_| Box::new(TyTyKind));
-    store.register_lints(&TypeIr::get_lints());
+    store.register_lints(&TypeIr::lint_vec());
     store.register_late_mod_pass(|_| Box::new(TypeIr));
-    store.register_lints(&Diagnostics::get_lints());
+    store.register_lints(&Diagnostics::lint_vec());
     store.register_late_mod_pass(|_| Box::new(Diagnostics));
-    store.register_lints(&BadOptAccess::get_lints());
+    store.register_lints(&BadOptAccess::lint_vec());
     store.register_late_mod_pass(|_| Box::new(BadOptAccess));
-    store.register_lints(&PassByValue::get_lints());
+    store.register_lints(&PassByValue::lint_vec());
     store.register_late_mod_pass(|_| Box::new(PassByValue));
-    store.register_lints(&SpanUseEqCtxt::get_lints());
+    store.register_lints(&SpanUseEqCtxt::lint_vec());
     store.register_late_mod_pass(|_| Box::new(SpanUseEqCtxt));
     // FIXME(davidtwco): deliberately do not include `UNTRANSLATABLE_DIAGNOSTIC` and
     // `DIAGNOSTIC_OUTSIDE_OF_IMPL` here because `-Wrustc::internal` is provided to every crate and
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index 16cfae1..000f4b6 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -1137,16 +1137,19 @@
     pub name: Symbol,
 }
 
-// methods.rs
+// dangling.rs
 #[derive(LintDiagnostic)]
-#[diag(lint_cstring_ptr)]
+#[diag(lint_dangling_pointers_from_temporaries)]
 #[note]
 #[help]
-pub(crate) struct CStringPtr {
-    #[label(lint_as_ptr_label)]
-    pub as_ptr: Span,
-    #[label(lint_unwrap_label)]
-    pub unwrap: Span,
+// FIXME: put #[primary_span] on `ptr_span` once it does not cause conflicts
+pub(crate) struct DanglingPointersFromTemporaries<'tcx> {
+    pub callee: Symbol,
+    pub ty: Ty<'tcx>,
+    #[label(lint_label_ptr)]
+    pub ptr_span: Span,
+    #[label(lint_label_temporary)]
+    pub temporary_span: Span,
 }
 
 // multiple_supertrait_upcastable.rs
diff --git a/compiler/rustc_lint/src/methods.rs b/compiler/rustc_lint/src/methods.rs
deleted file mode 100644
index df22bf0..0000000
--- a/compiler/rustc_lint/src/methods.rs
+++ /dev/null
@@ -1,69 +0,0 @@
-use rustc_hir::{Expr, ExprKind};
-use rustc_middle::ty;
-use rustc_session::{declare_lint, declare_lint_pass};
-use rustc_span::Span;
-use rustc_span::symbol::sym;
-
-use crate::lints::CStringPtr;
-use crate::{LateContext, LateLintPass, LintContext};
-
-declare_lint! {
-    /// The `temporary_cstring_as_ptr` lint detects getting the inner pointer of
-    /// a temporary `CString`.
-    ///
-    /// ### Example
-    ///
-    /// ```rust
-    /// # #![allow(unused)]
-    /// # use std::ffi::CString;
-    /// let c_str = CString::new("foo").unwrap().as_ptr();
-    /// ```
-    ///
-    /// {{produces}}
-    ///
-    /// ### Explanation
-    ///
-    /// The inner pointer of a `CString` lives only as long as the `CString` it
-    /// points to. Getting the inner pointer of a *temporary* `CString` allows the `CString`
-    /// to be dropped at the end of the statement, as it is not being referenced as far as the
-    /// typesystem is concerned. This means outside of the statement the pointer will point to
-    /// freed memory, which causes undefined behavior if the pointer is later dereferenced.
-    pub TEMPORARY_CSTRING_AS_PTR,
-    Warn,
-    "detects getting the inner pointer of a temporary `CString`"
-}
-
-declare_lint_pass!(TemporaryCStringAsPtr => [TEMPORARY_CSTRING_AS_PTR]);
-
-impl<'tcx> LateLintPass<'tcx> for TemporaryCStringAsPtr {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if let ExprKind::MethodCall(as_ptr_path, as_ptr_receiver, ..) = expr.kind
-            && as_ptr_path.ident.name == sym::as_ptr
-            && let ExprKind::MethodCall(unwrap_path, unwrap_receiver, ..) = as_ptr_receiver.kind
-            && (unwrap_path.ident.name == sym::unwrap || unwrap_path.ident.name == sym::expect)
-        {
-            lint_cstring_as_ptr(cx, as_ptr_path.ident.span, unwrap_receiver, as_ptr_receiver);
-        }
-    }
-}
-
-fn lint_cstring_as_ptr(
-    cx: &LateContext<'_>,
-    as_ptr_span: Span,
-    source: &rustc_hir::Expr<'_>,
-    unwrap: &rustc_hir::Expr<'_>,
-) {
-    let source_type = cx.typeck_results().expr_ty(source);
-    if let ty::Adt(def, args) = source_type.kind() {
-        if cx.tcx.is_diagnostic_item(sym::Result, def.did()) {
-            if let ty::Adt(adt, _) = args.type_at(0).kind() {
-                if cx.tcx.is_diagnostic_item(sym::cstring_type, adt.did()) {
-                    cx.emit_span_lint(TEMPORARY_CSTRING_AS_PTR, as_ptr_span, CStringPtr {
-                        as_ptr: as_ptr_span,
-                        unwrap: unwrap.span,
-                    });
-                }
-            }
-        }
-    }
-}
diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs
index 83a8ca4..1c27e1d 100644
--- a/compiler/rustc_lint/src/nonstandard_style.rs
+++ b/compiler/rustc_lint/src/nonstandard_style.rs
@@ -542,11 +542,7 @@
     }
 
     fn check_generic_param(&mut self, cx: &LateContext<'_>, param: &hir::GenericParam<'_>) {
-        if let GenericParamKind::Const { is_host_effect, .. } = param.kind {
-            // `host` params are explicitly allowed to be lowercase.
-            if is_host_effect {
-                return;
-            }
+        if let GenericParamKind::Const { .. } = param.kind {
             NonUpperCaseGlobals::check_upper_case(cx, "const parameter", &param.name.ident());
         }
     }
diff --git a/compiler/rustc_lint/src/passes.rs b/compiler/rustc_lint/src/passes.rs
index a1d436e..9d84d36 100644
--- a/compiler/rustc_lint/src/passes.rs
+++ b/compiler/rustc_lint/src/passes.rs
@@ -110,7 +110,7 @@
 
             $v fn get_lints() -> $crate::LintVec {
                 let mut lints = Vec::new();
-                $(lints.extend_from_slice(&$pass::get_lints());)*
+                $(lints.extend_from_slice(&$pass::lint_vec());)*
                 lints
             }
         }
@@ -124,6 +124,9 @@
             fn name(&self) -> &'static str {
                 panic!()
             }
+            fn get_lints(&self) -> LintVec {
+                panic!()
+            }
         }
     )
 }
@@ -133,7 +136,7 @@
     ($macro:path, $args:tt) => (
         $macro!($args, [
             fn check_param(a: &rustc_ast::Param);
-            fn check_ident(a: rustc_span::symbol::Ident);
+            fn check_ident(a: &rustc_span::symbol::Ident);
             fn check_crate(a: &rustc_ast::Crate);
             fn check_crate_post(a: &rustc_ast::Crate);
             fn check_item(a: &rustc_ast::Item);
@@ -222,7 +225,7 @@
 
             $v fn get_lints() -> $crate::LintVec {
                 let mut lints = Vec::new();
-                $(lints.extend_from_slice(&$pass::get_lints());)*
+                $(lints.extend_from_slice(&$pass::lint_vec());)*
                 lints
             }
         }
@@ -236,6 +239,9 @@
             fn name(&self) -> &'static str {
                 panic!()
             }
+            fn get_lints(&self) -> LintVec {
+                panic!()
+            }
         }
     )
 }
diff --git a/compiler/rustc_lint/src/tail_expr_drop_order.rs b/compiler/rustc_lint/src/tail_expr_drop_order.rs
index 44a3614..8976305 100644
--- a/compiler/rustc_lint/src/tail_expr_drop_order.rs
+++ b/compiler/rustc_lint/src/tail_expr_drop_order.rs
@@ -14,15 +14,14 @@
 use crate::{LateContext, LateLintPass};
 
 declare_lint! {
-    /// The `tail_expr_drop_order` lint looks for those values generated at the tail expression location, that of type
-    /// with a significant `Drop` implementation, such as locks.
-    /// In case there are also local variables of type with significant `Drop` implementation as well,
-    /// this lint warns you of a potential transposition in the drop order.
-    /// Your discretion on the new drop order introduced by Edition 2024 is required.
+    /// The `tail_expr_drop_order` lint looks for those values generated at the tail expression location,
+    /// that runs a custom `Drop` destructor.
+    /// Some of them may be dropped earlier in Edition 2024 that they used to in Edition 2021 and prior.
+    /// This lint detects those cases and provides you information on those values and their custom destructor implementations.
+    /// Your discretion on this information is required.
     ///
     /// ### Example
-    /// ```rust,edition2024
-    /// #![feature(shorter_tail_lifetimes)]
+    /// ```rust,edition2021
     /// #![warn(tail_expr_drop_order)]
     /// struct Droppy(i32);
     /// impl Droppy {
@@ -37,12 +36,12 @@
     ///         println!("loud drop {}", self.0);
     ///     }
     /// }
-    /// fn edition_2024() -> i32 {
+    /// fn edition_2021() -> i32 {
     ///     let another_droppy = Droppy(0);
     ///     Droppy(1).get()
     /// }
     /// fn main() {
-    ///     edition_2024();
+    ///     edition_2021();
     /// }
     /// ```
     ///
@@ -137,7 +136,7 @@
         _: Span,
         def_id: rustc_span::def_id::LocalDefId,
     ) {
-        if cx.tcx.sess.at_least_rust_2024() && cx.tcx.features().shorter_tail_lifetimes {
+        if !body.value.span.edition().at_least_rust_2024() {
             Self::check_fn_or_closure(cx, fn_kind, body, def_id);
         }
     }
@@ -185,8 +184,8 @@
 
 impl<'a, 'tcx> LintVisitor<'a, 'tcx> {
     fn check_block_inner(&mut self, block: &Block<'tcx>) {
-        if !block.span.at_least_rust_2024() {
-            // We only lint for Edition 2024 onwards
+        if block.span.at_least_rust_2024() {
+            // We only lint up to Edition 2021
             return;
         }
         let Some(tail_expr) = block.expr else { return };
diff --git a/compiler/rustc_lint/src/traits.rs b/compiler/rustc_lint/src/traits.rs
index 5a3666d..b793ec6 100644
--- a/compiler/rustc_lint/src/traits.rs
+++ b/compiler/rustc_lint/src/traits.rs
@@ -114,10 +114,7 @@
         let hir::TyKind::TraitObject(bounds, _lifetime, _syntax) = &ty.kind else { return };
         for bound in &bounds[..] {
             let def_id = bound.trait_ref.trait_def_id();
-            if def_id.is_some_and(|def_id| cx.tcx.is_lang_item(def_id, LangItem::Drop))
-                // FIXME: ?Drop is not a thing.
-                && bound.modifiers != hir::TraitBoundModifier::Maybe
-            {
+            if def_id.is_some_and(|def_id| cx.tcx.is_lang_item(def_id, LangItem::Drop)) {
                 let Some(def_id) = cx.tcx.get_diagnostic_item(sym::needs_drop) else { return };
                 cx.emit_span_lint(DYN_DROP, bound.span, DropGlue { tcx: cx.tcx, def_id });
             }
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index 60ff925..0751d35 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -167,7 +167,7 @@
     "detects ambiguous wide pointer comparisons"
 }
 
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, Default)]
 pub(crate) struct TypeLimits {
     /// Id of the last visited negated expression
     negated_expr_id: Option<hir::HirId>,
diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs
index ddc18c7..bbb290c 100644
--- a/compiler/rustc_lint/src/unused.rs
+++ b/compiler/rustc_lint/src/unused.rs
@@ -1025,8 +1025,8 @@
     parens_in_cast_in_lt: Vec<ast::NodeId>,
 }
 
-impl UnusedParens {
-    pub(crate) fn new() -> Self {
+impl Default for UnusedParens {
+    fn default() -> Self {
         Self { with_self_ty_parens: false, parens_in_cast_in_lt: Vec::new() }
     }
 }
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index a4c49a1..06a3e4a6 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -377,7 +377,8 @@
     /// will not overflow.
     pub ARITHMETIC_OVERFLOW,
     Deny,
-    "arithmetic operation overflows"
+    "arithmetic operation overflows",
+    @eval_always = true
 }
 
 declare_lint! {
@@ -401,7 +402,8 @@
     /// `panic!` or `unreachable!` macro instead in case the panic is intended.
     pub UNCONDITIONAL_PANIC,
     Deny,
-    "operation will cause a panic at runtime"
+    "operation will cause a panic at runtime",
+    @eval_always = true
 }
 
 declare_lint! {
@@ -632,7 +634,8 @@
     /// is only available in a newer version.
     pub UNKNOWN_LINTS,
     Warn,
-    "unrecognized lint attribute"
+    "unrecognized lint attribute",
+    @eval_always = true
 }
 
 declare_lint! {
diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs
index c01fa5c..601784f 100644
--- a/compiler/rustc_lint_defs/src/lib.rs
+++ b/compiler/rustc_lint_defs/src/lib.rs
@@ -312,6 +312,10 @@
     pub feature_gate: Option<Symbol>,
 
     pub crate_level_only: bool,
+
+    /// `true` if this lint should not be filtered out under any circustamces
+    /// (e.g. the unknown_attributes lint)
+    pub eval_always: bool,
 }
 
 /// Extra information for a future incompatibility lint.
@@ -456,6 +460,7 @@
             future_incompatible: None,
             feature_gate: None,
             crate_level_only: false,
+            eval_always: false,
         }
     }
 
@@ -864,6 +869,7 @@
         );
     );
     ($(#[$attr:meta])* $vis: vis $NAME: ident, $Level: ident, $desc: expr,
+     $(@eval_always = $eval_always:literal)?
      $(@feature_gate = $gate:ident;)?
      $(@future_incompatible = FutureIncompatibleInfo {
         reason: $reason:expr,
@@ -885,6 +891,7 @@
                 ..$crate::FutureIncompatibleInfo::default_fields_for_macro()
             }),)?
             $(edition_lint_opts: Some(($crate::Edition::$lint_edition, $crate::$edition_level)),)?
+            $(eval_always: $eval_always,)?
             ..$crate::Lint::default_fields_for_macro()
         };
     );
@@ -894,20 +901,23 @@
 macro_rules! declare_tool_lint {
     (
         $(#[$attr:meta])* $vis:vis $tool:ident ::$NAME:ident, $Level: ident, $desc: expr
+        $(, @eval_always = $eval_always:literal)?
         $(, @feature_gate = $gate:ident;)?
     ) => (
-        $crate::declare_tool_lint!{$(#[$attr])* $vis $tool::$NAME, $Level, $desc, false $(, @feature_gate = $gate;)?}
+        $crate::declare_tool_lint!{$(#[$attr])* $vis $tool::$NAME, $Level, $desc, false $(, @eval_always = $eval_always)? $(, @feature_gate = $gate;)?}
     );
     (
         $(#[$attr:meta])* $vis:vis $tool:ident ::$NAME:ident, $Level:ident, $desc:expr,
         report_in_external_macro: $rep:expr
+        $(, @eval_always = $eval_always: literal)?
         $(, @feature_gate = $gate:ident;)?
     ) => (
-         $crate::declare_tool_lint!{$(#[$attr])* $vis $tool::$NAME, $Level, $desc, $rep $(, @feature_gate = $gate;)?}
+         $crate::declare_tool_lint!{$(#[$attr])* $vis $tool::$NAME, $Level, $desc, $rep  $(, @eval_always = $eval_always)? $(, @feature_gate = $gate;)?}
     );
     (
         $(#[$attr:meta])* $vis:vis $tool:ident ::$NAME:ident, $Level:ident, $desc:expr,
         $external:expr
+        $(, @eval_always = $eval_always: literal)?
         $(, @feature_gate = $gate:ident;)?
     ) => (
         $(#[$attr])*
@@ -921,6 +931,7 @@
             is_externally_loaded: true,
             $(feature_gate: Some(rustc_span::symbol::sym::$gate),)?
             crate_level_only: false,
+            $(eval_always: $eval_always,)?
             ..$crate::Lint::default_fields_for_macro()
         };
     );
@@ -930,6 +941,7 @@
 
 pub trait LintPass {
     fn name(&self) -> &'static str;
+    fn get_lints(&self) -> LintVec;
 }
 
 /// Implements `LintPass for $ty` with the given list of `Lint` statics.
@@ -938,9 +950,11 @@
     ($ty:ty => [$($lint:expr),* $(,)?]) => {
         impl $crate::LintPass for $ty {
             fn name(&self) -> &'static str { stringify!($ty) }
+            fn get_lints(&self) -> $crate::LintVec { vec![$($lint),*] }
         }
         impl $ty {
-            pub fn get_lints() -> $crate::LintVec { vec![$($lint),*] }
+            #[allow(unused)]
+            pub fn lint_vec() -> $crate::LintVec { vec![$($lint),*] }
         }
     };
 }
diff --git a/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp
index cda81d4..b32af5e 100644
--- a/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp
@@ -33,45 +33,6 @@
   report_fatal_error("Bad LLVMRustCounterKind!");
 }
 
-// FFI equivalent of enum `llvm::coverage::CounterMappingRegion::RegionKind`
-// https://github.com/rust-lang/llvm-project/blob/ea6fa9c2/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L213-L234
-enum class LLVMRustCounterMappingRegionKind {
-  CodeRegion = 0,
-  ExpansionRegion = 1,
-  SkippedRegion = 2,
-  GapRegion = 3,
-  BranchRegion = 4,
-  MCDCDecisionRegion = 5,
-  MCDCBranchRegion = 6
-};
-
-static coverage::CounterMappingRegion::RegionKind
-fromRust(LLVMRustCounterMappingRegionKind Kind) {
-  switch (Kind) {
-  case LLVMRustCounterMappingRegionKind::CodeRegion:
-    return coverage::CounterMappingRegion::CodeRegion;
-  case LLVMRustCounterMappingRegionKind::ExpansionRegion:
-    return coverage::CounterMappingRegion::ExpansionRegion;
-  case LLVMRustCounterMappingRegionKind::SkippedRegion:
-    return coverage::CounterMappingRegion::SkippedRegion;
-  case LLVMRustCounterMappingRegionKind::GapRegion:
-    return coverage::CounterMappingRegion::GapRegion;
-  case LLVMRustCounterMappingRegionKind::BranchRegion:
-    return coverage::CounterMappingRegion::BranchRegion;
-  case LLVMRustCounterMappingRegionKind::MCDCDecisionRegion:
-    return coverage::CounterMappingRegion::MCDCDecisionRegion;
-  case LLVMRustCounterMappingRegionKind::MCDCBranchRegion:
-    return coverage::CounterMappingRegion::MCDCBranchRegion;
-  }
-  report_fatal_error("Bad LLVMRustCounterMappingRegionKind!");
-}
-
-enum LLVMRustMCDCParametersTag {
-  None = 0,
-  Decision = 1,
-  Branch = 2,
-};
-
 struct LLVMRustMCDCDecisionParameters {
   uint32_t BitmapIdx;
   uint16_t NumConditions;
@@ -82,47 +43,58 @@
   int16_t ConditionIDs[2];
 };
 
-struct LLVMRustMCDCParameters {
-  LLVMRustMCDCParametersTag Tag;
-  LLVMRustMCDCDecisionParameters DecisionParameters;
-  LLVMRustMCDCBranchParameters BranchParameters;
-};
-
 #if LLVM_VERSION_GE(19, 0)
-static coverage::mcdc::Parameters fromRust(LLVMRustMCDCParameters Params) {
-  switch (Params.Tag) {
-  case LLVMRustMCDCParametersTag::None:
-    return std::monostate();
-  case LLVMRustMCDCParametersTag::Decision:
-    return coverage::mcdc::DecisionParameters(
-        Params.DecisionParameters.BitmapIdx,
-        Params.DecisionParameters.NumConditions);
-  case LLVMRustMCDCParametersTag::Branch:
-    return coverage::mcdc::BranchParameters(
-        static_cast<coverage::mcdc::ConditionID>(
-            Params.BranchParameters.ConditionID),
-        {static_cast<coverage::mcdc::ConditionID>(
-             Params.BranchParameters.ConditionIDs[0]),
-         static_cast<coverage::mcdc::ConditionID>(
-             Params.BranchParameters.ConditionIDs[1])});
-  }
-  report_fatal_error("Bad LLVMRustMCDCParametersTag!");
+static coverage::mcdc::BranchParameters
+fromRust(LLVMRustMCDCBranchParameters Params) {
+  return coverage::mcdc::BranchParameters(
+      Params.ConditionID, {Params.ConditionIDs[0], Params.ConditionIDs[1]});
+}
+
+static coverage::mcdc::DecisionParameters
+fromRust(LLVMRustMCDCDecisionParameters Params) {
+  return coverage::mcdc::DecisionParameters(Params.BitmapIdx,
+                                            Params.NumConditions);
 }
 #endif
 
-// FFI equivalent of struct `llvm::coverage::CounterMappingRegion`
-// https://github.com/rust-lang/llvm-project/blob/ea6fa9c2/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L211-L304
-struct LLVMRustCounterMappingRegion {
-  LLVMRustCounter Count;
-  LLVMRustCounter FalseCount;
-  LLVMRustMCDCParameters MCDCParameters;
+// Must match the layout of
+// `rustc_codegen_llvm::coverageinfo::ffi::CoverageSpan`.
+struct LLVMRustCoverageSpan {
   uint32_t FileID;
-  uint32_t ExpandedFileID;
   uint32_t LineStart;
   uint32_t ColumnStart;
   uint32_t LineEnd;
   uint32_t ColumnEnd;
-  LLVMRustCounterMappingRegionKind Kind;
+};
+
+// Must match the layout of `rustc_codegen_llvm::coverageinfo::ffi::CodeRegion`.
+struct LLVMRustCoverageCodeRegion {
+  LLVMRustCoverageSpan Span;
+  LLVMRustCounter Count;
+};
+
+// Must match the layout of
+// `rustc_codegen_llvm::coverageinfo::ffi::BranchRegion`.
+struct LLVMRustCoverageBranchRegion {
+  LLVMRustCoverageSpan Span;
+  LLVMRustCounter TrueCount;
+  LLVMRustCounter FalseCount;
+};
+
+// Must match the layout of
+// `rustc_codegen_llvm::coverageinfo::ffi::MCDCBranchRegion`.
+struct LLVMRustCoverageMCDCBranchRegion {
+  LLVMRustCoverageSpan Span;
+  LLVMRustCounter TrueCount;
+  LLVMRustCounter FalseCount;
+  LLVMRustMCDCBranchParameters MCDCBranchParams;
+};
+
+// Must match the layout of
+// `rustc_codegen_llvm::coverageinfo::ffi::MCDCDecisionRegion`.
+struct LLVMRustCoverageMCDCDecisionRegion {
+  LLVMRustCoverageSpan Span;
+  LLVMRustMCDCDecisionParameters MCDCDecisionParams;
 };
 
 // FFI equivalent of enum `llvm::coverage::CounterExpression::ExprKind`
@@ -174,28 +146,16 @@
 extern "C" void LLVMRustCoverageWriteMappingToBuffer(
     const unsigned *VirtualFileMappingIDs, unsigned NumVirtualFileMappingIDs,
     const LLVMRustCounterExpression *RustExpressions, unsigned NumExpressions,
-    const LLVMRustCounterMappingRegion *RustMappingRegions,
-    unsigned NumMappingRegions, RustStringRef BufferOut) {
+    const LLVMRustCoverageCodeRegion *CodeRegions, unsigned NumCodeRegions,
+    const LLVMRustCoverageBranchRegion *BranchRegions,
+    unsigned NumBranchRegions,
+    const LLVMRustCoverageMCDCBranchRegion *MCDCBranchRegions,
+    unsigned NumMCDCBranchRegions,
+    const LLVMRustCoverageMCDCDecisionRegion *MCDCDecisionRegions,
+    unsigned NumMCDCDecisionRegions, RustStringRef BufferOut) {
   // Convert from FFI representation to LLVM representation.
-  SmallVector<coverage::CounterMappingRegion, 0> MappingRegions;
-  MappingRegions.reserve(NumMappingRegions);
-  for (const auto &Region : ArrayRef<LLVMRustCounterMappingRegion>(
-           RustMappingRegions, NumMappingRegions)) {
-    MappingRegions.emplace_back(
-        fromRust(Region.Count), fromRust(Region.FalseCount),
-#if LLVM_VERSION_LT(19, 0)
-        coverage::CounterMappingRegion::MCDCParameters{},
-#endif
-        Region.FileID, Region.ExpandedFileID, // File IDs, then region info.
-        Region.LineStart, Region.ColumnStart, Region.LineEnd, Region.ColumnEnd,
-        fromRust(Region.Kind)
-#if LLVM_VERSION_GE(19, 0)
-            ,
-        fromRust(Region.MCDCParameters)
-#endif
-    );
-  }
 
+  // Expressions:
   std::vector<coverage::CounterExpression> Expressions;
   Expressions.reserve(NumExpressions);
   for (const auto &Expression :
@@ -205,6 +165,46 @@
                              fromRust(Expression.RHS));
   }
 
+  std::vector<coverage::CounterMappingRegion> MappingRegions;
+  MappingRegions.reserve(NumCodeRegions + NumBranchRegions +
+                         NumMCDCBranchRegions + NumMCDCDecisionRegions);
+
+  // Code regions:
+  for (const auto &Region : ArrayRef(CodeRegions, NumCodeRegions)) {
+    MappingRegions.push_back(coverage::CounterMappingRegion::makeRegion(
+        fromRust(Region.Count), Region.Span.FileID, Region.Span.LineStart,
+        Region.Span.ColumnStart, Region.Span.LineEnd, Region.Span.ColumnEnd));
+  }
+
+  // Branch regions:
+  for (const auto &Region : ArrayRef(BranchRegions, NumBranchRegions)) {
+    MappingRegions.push_back(coverage::CounterMappingRegion::makeBranchRegion(
+        fromRust(Region.TrueCount), fromRust(Region.FalseCount),
+        Region.Span.FileID, Region.Span.LineStart, Region.Span.ColumnStart,
+        Region.Span.LineEnd, Region.Span.ColumnEnd));
+  }
+
+#if LLVM_VERSION_GE(19, 0)
+  // MC/DC branch regions:
+  for (const auto &Region : ArrayRef(MCDCBranchRegions, NumMCDCBranchRegions)) {
+    MappingRegions.push_back(coverage::CounterMappingRegion::makeBranchRegion(
+        fromRust(Region.TrueCount), fromRust(Region.FalseCount),
+        Region.Span.FileID, Region.Span.LineStart, Region.Span.ColumnStart,
+        Region.Span.LineEnd, Region.Span.ColumnEnd,
+        fromRust(Region.MCDCBranchParams)));
+  }
+
+  // MC/DC decision regions:
+  for (const auto &Region :
+       ArrayRef(MCDCDecisionRegions, NumMCDCDecisionRegions)) {
+    MappingRegions.push_back(coverage::CounterMappingRegion::makeDecisionRegion(
+        fromRust(Region.MCDCDecisionParams), Region.Span.FileID,
+        Region.Span.LineStart, Region.Span.ColumnStart, Region.Span.LineEnd,
+        Region.Span.ColumnEnd));
+  }
+#endif
+
+  // Write the converted expressions and mappings to a byte buffer.
   auto CoverageMappingWriter = coverage::CoverageMappingWriter(
       ArrayRef<unsigned>(VirtualFileMappingIDs, NumVirtualFileMappingIDs),
       Expressions, MappingRegions);
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index 910c27d..9f94163 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -1531,45 +1531,6 @@
                                     ArrayRef<OperandBundleDef>(OpBundles)));
 }
 
-extern "C" LLVMValueRef
-LLVMRustGetInstrProfIncrementIntrinsic(LLVMModuleRef M) {
-#if LLVM_VERSION_GE(20, 0)
-  return wrap(llvm::Intrinsic::getOrInsertDeclaration(
-      unwrap(M), llvm::Intrinsic::instrprof_increment));
-#else
-  return wrap(llvm::Intrinsic::getDeclaration(
-      unwrap(M), llvm::Intrinsic::instrprof_increment));
-#endif
-}
-
-extern "C" LLVMValueRef
-LLVMRustGetInstrProfMCDCParametersIntrinsic(LLVMModuleRef M) {
-#if LLVM_VERSION_LT(19, 0)
-  report_fatal_error("LLVM 19.0 is required for mcdc intrinsic functions");
-#endif
-#if LLVM_VERSION_GE(20, 0)
-  return wrap(llvm::Intrinsic::getOrInsertDeclaration(
-      unwrap(M), llvm::Intrinsic::instrprof_mcdc_parameters));
-#else
-  return wrap(llvm::Intrinsic::getDeclaration(
-      unwrap(M), llvm::Intrinsic::instrprof_mcdc_parameters));
-#endif
-}
-
-extern "C" LLVMValueRef
-LLVMRustGetInstrProfMCDCTVBitmapUpdateIntrinsic(LLVMModuleRef M) {
-#if LLVM_VERSION_LT(19, 0)
-  report_fatal_error("LLVM 19.0 is required for mcdc intrinsic functions");
-#endif
-#if LLVM_VERSION_GE(20, 0)
-  return wrap(llvm::Intrinsic::getOrInsertDeclaration(
-      unwrap(M), llvm::Intrinsic::instrprof_mcdc_tvbitmap_update));
-#else
-  return wrap(llvm::Intrinsic::getDeclaration(
-      unwrap(M), llvm::Intrinsic::instrprof_mcdc_tvbitmap_update));
-#endif
-}
-
 extern "C" LLVMValueRef LLVMRustBuildMemCpy(LLVMBuilderRef B, LLVMValueRef Dst,
                                             unsigned DstAlign, LLVMValueRef Src,
                                             unsigned SrcAlign,
@@ -1658,86 +1619,6 @@
   unwrap(B)->SetInsertPoint(unwrap(BB), Point);
 }
 
-enum class LLVMRustLinkage {
-  ExternalLinkage = 0,
-  AvailableExternallyLinkage = 1,
-  LinkOnceAnyLinkage = 2,
-  LinkOnceODRLinkage = 3,
-  WeakAnyLinkage = 4,
-  WeakODRLinkage = 5,
-  AppendingLinkage = 6,
-  InternalLinkage = 7,
-  PrivateLinkage = 8,
-  ExternalWeakLinkage = 9,
-  CommonLinkage = 10,
-};
-
-static LLVMRustLinkage toRust(LLVMLinkage Linkage) {
-  switch (Linkage) {
-  case LLVMExternalLinkage:
-    return LLVMRustLinkage::ExternalLinkage;
-  case LLVMAvailableExternallyLinkage:
-    return LLVMRustLinkage::AvailableExternallyLinkage;
-  case LLVMLinkOnceAnyLinkage:
-    return LLVMRustLinkage::LinkOnceAnyLinkage;
-  case LLVMLinkOnceODRLinkage:
-    return LLVMRustLinkage::LinkOnceODRLinkage;
-  case LLVMWeakAnyLinkage:
-    return LLVMRustLinkage::WeakAnyLinkage;
-  case LLVMWeakODRLinkage:
-    return LLVMRustLinkage::WeakODRLinkage;
-  case LLVMAppendingLinkage:
-    return LLVMRustLinkage::AppendingLinkage;
-  case LLVMInternalLinkage:
-    return LLVMRustLinkage::InternalLinkage;
-  case LLVMPrivateLinkage:
-    return LLVMRustLinkage::PrivateLinkage;
-  case LLVMExternalWeakLinkage:
-    return LLVMRustLinkage::ExternalWeakLinkage;
-  case LLVMCommonLinkage:
-    return LLVMRustLinkage::CommonLinkage;
-  default:
-    report_fatal_error("Invalid LLVMRustLinkage value!");
-  }
-}
-
-static LLVMLinkage fromRust(LLVMRustLinkage Linkage) {
-  switch (Linkage) {
-  case LLVMRustLinkage::ExternalLinkage:
-    return LLVMExternalLinkage;
-  case LLVMRustLinkage::AvailableExternallyLinkage:
-    return LLVMAvailableExternallyLinkage;
-  case LLVMRustLinkage::LinkOnceAnyLinkage:
-    return LLVMLinkOnceAnyLinkage;
-  case LLVMRustLinkage::LinkOnceODRLinkage:
-    return LLVMLinkOnceODRLinkage;
-  case LLVMRustLinkage::WeakAnyLinkage:
-    return LLVMWeakAnyLinkage;
-  case LLVMRustLinkage::WeakODRLinkage:
-    return LLVMWeakODRLinkage;
-  case LLVMRustLinkage::AppendingLinkage:
-    return LLVMAppendingLinkage;
-  case LLVMRustLinkage::InternalLinkage:
-    return LLVMInternalLinkage;
-  case LLVMRustLinkage::PrivateLinkage:
-    return LLVMPrivateLinkage;
-  case LLVMRustLinkage::ExternalWeakLinkage:
-    return LLVMExternalWeakLinkage;
-  case LLVMRustLinkage::CommonLinkage:
-    return LLVMCommonLinkage;
-  }
-  report_fatal_error("Invalid LLVMRustLinkage value!");
-}
-
-extern "C" LLVMRustLinkage LLVMRustGetLinkage(LLVMValueRef V) {
-  return toRust(LLVMGetLinkage(V));
-}
-
-extern "C" void LLVMRustSetLinkage(LLVMValueRef V,
-                                   LLVMRustLinkage RustLinkage) {
-  LLVMSetLinkage(V, fromRust(RustLinkage));
-}
-
 extern "C" bool LLVMRustConstIntGetZExtValue(LLVMValueRef CV, uint64_t *value) {
   auto C = unwrap<llvm::ConstantInt>(CV);
   if (C->getBitWidth() > 64)
@@ -1765,45 +1646,6 @@
   return true;
 }
 
-enum class LLVMRustVisibility {
-  Default = 0,
-  Hidden = 1,
-  Protected = 2,
-};
-
-static LLVMRustVisibility toRust(LLVMVisibility Vis) {
-  switch (Vis) {
-  case LLVMDefaultVisibility:
-    return LLVMRustVisibility::Default;
-  case LLVMHiddenVisibility:
-    return LLVMRustVisibility::Hidden;
-  case LLVMProtectedVisibility:
-    return LLVMRustVisibility::Protected;
-  }
-  report_fatal_error("Invalid LLVMRustVisibility value!");
-}
-
-static LLVMVisibility fromRust(LLVMRustVisibility Vis) {
-  switch (Vis) {
-  case LLVMRustVisibility::Default:
-    return LLVMDefaultVisibility;
-  case LLVMRustVisibility::Hidden:
-    return LLVMHiddenVisibility;
-  case LLVMRustVisibility::Protected:
-    return LLVMProtectedVisibility;
-  }
-  report_fatal_error("Invalid LLVMRustVisibility value!");
-}
-
-extern "C" LLVMRustVisibility LLVMRustGetVisibility(LLVMValueRef V) {
-  return toRust(LLVMGetVisibility(V));
-}
-
-extern "C" void LLVMRustSetVisibility(LLVMValueRef V,
-                                      LLVMRustVisibility RustVisibility) {
-  LLVMSetVisibility(V, fromRust(RustVisibility));
-}
-
 extern "C" void LLVMRustSetDSOLocal(LLVMValueRef Global, bool is_dso_local) {
   unwrap<GlobalValue>(Global)->setDSOLocal(is_dso_local);
 }
diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
index 72f1e59..1055f27 100644
--- a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
+++ b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
@@ -253,7 +253,10 @@
         let mut field_binding = binding_info.binding.clone();
         field_binding.set_span(field.ty.span());
 
-        let ident = field.ident.as_ref().unwrap();
+        let Some(ident) = field.ident.as_ref() else {
+            span_err(field.span().unwrap(), "tuple structs are not supported").emit();
+            return TokenStream::new();
+        };
         let ident = format_ident!("{}", ident); // strip `r#` prefix, if present
 
         quote! {
diff --git a/compiler/rustc_macros/src/diagnostics/error.rs b/compiler/rustc_macros/src/diagnostics/error.rs
index 9cdb9fb..a78cf2b 100644
--- a/compiler/rustc_macros/src/diagnostics/error.rs
+++ b/compiler/rustc_macros/src/diagnostics/error.rs
@@ -56,7 +56,7 @@
 /// Returns an error diagnostic on span `span` with msg `msg`.
 #[must_use]
 pub(crate) fn span_err<T: Into<String>>(span: impl MultiSpan, msg: T) -> Diagnostic {
-    Diagnostic::spanned(span, Level::Error, msg)
+    Diagnostic::spanned(span, Level::Error, format!("derive(Diagnostic): {}", msg.into()))
 }
 
 /// Emit a diagnostic on span `$span` with msg `$msg` (optionally performing additional decoration
diff --git a/compiler/rustc_macros/src/diagnostics/utils.rs b/compiler/rustc_macros/src/diagnostics/utils.rs
index 5946b11..612a36b 100644
--- a/compiler/rustc_macros/src/diagnostics/utils.rs
+++ b/compiler/rustc_macros/src/diagnostics/utils.rs
@@ -243,7 +243,7 @@
                 *self = Some((value, span));
             }
             Some((_, prev_span)) => {
-                span_err(span, "specified multiple times")
+                span_err(span, "attribute specified multiple times")
                     .span_note(*prev_span, "previously specified here")
                     .emit();
             }
diff --git a/compiler/rustc_macros/src/lib.rs b/compiler/rustc_macros/src/lib.rs
index f46c795..0df674e 100644
--- a/compiler/rustc_macros/src/lib.rs
+++ b/compiler/rustc_macros/src/lib.rs
@@ -20,6 +20,7 @@
 mod query;
 mod serialize;
 mod symbols;
+mod try_from;
 mod type_foldable;
 mod type_visitable;
 
@@ -165,3 +166,12 @@
         suggestion_part,
         applicability)] => diagnostics::subdiagnostic_derive
 );
+
+decl_derive! {
+    [TryFromU32] =>
+    /// Derives `TryFrom<u32>` for the annotated `enum`, which must have no fields.
+    /// Each variant maps to the value it would produce under an `as u32` cast.
+    ///
+    /// The error type is `u32`.
+    try_from::try_from_u32
+}
diff --git a/compiler/rustc_macros/src/try_from.rs b/compiler/rustc_macros/src/try_from.rs
new file mode 100644
index 0000000..9338c1c
--- /dev/null
+++ b/compiler/rustc_macros/src/try_from.rs
@@ -0,0 +1,55 @@
+use proc_macro2::TokenStream;
+use quote::{quote, quote_spanned};
+use syn::Data;
+use syn::spanned::Spanned;
+use synstructure::Structure;
+
+pub(crate) fn try_from_u32(s: Structure<'_>) -> TokenStream {
+    let span_error = |span, message: &str| {
+        quote_spanned! { span => const _: () = ::core::compile_error!(#message); }
+    };
+
+    // Must be applied to an enum type.
+    if let Some(span) = match &s.ast().data {
+        Data::Enum(_) => None,
+        Data::Struct(s) => Some(s.struct_token.span()),
+        Data::Union(u) => Some(u.union_token.span()),
+    } {
+        return span_error(span, "type is not an enum (TryFromU32)");
+    }
+
+    // The enum's variants must not have fields.
+    let variant_field_errors = s
+        .variants()
+        .iter()
+        .filter_map(|v| v.ast().fields.iter().map(|f| f.span()).next())
+        .map(|span| span_error(span, "enum variant cannot have fields (TryFromU32)"))
+        .collect::<TokenStream>();
+    if !variant_field_errors.is_empty() {
+        return variant_field_errors;
+    }
+
+    let ctor = s
+        .variants()
+        .iter()
+        .map(|v| v.construct(|_, _| -> TokenStream { unreachable!() }))
+        .collect::<Vec<_>>();
+    // FIXME(edition_2024): Fix the `keyword_idents_2024` lint to not trigger here?
+    #[allow(keyword_idents_2024)]
+    s.gen_impl(quote! {
+        // The surrounding code might have shadowed these identifiers.
+        use ::core::convert::TryFrom;
+        use ::core::primitive::u32;
+        use ::core::result::Result::{self, Ok, Err};
+
+        gen impl TryFrom<u32> for @Self {
+            type Error = u32;
+
+            #[allow(deprecated)] // Don't warn about deprecated variants.
+            fn try_from(value: u32) -> Result<Self, Self::Error> {
+                #( if value == const { #ctor as u32 } { return Ok(#ctor) } )*
+                Err(value)
+            }
+        }
+    })
+}
diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs
index 8adec75..1662391 100644
--- a/compiler/rustc_metadata/src/creader.rs
+++ b/compiler/rustc_metadata/src/creader.rs
@@ -28,7 +28,7 @@
 use rustc_session::output::validate_crate_name;
 use rustc_session::search_paths::PathKind;
 use rustc_span::edition::Edition;
-use rustc_span::symbol::{Symbol, sym};
+use rustc_span::symbol::{Ident, Symbol, sym};
 use rustc_span::{DUMMY_SP, Span};
 use rustc_target::spec::{PanicStrategy, Target, TargetTriple};
 use tracing::{debug, info, trace};
@@ -97,7 +97,7 @@
 }
 
 pub enum LoadedMacro {
-    MacroDef(ast::Item, Edition),
+    MacroDef { def: MacroDef, ident: Ident, attrs: AttrVec, span: Span, edition: Edition },
     ProcMacro(SyntaxExtension),
 }
 
diff --git a/compiler/rustc_metadata/src/dependency_format.rs b/compiler/rustc_metadata/src/dependency_format.rs
index 39fa237..641d1d8 100644
--- a/compiler/rustc_metadata/src/dependency_format.rs
+++ b/compiler/rustc_metadata/src/dependency_format.rs
@@ -170,7 +170,7 @@
 
     let mut upstream_in_dylibs = FxHashSet::default();
 
-    if tcx.features().rustc_private {
+    if tcx.features().rustc_private() {
         // We need this to prevent users of `rustc_driver` from linking dynamically to `std`
         // which does not work as `std` is also statically linked into `rustc_driver`.
 
diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs
index c7953d5..1e6bc41 100644
--- a/compiler/rustc_metadata/src/native_libs.rs
+++ b/compiler/rustc_metadata/src/native_libs.rs
@@ -265,7 +265,7 @@
                                 NativeLibKind::RawDylib
                             }
                             "link-arg" => {
-                                if !features.link_arg_attribute {
+                                if !features.link_arg_attribute() {
                                     feature_err(
                                         sess,
                                         sym::link_arg_attribute,
@@ -314,7 +314,7 @@
                                 .emit_err(errors::LinkCfgSinglePredicate { span: item.span() });
                             continue;
                         };
-                        if !features.link_cfg {
+                        if !features.link_cfg() {
                             feature_err(
                                 sess,
                                 sym::link_cfg,
@@ -384,7 +384,7 @@
                     };
 
                     macro report_unstable_modifier($feature: ident) {
-                        if !features.$feature {
+                        if !features.$feature() {
                             // FIXME: make this translatable
                             #[expect(rustc::untranslatable_diagnostic)]
                             feature_err(
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index 7bb4099..926eb4f 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -1,7 +1,6 @@
 use std::any::Any;
 use std::mem;
 
-use rustc_ast as ast;
 use rustc_attr::Deprecation;
 use rustc_data_structures::sync::Lrc;
 use rustc_hir::def::{CtorKind, DefKind, Res};
@@ -275,6 +274,8 @@
     impl_parent => { table }
     defaultness => { table_direct }
     constness => { table_direct }
+    const_conditions => { table }
+    implied_const_bounds => { table_defaulted_array }
     coerce_unsized_info => {
         Ok(cdata
             .root
@@ -330,7 +331,6 @@
             .process_decoded(tcx, || panic!("{def_id:?} does not have trait_impl_trait_tys")))
     }
 
-    associated_type_for_effects => { table }
     associated_types_for_impl_traits_in_associated_fn => { table_defaulted_array }
 
     visibility => { cdata.get_visibility(def_id.index) }
@@ -591,27 +591,16 @@
 
         let data = self.get_crate_data(id.krate);
         if data.root.is_proc_macro_crate() {
-            return LoadedMacro::ProcMacro(data.load_proc_macro(id.index, tcx));
-        }
-
-        let span = data.get_span(id.index, sess);
-
-        LoadedMacro::MacroDef(
-            ast::Item {
+            LoadedMacro::ProcMacro(data.load_proc_macro(id.index, tcx))
+        } else {
+            LoadedMacro::MacroDef {
+                def: data.get_macro(id.index, sess),
                 ident: data.item_ident(id.index, sess),
-                id: ast::DUMMY_NODE_ID,
-                span,
                 attrs: data.get_item_attrs(id.index, sess).collect(),
-                kind: ast::ItemKind::MacroDef(data.get_macro(id.index, sess)),
-                vis: ast::Visibility {
-                    span: span.shrink_to_lo(),
-                    kind: ast::VisibilityKind::Inherited,
-                    tokens: None,
-                },
-                tokens: None,
-            },
-            data.root.edition,
-        )
+                span: data.get_span(id.index, sess),
+                edition: data.root.edition,
+            }
+        }
     }
 
     pub fn def_span_untracked(&self, def_id: DefId, sess: &Session) -> Span {
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index afe0353..47f7a8b 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -1081,7 +1081,7 @@
                     && (generics.requires_monomorphization(tcx)
                         || tcx.cross_crate_inlinable(def_id)));
             // The function has a `const` modifier or is in a `#[const_trait]`.
-            let is_const_fn = tcx.is_const_fn_raw(def_id.to_def_id())
+            let is_const_fn = tcx.is_const_fn(def_id.to_def_id())
                 || tcx.is_const_default_method(def_id.to_def_id());
             (is_const_fn, opt)
         }
@@ -1433,6 +1433,9 @@
                     }
                 }
             }
+            if tcx.is_conditionally_const(def_id) {
+                record!(self.tables.const_conditions[def_id] <- self.tcx.const_conditions(def_id));
+            }
             if should_encode_type(tcx, local_id, def_kind) {
                 record!(self.tables.type_of[def_id] <- self.tcx.type_of(def_id));
             }
@@ -1456,10 +1459,13 @@
                     self.tcx.explicit_super_predicates_of(def_id).skip_binder());
                 record_defaulted_array!(self.tables.explicit_implied_predicates_of[def_id] <-
                     self.tcx.explicit_implied_predicates_of(def_id).skip_binder());
-
                 let module_children = self.tcx.module_children_local(local_id);
                 record_array!(self.tables.module_children_non_reexports[def_id] <-
                     module_children.iter().map(|child| child.res.def_id().index));
+                if self.tcx.is_const_trait(def_id) {
+                    record_defaulted_array!(self.tables.implied_const_bounds[def_id]
+                        <- self.tcx.implied_const_bounds(def_id).skip_binder());
+                }
             }
             if let DefKind::TraitAlias = def_kind {
                 record!(self.tables.trait_def[def_id] <- self.tcx.trait_def(def_id));
@@ -1479,9 +1485,6 @@
                 for &def_id in associated_item_def_ids {
                     self.encode_info_for_assoc_item(def_id);
                 }
-                if let Some(assoc_def_id) = self.tcx.associated_type_for_effects(def_id) {
-                    record!(self.tables.associated_type_for_effects[def_id] <- assoc_def_id);
-                }
             }
             if let DefKind::Closure | DefKind::SyntheticCoroutineBody = def_kind
                 && let Some(coroutine_kind) = self.tcx.coroutine_kind(def_id)
@@ -1652,6 +1655,10 @@
                 if let ty::AssocKind::Type = item.kind {
                     self.encode_explicit_item_bounds(def_id);
                     self.encode_explicit_item_super_predicates(def_id);
+                    if tcx.is_conditionally_const(def_id) {
+                        record_defaulted_array!(self.tables.implied_const_bounds[def_id]
+                            <- self.tcx.implied_const_bounds(def_id).skip_binder());
+                    }
                 }
             }
             AssocItemContainer::ImplContainer => {
@@ -1765,7 +1772,7 @@
     fn encode_stability(&mut self, def_id: DefId) {
         // The query lookup can take a measurable amount of time in crates with many items. Check if
         // the stability attributes are even enabled before using their queries.
-        if self.feat.staged_api || self.tcx.sess.opts.unstable_opts.force_unstable_if_unmarked {
+        if self.feat.staged_api() || self.tcx.sess.opts.unstable_opts.force_unstable_if_unmarked {
             if let Some(stab) = self.tcx.lookup_stability(def_id) {
                 record!(self.tables.lookup_stability[def_id] <- stab)
             }
@@ -1776,7 +1783,7 @@
     fn encode_const_stability(&mut self, def_id: DefId) {
         // The query lookup can take a measurable amount of time in crates with many items. Check if
         // the stability attributes are even enabled before using their queries.
-        if self.feat.staged_api || self.tcx.sess.opts.unstable_opts.force_unstable_if_unmarked {
+        if self.feat.staged_api() || self.tcx.sess.opts.unstable_opts.force_unstable_if_unmarked {
             if let Some(stab) = self.tcx.lookup_const_stability(def_id) {
                 record!(self.tables.lookup_const_stability[def_id] <- stab)
             }
@@ -1787,7 +1794,7 @@
     fn encode_default_body_stability(&mut self, def_id: DefId) {
         // The query lookup can take a measurable amount of time in crates with many items. Check if
         // the stability attributes are even enabled before using their queries.
-        if self.feat.staged_api || self.tcx.sess.opts.unstable_opts.force_unstable_if_unmarked {
+        if self.feat.staged_api() || self.tcx.sess.opts.unstable_opts.force_unstable_if_unmarked {
             if let Some(stab) = self.tcx.lookup_default_body_stability(def_id) {
                 record!(self.tables.lookup_default_body_stability[def_id] <- stab)
             }
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index 79bd1c1..a00ca27 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -392,9 +392,9 @@
     inferred_outlives_of: Table<DefIndex, LazyArray<(ty::Clause<'static>, Span)>>,
     explicit_super_predicates_of: Table<DefIndex, LazyArray<(ty::Clause<'static>, Span)>>,
     explicit_implied_predicates_of: Table<DefIndex, LazyArray<(ty::Clause<'static>, Span)>>,
+    implied_const_bounds: Table<DefIndex, LazyArray<(ty::PolyTraitRef<'static>, Span)>>,
     inherent_impls: Table<DefIndex, LazyArray<DefIndex>>,
     associated_types_for_impl_traits_in_associated_fn: Table<DefIndex, LazyArray<DefId>>,
-    associated_type_for_effects: Table<DefIndex, Option<LazyValue<DefId>>>,
     opt_rpitit_info: Table<DefIndex, Option<LazyValue<ty::ImplTraitInTraitData>>>,
     is_effects_desugaring: Table<DefIndex, bool>,
     unused_generic_params: Table<DefIndex, UnusedGenericParams>,
@@ -436,6 +436,7 @@
     thir_abstract_const: Table<DefIndex, LazyValue<ty::EarlyBinder<'static, ty::Const<'static>>>>,
     impl_parent: Table<DefIndex, RawDefId>,
     constness: Table<DefIndex, hir::Constness>,
+    const_conditions: Table<DefIndex, LazyValue<ty::ConstConditions<'static>>>,
     defaultness: Table<DefIndex, hir::Defaultness>,
     // FIXME(eddyb) perhaps compute this on the fly if cheap enough?
     coerce_unsized_info: Table<DefIndex, LazyValue<ty::adjustment::CoerceUnsizedInfo>>,
diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml
index 8cb602d9..485d1c1 100644
--- a/compiler/rustc_middle/Cargo.toml
+++ b/compiler/rustc_middle/Cargo.toml
@@ -27,6 +27,7 @@
 rustc_hir = { path = "../rustc_hir" }
 rustc_hir_pretty = { path = "../rustc_hir_pretty" }
 rustc_index = { path = "../rustc_index" }
+rustc_lint_defs = { path = "../rustc_lint_defs" }
 rustc_macros = { path = "../rustc_macros" }
 rustc_query_system = { path = "../rustc_query_system" }
 rustc_serialize = { path = "../rustc_serialize" }
diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs
index 52fe995..7e77923 100644
--- a/compiler/rustc_middle/src/arena.rs
+++ b/compiler/rustc_middle/src/arena.rs
@@ -8,7 +8,7 @@
 macro_rules! arena_types {
     ($macro:path) => (
         $macro!([
-            [] layout: rustc_target::abi::LayoutS<rustc_target::abi::FieldIdx, rustc_target::abi::VariantIdx>,
+            [] layout: rustc_abi::LayoutData<rustc_abi::FieldIdx, rustc_abi::VariantIdx>,
             [] fn_abi: rustc_target::abi::call::FnAbi<'tcx, rustc_middle::ty::Ty<'tcx>>,
             // AdtDef are interned and compared by address
             [decode] adt_def: rustc_middle::ty::AdtDefData,
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index 8fd5ff1..9266910 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -329,7 +329,7 @@
             BodyOwnerKind::Static(mutability) => ConstContext::Static(mutability),
 
             BodyOwnerKind::Fn if self.tcx.is_constructor(def_id) => return None,
-            BodyOwnerKind::Fn | BodyOwnerKind::Closure if self.tcx.is_const_fn_raw(def_id) => {
+            BodyOwnerKind::Fn | BodyOwnerKind::Closure if self.tcx.is_const_fn(def_id) => {
                 ConstContext::ConstFn
             }
             BodyOwnerKind::Fn if self.tcx.is_const_default_method(def_id) => ConstContext::ConstFn,
diff --git a/compiler/rustc_middle/src/infer/unify_key.rs b/compiler/rustc_middle/src/infer/unify_key.rs
index cf692b1..7f92110 100644
--- a/compiler/rustc_middle/src/infer/unify_key.rs
+++ b/compiler/rustc_middle/src/infer/unify_key.rs
@@ -172,70 +172,3 @@
         }
     }
 }
-
-/// values for the effect inference variable
-#[derive(Clone, Copy, Debug)]
-pub enum EffectVarValue<'tcx> {
-    Unknown,
-    Known(ty::Const<'tcx>),
-}
-
-impl<'tcx> EffectVarValue<'tcx> {
-    pub fn known(self) -> Option<ty::Const<'tcx>> {
-        match self {
-            EffectVarValue::Unknown => None,
-            EffectVarValue::Known(value) => Some(value),
-        }
-    }
-
-    pub fn is_unknown(self) -> bool {
-        match self {
-            EffectVarValue::Unknown => true,
-            EffectVarValue::Known(_) => false,
-        }
-    }
-}
-
-impl<'tcx> UnifyValue for EffectVarValue<'tcx> {
-    type Error = NoError;
-
-    fn unify_values(value1: &Self, value2: &Self) -> Result<Self, Self::Error> {
-        match (*value1, *value2) {
-            (EffectVarValue::Unknown, EffectVarValue::Unknown) => Ok(EffectVarValue::Unknown),
-            (EffectVarValue::Unknown, EffectVarValue::Known(val))
-            | (EffectVarValue::Known(val), EffectVarValue::Unknown) => {
-                Ok(EffectVarValue::Known(val))
-            }
-            (EffectVarValue::Known(_), EffectVarValue::Known(_)) => {
-                bug!("equating known inference variables: {value1:?} {value2:?}")
-            }
-        }
-    }
-}
-
-#[derive(PartialEq, Copy, Clone, Debug)]
-pub struct EffectVidKey<'tcx> {
-    pub vid: ty::EffectVid,
-    pub phantom: PhantomData<ty::Const<'tcx>>,
-}
-
-impl<'tcx> From<ty::EffectVid> for EffectVidKey<'tcx> {
-    fn from(vid: ty::EffectVid) -> Self {
-        EffectVidKey { vid, phantom: PhantomData }
-    }
-}
-
-impl<'tcx> UnifyKey for EffectVidKey<'tcx> {
-    type Value = EffectVarValue<'tcx>;
-    #[inline]
-    fn index(&self) -> u32 {
-        self.vid.as_u32()
-    }
-    #[inline]
-    fn from_index(i: u32) -> Self {
-        EffectVidKey::from(ty::EffectVid::from_u32(i))
-    }
-    fn tag() -> &'static str {
-        "EffectVidKey"
-    }
-}
diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs
index ee34ccd..c0688af 100644
--- a/compiler/rustc_middle/src/middle/stability.rs
+++ b/compiler/rustc_middle/src/middle/stability.rs
@@ -422,15 +422,15 @@
                     debug!("stability: skipping span={:?} since it is internal", span);
                     return EvalResult::Allow;
                 }
-                if self.features().declared(feature) {
+                if self.features().enabled(feature) {
                     return EvalResult::Allow;
                 }
 
                 // If this item was previously part of a now-stabilized feature which is still
-                // active (i.e. the user hasn't removed the attribute for the stabilized feature
+                // enabled (i.e. the user hasn't removed the attribute for the stabilized feature
                 // yet) then allow use of this item.
                 if let Some(implied_by) = implied_by
-                    && self.features().declared(implied_by)
+                    && self.features().enabled(implied_by)
                 {
                     return EvalResult::Allow;
                 }
@@ -509,7 +509,7 @@
                     debug!("body stability: skipping span={:?} since it is internal", span);
                     return EvalResult::Allow;
                 }
-                if self.features().declared(feature) {
+                if self.features().enabled(feature) {
                     return EvalResult::Allow;
                 }
 
diff --git a/compiler/rustc_middle/src/mir/graphviz.rs b/compiler/rustc_middle/src/mir/graphviz.rs
index a3fe8f9..7bb4119 100644
--- a/compiler/rustc_middle/src/mir/graphviz.rs
+++ b/compiler/rustc_middle/src/mir/graphviz.rs
@@ -17,7 +17,7 @@
     let mirs = def_ids
         .iter()
         .flat_map(|def_id| {
-            if tcx.is_const_fn_raw(*def_id) {
+            if tcx.is_const_fn(*def_id) {
                 vec![tcx.optimized_mir(*def_id), tcx.mir_for_ctfe(*def_id)]
             } else {
                 vec![tcx.instance_mir(ty::InstanceKind::Item(*def_id))]
diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs
index 59bc552..2ecf1d0 100644
--- a/compiler/rustc_middle/src/mir/interpret/queries.rs
+++ b/compiler/rustc_middle/src/mir/interpret/queries.rs
@@ -116,7 +116,7 @@
                     // @lcnr believes that successfully evaluating even though there are
                     // used generic parameters is a bug of evaluation, so checking for it
                     // here does feel somewhat sensible.
-                    if !self.features().generic_const_exprs && ct.args.has_non_region_param() {
+                    if !self.features().generic_const_exprs() && ct.args.has_non_region_param() {
                         let def_kind = self.def_kind(instance.def_id());
                         assert!(
                             matches!(
diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs
index 56ca916..d8d99de 100644
--- a/compiler/rustc_middle/src/mir/mono.rs
+++ b/compiler/rustc_middle/src/mir/mono.rs
@@ -86,11 +86,9 @@
         }
     }
 
-    pub fn is_generic_fn(&self, tcx: TyCtxt<'tcx>) -> bool {
+    pub fn is_generic_fn(&self) -> bool {
         match self {
-            MonoItem::Fn(instance) => {
-                instance.args.non_erasable_generics(tcx, instance.def_id()).next().is_some()
-            }
+            MonoItem::Fn(instance) => instance.args.non_erasable_generics().next().is_some(),
             MonoItem::Static(..) | MonoItem::GlobalAsm(..) => false,
         }
     }
diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs
index 2a3a070..e690bf7 100644
--- a/compiler/rustc_middle/src/mir/pretty.rs
+++ b/compiler/rustc_middle/src/mir/pretty.rs
@@ -277,9 +277,9 @@
             )
         })?;
     }
-    Ok(fs::File::create_buffered(&file_path).map_err(|e| {
+    fs::File::create_buffered(&file_path).map_err(|e| {
         io::Error::new(e.kind(), format!("IO error creating MIR dump file: {file_path:?}; {e}"))
-    })?)
+    })
 }
 
 ///////////////////////////////////////////////////////////////////////////
@@ -317,7 +317,7 @@
         };
 
         // For `const fn` we want to render both the optimized MIR and the MIR for ctfe.
-        if tcx.is_const_fn_raw(def_id) {
+        if tcx.is_const_fn(def_id) {
             render_body(w, tcx.optimized_mir(def_id))?;
             writeln!(w)?;
             writeln!(w, "// MIR FOR CTFE")?;
diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs
index 48bf4ff..5f8427b 100644
--- a/compiler/rustc_middle/src/query/erase.rs
+++ b/compiler/rustc_middle/src/query/erase.rs
@@ -370,6 +370,7 @@
     rustc_middle::ty::FnSig,
     rustc_middle::ty::GenericArg,
     rustc_middle::ty::GenericPredicates,
+    rustc_middle::ty::ConstConditions,
     rustc_middle::ty::inhabitedness::InhabitedPredicate,
     rustc_middle::ty::Instance,
     rustc_middle::ty::InstanceKind,
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index f8ba606..d7a60a8 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -29,6 +29,7 @@
 use rustc_hir::lang_items::{LangItem, LanguageItems};
 use rustc_hir::{Crate, ItemLocalId, ItemLocalMap, TraitCandidate};
 use rustc_index::IndexVec;
+use rustc_lint_defs::LintId;
 use rustc_macros::rustc_queries;
 use rustc_query_system::ich::StableHashingContext;
 use rustc_query_system::query::{QueryCache, QueryMode, QueryState, try_get_cached};
@@ -422,6 +423,11 @@
         desc { "computing `#[expect]`ed lints in this crate" }
     }
 
+    query lints_that_dont_need_to_run(_: ()) -> &'tcx FxIndexSet<LintId> {
+        arena_cache
+        desc { "Computing all lints that are explicitly enabled or with a default level greater than Allow" }
+    }
+
     query expn_that_defined(key: DefId) -> rustc_span::ExpnId {
         desc { |tcx| "getting the expansion that defined `{}`", tcx.def_path_str(key) }
         separate_provide_extern
@@ -683,6 +689,24 @@
         }
     }
 
+    query const_conditions(
+        key: DefId
+    ) -> ty::ConstConditions<'tcx> {
+        desc { |tcx| "computing the conditions for `{}` to be considered const",
+            tcx.def_path_str(key)
+        }
+        separate_provide_extern
+    }
+
+    query implied_const_bounds(
+        key: DefId
+    ) -> ty::EarlyBinder<'tcx, &'tcx [(ty::PolyTraitRef<'tcx>, Span)]> {
+        desc { |tcx| "computing the implied `~const` bounds for `{}`",
+            tcx.def_path_str(key)
+        }
+        separate_provide_extern
+    }
+
     /// To avoid cycles within the predicates of a single item we compute
     /// per-type-parameter predicates for resolving `T::AssocTy`.
     query type_param_predicates(
@@ -723,12 +747,11 @@
         desc { |tcx| "computing drop-check constraints for `{}`", tcx.def_path_str(key) }
     }
 
-    /// Returns `true` if this is a const fn, use the `is_const_fn` to know whether your crate
-    /// actually sees it as const fn (e.g., the const-fn-ness might be unstable and you might
-    /// not have the feature gate active).
+    /// Returns `true` if this is a const fn / const impl.
     ///
     /// **Do not call this function manually.** It is only meant to cache the base data for the
-    /// `is_const_fn` function. Consider using `is_const_fn` or `is_const_fn_raw` instead.
+    /// higher-level functions. Consider using `is_const_fn` or `is_const_trait_impl` instead.
+    /// Also note that neither of them takes into account feature gates and stability.
     query constness(key: DefId) -> hir::Constness {
         desc { |tcx| "checking if item is const: `{}`", tcx.def_path_str(key) }
         separate_provide_extern
@@ -854,12 +877,6 @@
         separate_provide_extern
     }
 
-    query associated_type_for_effects(def_id: DefId) -> Option<DefId> {
-        desc { |tcx| "creating associated items for effects in `{}`", tcx.def_path_str(def_id) }
-        cache_on_disk_if { def_id.is_local() }
-        separate_provide_extern
-    }
-
     /// Given an impl trait in trait `opaque_ty_def_id`, create and return the corresponding
     /// associated item.
     query associated_type_for_impl_trait_in_trait(opaque_ty_def_id: LocalDefId) -> LocalDefId {
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index 8ee8b4c..40e5ec4 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -92,16 +92,6 @@
         ObligationCause { span, body_id: CRATE_DEF_ID, code: Default::default() }
     }
 
-    pub fn span(&self) -> Span {
-        match *self.code() {
-            ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
-                arm_span,
-                ..
-            }) => arm_span,
-            _ => self.span,
-        }
-    }
-
     #[inline]
     pub fn code(&self) -> &ObligationCauseCode<'tcx> {
         &self.code
@@ -517,10 +507,17 @@
     pub prior_arm_block_id: Option<HirId>,
     pub prior_arm_ty: Ty<'tcx>,
     pub prior_arm_span: Span,
+    /// Span of the scrutinee of the match (the matched value).
     pub scrut_span: Span,
+    /// Source of the match, i.e. `match` or a desugaring.
     pub source: hir::MatchSource,
+    /// Span of the *whole* match expr.
+    pub expr_span: Span,
+    /// Spans of the previous arms except for those that diverge (i.e. evaluate to `!`).
+    ///
+    /// These are used for pointing out errors that may affect several arms.
     pub prior_non_diverging_arms: Vec<Span>,
-    // Is the expectation of this match expression an RPIT?
+    /// Is the expectation of this match expression an RPIT?
     pub tail_defines_return_position_impl_trait: Option<LocalDefId>,
 }
 
diff --git a/compiler/rustc_middle/src/traits/specialization_graph.rs b/compiler/rustc_middle/src/traits/specialization_graph.rs
index 26dcae0..515aabb 100644
--- a/compiler/rustc_middle/src/traits/specialization_graph.rs
+++ b/compiler/rustc_middle/src/traits/specialization_graph.rs
@@ -61,7 +61,7 @@
 
 impl OverlapMode {
     pub fn get(tcx: TyCtxt<'_>, trait_id: DefId) -> OverlapMode {
-        let with_negative_coherence = tcx.features().with_negative_coherence;
+        let with_negative_coherence = tcx.features().with_negative_coherence();
         let strict_coherence = tcx.has_attr(trait_id, sym::rustc_strict_coherence);
 
         if with_negative_coherence {
diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs
index 7e533bc..ef9dfdd 100644
--- a/compiler/rustc_middle/src/ty/codec.rs
+++ b/compiler/rustc_middle/src/ty/codec.rs
@@ -387,6 +387,17 @@
 }
 
 impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D>
+    for [(ty::PolyTraitRef<'tcx>, Span)]
+{
+    fn decode(decoder: &mut D) -> &'tcx Self {
+        decoder
+            .interner()
+            .arena
+            .alloc_from_iter((0..decoder.read_usize()).map(|_| Decodable::decode(decoder)))
+    }
+}
+
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D>
     for ty::List<ty::BoundVariableKind>
 {
     fn decode(decoder: &mut D) -> &'tcx Self {
diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs
index eb715be..5ab85a6 100644
--- a/compiler/rustc_middle/src/ty/consts.rs
+++ b/compiler/rustc_middle/src/ty/consts.rs
@@ -109,6 +109,7 @@
 
     #[inline]
     pub fn new_unevaluated(tcx: TyCtxt<'tcx>, uv: ty::UnevaluatedConst<'tcx>) -> Const<'tcx> {
+        tcx.debug_assert_args_compatible(uv.def, uv.args);
         Const::new(tcx, ty::ConstKind::Unevaluated(uv))
     }
 
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index c2a5506..5ae9c58 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -12,7 +12,7 @@
 use std::ops::{Bound, Deref};
 use std::{fmt, iter, mem};
 
-use rustc_abi::{FieldIdx, Layout, LayoutS, TargetDataLayout, VariantIdx};
+use rustc_abi::{FieldIdx, Layout, LayoutData, TargetDataLayout, VariantIdx};
 use rustc_ast::{self as ast, attr};
 use rustc_data_structures::defer;
 use rustc_data_structures::fingerprint::Fingerprint;
@@ -78,10 +78,10 @@
 use crate::ty::predicate::ExistentialPredicateStableCmpExt as _;
 use crate::ty::{
     self, AdtDef, AdtDefData, AdtKind, Binder, Clause, Clauses, Const, GenericArg, GenericArgs,
-    GenericArgsRef, GenericParamDefKind, ImplPolarity, List, ListWithCachedTypeInfo, ParamConst,
-    ParamTy, Pattern, PatternKind, PolyExistentialPredicate, PolyFnSig, Predicate, PredicateKind,
-    PredicatePolarity, Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyVid,
-    Visibility,
+    GenericArgsRef, GenericParamDefKind, HostPolarity, ImplPolarity, List, ListWithCachedTypeInfo,
+    ParamConst, ParamTy, Pattern, PatternKind, PolyExistentialPredicate, PolyFnSig, Predicate,
+    PredicateKind, PredicatePolarity, Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty,
+    TyKind, TyVid, Visibility,
 };
 
 #[allow(rustc::usage_of_ty_tykind)]
@@ -279,6 +279,26 @@
         self.debug_assert_args_compatible(def_id, args);
     }
 
+    /// Assert that the args from an `ExistentialTraitRef` or `ExistentialProjection`
+    /// are compatible with the `DefId`. Since we're missing a `Self` type, stick on
+    /// a dummy self type and forward to `debug_assert_args_compatible`.
+    fn debug_assert_existential_args_compatible(
+        self,
+        def_id: Self::DefId,
+        args: Self::GenericArgs,
+    ) {
+        // FIXME: We could perhaps add a `skip: usize` to `debug_assert_args_compatible`
+        // to avoid needing to reintern the set of args...
+        if cfg!(debug_assertions) {
+            self.debug_assert_args_compatible(
+                def_id,
+                self.mk_args_from_iter(
+                    [self.types.trait_object_dummy_self.into()].into_iter().chain(args.iter()),
+                ),
+            );
+        }
+    }
+
     fn mk_type_list_from_iter<I, T>(self, args: I) -> T::Output
     where
         I: Iterator<Item = T>,
@@ -363,6 +383,28 @@
         self.explicit_implied_predicates_of(def_id).map_bound(|preds| preds.into_iter().copied())
     }
 
+    fn is_const_impl(self, def_id: DefId) -> bool {
+        self.is_conditionally_const(def_id)
+    }
+
+    fn const_conditions(
+        self,
+        def_id: DefId,
+    ) -> ty::EarlyBinder<'tcx, impl IntoIterator<Item = ty::Binder<'tcx, ty::TraitRef<'tcx>>>> {
+        ty::EarlyBinder::bind(
+            self.const_conditions(def_id).instantiate_identity(self).into_iter().map(|(c, _)| c),
+        )
+    }
+
+    fn implied_const_bounds(
+        self,
+        def_id: DefId,
+    ) -> ty::EarlyBinder<'tcx, impl IntoIterator<Item = ty::Binder<'tcx, ty::TraitRef<'tcx>>>> {
+        ty::EarlyBinder::bind(
+            self.implied_const_bounds(def_id).iter_identity_copied().map(|(c, _)| c),
+        )
+    }
+
     fn has_target_features(self, def_id: DefId) -> bool {
         !self.codegen_fn_attrs(def_id).target_features.is_empty()
     }
@@ -626,13 +668,6 @@
     Destruct,
     DiscriminantKind,
     DynMetadata,
-    EffectsCompat,
-    EffectsIntersection,
-    EffectsIntersectionOutput,
-    EffectsMaybe,
-    EffectsNoRuntime,
-    EffectsRuntime,
-    EffectsTyCompat,
     Fn,
     FnMut,
     FnOnce,
@@ -690,15 +725,15 @@
 
 impl<'tcx> rustc_type_ir::inherent::Features<TyCtxt<'tcx>> for &'tcx rustc_feature::Features {
     fn generic_const_exprs(self) -> bool {
-        self.generic_const_exprs
+        self.generic_const_exprs()
     }
 
     fn coroutine_clone(self) -> bool {
-        self.coroutine_clone
+        self.coroutine_clone()
     }
 
     fn associated_const_equality(self) -> bool {
-        self.associated_const_equality
+        self.associated_const_equality()
     }
 }
 
@@ -731,7 +766,7 @@
     pat: InternedSet<'tcx, PatternKind<'tcx>>,
     const_allocation: InternedSet<'tcx, Allocation>,
     bound_variable_kinds: InternedSet<'tcx, List<ty::BoundVariableKind>>,
-    layout: InternedSet<'tcx, LayoutS<FieldIdx, VariantIdx>>,
+    layout: InternedSet<'tcx, LayoutData<FieldIdx, VariantIdx>>,
     adt_def: InternedSet<'tcx, AdtDefData>,
     external_constraints: InternedSet<'tcx, ExternalConstraintsData<TyCtxt<'tcx>>>,
     predefined_opaques_in_body: InternedSet<'tcx, PredefinedOpaquesData<TyCtxt<'tcx>>>,
@@ -2176,7 +2211,7 @@
 nop_slice_lift! {ty::ValTree<'a> => ty::ValTree<'tcx>}
 
 TrivialLiftImpls! {
-    ImplPolarity, PredicatePolarity, Promoted
+    ImplPolarity, PredicatePolarity, Promoted, HostPolarity,
 }
 
 macro_rules! sty_debug_print {
@@ -2434,7 +2469,7 @@
     region: pub(crate) intern_region(RegionKind<'tcx>): Region -> Region<'tcx>,
     pat: pub mk_pat(PatternKind<'tcx>): Pattern -> Pattern<'tcx>,
     const_allocation: pub mk_const_alloc(Allocation): ConstAllocation -> ConstAllocation<'tcx>,
-    layout: pub mk_layout(LayoutS<FieldIdx, VariantIdx>): Layout -> Layout<'tcx>,
+    layout: pub mk_layout(LayoutData<FieldIdx, VariantIdx>): Layout -> Layout<'tcx>,
     adt_def: pub mk_adt_def_from_data(AdtDefData): AdtDef -> AdtDef<'tcx>,
     external_constraints: pub mk_external_constraints(ExternalConstraintsData<TyCtxt<'tcx>>):
         ExternalConstraints -> ExternalConstraints<'tcx>,
@@ -3085,38 +3120,24 @@
         }
     }
 
-    /// Whether the `def_id` counts as const fn in the current crate, considering all active
-    /// feature gates
-    pub fn is_const_fn(self, def_id: DefId) -> bool {
-        if self.is_const_fn_raw(def_id) {
-            match self.lookup_const_stability(def_id) {
-                Some(stability) if stability.is_const_unstable() => {
-                    // has a `rustc_const_unstable` attribute, check whether the user enabled the
-                    // corresponding feature gate.
-                    self.features().declared(stability.feature)
-                }
-                // functions without const stability are either stable user written
-                // const fn or the user is using feature gates and we thus don't
-                // care what they do
-                _ => true,
+    /// Whether `def_id` is a stable const fn (i.e., doesn't need any feature gates to be called).
+    ///
+    /// When this is `false`, the function may still be callable as a `const fn` due to features
+    /// being enabled!
+    pub fn is_stable_const_fn(self, def_id: DefId) -> bool {
+        self.is_const_fn(def_id)
+            && match self.lookup_const_stability(def_id) {
+                None => true, // a fn in a non-staged_api crate
+                Some(stability) if stability.is_const_stable() => true,
+                _ => false,
             }
-        } else {
-            false
-        }
     }
 
+    // FIXME(effects): Please remove this. It's a footgun.
     /// Whether the trait impl is marked const. This does not consider stability or feature gates.
-    pub fn is_const_trait_impl_raw(self, def_id: DefId) -> bool {
-        let Some(local_def_id) = def_id.as_local() else { return false };
-        let node = self.hir_node_by_def_id(local_def_id);
-
-        matches!(
-            node,
-            hir::Node::Item(hir::Item {
-                kind: hir::ItemKind::Impl(hir::Impl { constness, .. }),
-                ..
-            }) if matches!(constness, hir::Constness::Const)
-        )
+    pub fn is_const_trait_impl(self, def_id: DefId) -> bool {
+        self.def_kind(def_id) == DefKind::Impl { of_trait: true }
+            && self.constness(def_id) == hir::Constness::Const
     }
 
     pub fn intrinsic(self, def_id: impl IntoQueryParam<DefId> + Copy) -> Option<ty::IntrinsicDef> {
diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs
index 4f408ee..84f52bf 100644
--- a/compiler/rustc_middle/src/ty/diagnostics.rs
+++ b/compiler/rustc_middle/src/ty/diagnostics.rs
@@ -70,7 +70,7 @@
     /// ADTs with no type arguments.
     pub fn is_simple_text(self, tcx: TyCtxt<'tcx>) -> bool {
         match self.kind() {
-            Adt(def, args) => args.non_erasable_generics(tcx, def.did()).next().is_none(),
+            Adt(_, args) => args.non_erasable_generics().next().is_none(),
             Ref(_, ty, _) => ty.is_simple_text(tcx),
             _ => self.is_simple_ty(),
         }
@@ -193,7 +193,7 @@
             .enumerate()
             .filter(|(_, bound)| {
                 if let hir::GenericBound::Trait(poly) = bound
-                    && poly.modifiers == hir::TraitBoundModifier::Maybe
+                    && let hir::BoundPolarity::Maybe(_) = poly.modifiers.polarity
                     && poly.trait_ref.trait_def_id() == def_id
                 {
                     true
@@ -592,9 +592,6 @@
         match c.kind() {
             ConstKind::Infer(InferConst::Var(_)) if self.infer_suggestable => {}
 
-            // effect variables are always suggestable, because they are not visible
-            ConstKind::Infer(InferConst::EffectVar(_)) => {}
-
             ConstKind::Infer(..)
             | ConstKind::Bound(..)
             | ConstKind::Placeholder(..)
diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs
index b02eff3..c49824b 100644
--- a/compiler/rustc_middle/src/ty/error.rs
+++ b/compiler/rustc_middle/src/ty/error.rs
@@ -35,9 +35,6 @@
             TypeError::CyclicTy(_) => "cyclic type of infinite size".into(),
             TypeError::CyclicConst(_) => "encountered a self-referencing constant".into(),
             TypeError::Mismatch => "types differ".into(),
-            TypeError::ConstnessMismatch(values) => {
-                format!("expected {} bound, found {} bound", values.expected, values.found).into()
-            }
             TypeError::PolarityMismatch(values) => {
                 format!("expected {} polarity, found {} polarity", values.expected, values.found)
                     .into()
diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs
index 92a975c..704a197 100644
--- a/compiler/rustc_middle/src/ty/flags.rs
+++ b/compiler/rustc_middle/src/ty/flags.rs
@@ -265,6 +265,12 @@
             ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) => {
                 self.add_args(trait_pred.trait_ref.args);
             }
+            ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(ty::HostEffectPredicate {
+                trait_ref,
+                host: _,
+            })) => {
+                self.add_args(trait_ref.args);
+            }
             ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(
                 a,
                 b,
@@ -354,9 +360,7 @@
                 self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
                 match infer {
                     InferConst::Fresh(_) => self.add_flags(TypeFlags::HAS_CT_FRESH),
-                    InferConst::Var(_) | InferConst::EffectVar(_) => {
-                        self.add_flags(TypeFlags::HAS_CT_INFER)
-                    }
+                    InferConst::Var(_) => self.add_flags(TypeFlags::HAS_CT_INFER),
                 }
             }
             ty::ConstKind::Bound(debruijn, _) => {
diff --git a/compiler/rustc_middle/src/ty/generic_args.rs b/compiler/rustc_middle/src/ty/generic_args.rs
index daf1362..737f136 100644
--- a/compiler/rustc_middle/src/ty/generic_args.rs
+++ b/compiler/rustc_middle/src/ty/generic_args.rs
@@ -501,12 +501,8 @@
     #[inline]
     pub fn non_erasable_generics(
         &'tcx self,
-        tcx: TyCtxt<'tcx>,
-        def_id: DefId,
     ) -> impl DoubleEndedIterator<Item = GenericArgKind<'tcx>> + 'tcx {
-        let generics = tcx.generics_of(def_id);
-        self.iter().enumerate().filter_map(|(i, k)| match k.unpack() {
-            _ if Some(i) == generics.host_effect_index => None,
+        self.iter().filter_map(|k| match k.unpack() {
             ty::GenericArgKind::Lifetime(_) => None,
             generic => Some(generic),
         })
diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs
index 660686f..1977974 100644
--- a/compiler/rustc_middle/src/ty/generics.rs
+++ b/compiler/rustc_middle/src/ty/generics.rs
@@ -14,7 +14,7 @@
 pub enum GenericParamDefKind {
     Lifetime,
     Type { has_default: bool, synthetic: bool },
-    Const { has_default: bool, is_host_effect: bool, synthetic: bool },
+    Const { has_default: bool, synthetic: bool },
 }
 
 impl GenericParamDefKind {
@@ -81,10 +81,6 @@
         }
     }
 
-    pub fn is_host_effect(&self) -> bool {
-        matches!(self.kind, GenericParamDefKind::Const { is_host_effect: true, .. })
-    }
-
     pub fn default_value<'tcx>(
         &self,
         tcx: TyCtxt<'tcx>,
@@ -133,9 +129,6 @@
 
     pub has_self: bool,
     pub has_late_bound_regions: Option<Span>,
-
-    // The index of the host effect when instantiated. (i.e. might be index to parent args)
-    pub host_effect_index: Option<usize>,
 }
 
 impl<'tcx> rustc_type_ir::inherent::GenericsOf<TyCtxt<'tcx>> for &'tcx Generics {
@@ -216,12 +209,10 @@
     pub fn own_requires_monomorphization(&self) -> bool {
         for param in &self.own_params {
             match param.kind {
-                GenericParamDefKind::Type { .. }
-                | GenericParamDefKind::Const { is_host_effect: false, .. } => {
+                GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
                     return true;
                 }
-                GenericParamDefKind::Lifetime
-                | GenericParamDefKind::Const { is_host_effect: true, .. } => {}
+                GenericParamDefKind::Lifetime => {}
             }
         }
         false
@@ -300,8 +291,6 @@
             own_params.start = 1;
         }
 
-        let verbose = tcx.sess.verbose_internals();
-
         // Filter the default arguments.
         //
         // This currently uses structural equality instead
@@ -316,8 +305,6 @@
                 param.default_value(tcx).is_some_and(|default| {
                     default.instantiate(tcx, args) == args[param.index as usize]
                 })
-                // filter out trailing effect params, if we're not in `-Zverbose-internals`.
-                || (!verbose && matches!(param.kind, GenericParamDefKind::Const { is_host_effect: true, .. }))
             })
             .count();
 
@@ -373,7 +360,6 @@
 pub struct GenericPredicates<'tcx> {
     pub parent: Option<DefId>,
     pub predicates: &'tcx [(Clause<'tcx>, Span)],
-    pub effects_min_tys: &'tcx ty::List<Ty<'tcx>>,
 }
 
 impl<'tcx> GenericPredicates<'tcx> {
@@ -395,7 +381,9 @@
         EarlyBinder::bind(self.predicates).iter_instantiated_copied(tcx, args)
     }
 
-    pub fn instantiate_own_identity(self) -> impl Iterator<Item = (Clause<'tcx>, Span)> {
+    pub fn instantiate_own_identity(
+        self,
+    ) -> impl Iterator<Item = (Clause<'tcx>, Span)> + DoubleEndedIterator + ExactSizeIterator {
         EarlyBinder::bind(self.predicates).iter_identity_copied()
     }
 
@@ -433,3 +421,73 @@
         instantiated.spans.extend(self.predicates.iter().map(|(_, s)| s));
     }
 }
+
+/// `~const` bounds for a given item. This is represented using a struct much like
+/// `GenericPredicates`, where you can either choose to only instantiate the "own"
+/// bounds or all of the bounds including those from the parent. This distinction
+/// is necessary for code like `compare_method_predicate_entailment`.
+#[derive(Copy, Clone, Default, Debug, TyEncodable, TyDecodable, HashStable)]
+pub struct ConstConditions<'tcx> {
+    pub parent: Option<DefId>,
+    pub predicates: &'tcx [(ty::PolyTraitRef<'tcx>, Span)],
+}
+
+impl<'tcx> ConstConditions<'tcx> {
+    pub fn instantiate(
+        self,
+        tcx: TyCtxt<'tcx>,
+        args: GenericArgsRef<'tcx>,
+    ) -> Vec<(ty::PolyTraitRef<'tcx>, Span)> {
+        let mut instantiated = vec![];
+        self.instantiate_into(tcx, &mut instantiated, args);
+        instantiated
+    }
+
+    pub fn instantiate_own(
+        self,
+        tcx: TyCtxt<'tcx>,
+        args: GenericArgsRef<'tcx>,
+    ) -> impl Iterator<Item = (ty::PolyTraitRef<'tcx>, Span)> + DoubleEndedIterator + ExactSizeIterator
+    {
+        EarlyBinder::bind(self.predicates).iter_instantiated_copied(tcx, args)
+    }
+
+    pub fn instantiate_own_identity(
+        self,
+    ) -> impl Iterator<Item = (ty::PolyTraitRef<'tcx>, Span)> + DoubleEndedIterator + ExactSizeIterator
+    {
+        EarlyBinder::bind(self.predicates).iter_identity_copied()
+    }
+
+    #[instrument(level = "debug", skip(self, tcx))]
+    fn instantiate_into(
+        self,
+        tcx: TyCtxt<'tcx>,
+        instantiated: &mut Vec<(ty::PolyTraitRef<'tcx>, Span)>,
+        args: GenericArgsRef<'tcx>,
+    ) {
+        if let Some(def_id) = self.parent {
+            tcx.const_conditions(def_id).instantiate_into(tcx, instantiated, args);
+        }
+        instantiated.extend(
+            self.predicates.iter().map(|&(p, s)| (EarlyBinder::bind(p).instantiate(tcx, args), s)),
+        );
+    }
+
+    pub fn instantiate_identity(self, tcx: TyCtxt<'tcx>) -> Vec<(ty::PolyTraitRef<'tcx>, Span)> {
+        let mut instantiated = vec![];
+        self.instantiate_identity_into(tcx, &mut instantiated);
+        instantiated
+    }
+
+    fn instantiate_identity_into(
+        self,
+        tcx: TyCtxt<'tcx>,
+        instantiated: &mut Vec<(ty::PolyTraitRef<'tcx>, Span)>,
+    ) {
+        if let Some(def_id) = self.parent {
+            tcx.const_conditions(def_id).instantiate_identity_into(tcx, instantiated);
+        }
+        instantiated.extend(self.predicates.iter().copied());
+    }
+}
diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs
index b1c5ff5..e237d38 100644
--- a/compiler/rustc_middle/src/ty/instance.rs
+++ b/compiler/rustc_middle/src/ty/instance.rs
@@ -204,7 +204,7 @@
         }
 
         // If this a non-generic instance, it cannot be a shared monomorphization.
-        self.args.non_erasable_generics(tcx, self.def_id()).next()?;
+        self.args.non_erasable_generics().next()?;
 
         // compiler_builtins cannot use upstream monomorphizations.
         if tcx.is_compiler_builtins(LOCAL_CRATE) {
@@ -476,7 +476,6 @@
     pub fn mono(tcx: TyCtxt<'tcx>, def_id: DefId) -> Instance<'tcx> {
         let args = GenericArgs::for_item(tcx, def_id, |param, _| match param.kind {
             ty::GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(),
-            ty::GenericParamDefKind::Const { is_host_effect: true, .. } => tcx.consts.true_.into(),
             ty::GenericParamDefKind::Type { .. } => {
                 bug!("Instance::mono: {:?} has type parameters", def_id)
             }
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index 3670b6b..990fc37 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -4,7 +4,7 @@
 
 use rustc_abi::Primitive::{self, Float, Int, Pointer};
 use rustc_abi::{
-    Abi, AddressSpace, Align, FieldsShape, HasDataLayout, Integer, LayoutCalculator, LayoutS,
+    Abi, AddressSpace, Align, FieldsShape, HasDataLayout, Integer, LayoutCalculator, LayoutData,
     PointeeInfo, PointerKind, ReprOptions, Scalar, Size, TagEncoding, TargetDataLayout, Variants,
 };
 use rustc_error_messages::DiagMessage;
@@ -21,7 +21,9 @@
 use rustc_target::abi::call::FnAbi;
 use rustc_target::abi::{FieldIdx, TyAbiInterface, VariantIdx, call};
 use rustc_target::spec::abi::Abi as SpecAbi;
-use rustc_target::spec::{HasTargetSpec, HasWasmCAbiOpt, PanicStrategy, Target, WasmCAbi};
+use rustc_target::spec::{
+    HasTargetSpec, HasWasmCAbiOpt, HasX86AbiOpt, PanicStrategy, Target, WasmCAbi, X86Abi,
+};
 use tracing::debug;
 use {rustc_abi as abi, rustc_hir as hir};
 
@@ -396,7 +398,7 @@
                     ),
                 }
             }
-            ty::Array(inner, len) if tcx.features().transmute_generic_consts => {
+            ty::Array(inner, len) if tcx.features().transmute_generic_consts() => {
                 let len_eval = len.try_to_target_usize(tcx);
                 if len_eval == Some(0) {
                     return Ok(SizeSkeleton::Known(Size::from_bytes(0), None));
@@ -544,6 +546,12 @@
     }
 }
 
+impl<'tcx> HasX86AbiOpt for TyCtxt<'tcx> {
+    fn x86_abi_opt(&self) -> X86Abi {
+        X86Abi { regparm: self.sess.opts.unstable_opts.regparm }
+    }
+}
+
 impl<'tcx> HasTyCtxt<'tcx> for TyCtxt<'tcx> {
     #[inline]
     fn tcx(&self) -> TyCtxt<'tcx> {
@@ -595,6 +603,12 @@
     }
 }
 
+impl<'tcx> HasX86AbiOpt for LayoutCx<'tcx> {
+    fn x86_abi_opt(&self) -> X86Abi {
+        self.calc.cx.x86_abi_opt()
+    }
+}
+
 impl<'tcx> HasTyCtxt<'tcx> for LayoutCx<'tcx> {
     fn tcx(&self) -> TyCtxt<'tcx> {
         self.calc.cx
@@ -737,7 +751,7 @@
                     ty::Adt(def, _) => def.variant(variant_index).fields.len(),
                     _ => bug!("`ty_and_layout_for_variant` on unexpected type {}", this.ty),
                 };
-                tcx.mk_layout(LayoutS {
+                tcx.mk_layout(LayoutData {
                     variants: Variants::Single { index: variant_index },
                     fields: match NonZero::new(fields) {
                         Some(fields) => FieldsShape::Union(fields),
@@ -774,7 +788,7 @@
             let tcx = cx.tcx();
             let tag_layout = |tag: Scalar| -> TyAndLayout<'tcx> {
                 TyAndLayout {
-                    layout: tcx.mk_layout(LayoutS::scalar(cx, tag)),
+                    layout: tcx.mk_layout(LayoutData::scalar(cx, tag)),
                     ty: tag.primitive().to_ty(tcx),
                 }
             };
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index ed24fcc..b92fc86 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -84,12 +84,13 @@
 pub use self::pattern::{Pattern, PatternKind};
 pub use self::predicate::{
     AliasTerm, Clause, ClauseKind, CoercePredicate, ExistentialPredicate,
-    ExistentialPredicateStableCmpExt, ExistentialProjection, ExistentialTraitRef, NormalizesTo,
-    OutlivesPredicate, PolyCoercePredicate, PolyExistentialPredicate, PolyExistentialProjection,
-    PolyExistentialTraitRef, PolyProjectionPredicate, PolyRegionOutlivesPredicate,
-    PolySubtypePredicate, PolyTraitPredicate, PolyTraitRef, PolyTypeOutlivesPredicate, Predicate,
-    PredicateKind, ProjectionPredicate, RegionOutlivesPredicate, SubtypePredicate, ToPolyTraitRef,
-    TraitPredicate, TraitRef, TypeOutlivesPredicate,
+    ExistentialPredicateStableCmpExt, ExistentialProjection, ExistentialTraitRef,
+    HostEffectPredicate, NormalizesTo, OutlivesPredicate, PolyCoercePredicate,
+    PolyExistentialPredicate, PolyExistentialProjection, PolyExistentialTraitRef,
+    PolyProjectionPredicate, PolyRegionOutlivesPredicate, PolySubtypePredicate, PolyTraitPredicate,
+    PolyTraitRef, PolyTypeOutlivesPredicate, Predicate, PredicateKind, ProjectionPredicate,
+    RegionOutlivesPredicate, SubtypePredicate, ToPolyTraitRef, TraitPredicate, TraitRef,
+    TypeOutlivesPredicate,
 };
 pub use self::region::BoundRegionKind::*;
 pub use self::region::{
@@ -1994,14 +1995,82 @@
         (ident, scope)
     }
 
+    /// Checks whether this is a `const fn`. Returns `false` for non-functions.
+    ///
+    /// Even if this returns `true`, constness may still be unstable!
     #[inline]
-    pub fn is_const_fn_raw(self, def_id: DefId) -> bool {
+    pub fn is_const_fn(self, def_id: DefId) -> bool {
         matches!(
             self.def_kind(def_id),
-            DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(..) | DefKind::Closure
+            DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::Closure
         ) && self.constness(def_id) == hir::Constness::Const
     }
 
+    /// Whether this item is conditionally constant for the purposes of the
+    /// effects implementation.
+    ///
+    /// This roughly corresponds to all const functions and other callable
+    /// items, along with const impls and traits, and associated types within
+    /// those impls and traits.
+    pub fn is_conditionally_const(self, def_id: impl Into<DefId>) -> bool {
+        let def_id: DefId = def_id.into();
+        match self.def_kind(def_id) {
+            DefKind::Impl { of_trait: true } => {
+                self.constness(def_id) == hir::Constness::Const
+                    && self.is_const_trait(
+                        self.trait_id_of_impl(def_id)
+                            .expect("expected trait for trait implementation"),
+                    )
+            }
+            DefKind::Fn | DefKind::Ctor(_, CtorKind::Fn) => {
+                self.constness(def_id) == hir::Constness::Const
+            }
+            DefKind::Trait => self.is_const_trait(def_id),
+            DefKind::AssocTy | DefKind::AssocFn => {
+                let parent_def_id = self.parent(def_id);
+                match self.def_kind(parent_def_id) {
+                    DefKind::Impl { of_trait: false } => {
+                        self.constness(def_id) == hir::Constness::Const
+                    }
+                    DefKind::Impl { of_trait: true } | DefKind::Trait => {
+                        self.is_conditionally_const(parent_def_id)
+                    }
+                    _ => bug!("unexpected parent item of associated item: {parent_def_id:?}"),
+                }
+            }
+            DefKind::Closure | DefKind::OpaqueTy => {
+                // Closures and RPITs will eventually have const conditions
+                // for `~const` bounds.
+                false
+            }
+            DefKind::Ctor(_, CtorKind::Const)
+            | DefKind::Impl { of_trait: false }
+            | DefKind::Mod
+            | DefKind::Struct
+            | DefKind::Union
+            | DefKind::Enum
+            | DefKind::Variant
+            | DefKind::TyAlias
+            | DefKind::ForeignTy
+            | DefKind::TraitAlias
+            | DefKind::TyParam
+            | DefKind::Const
+            | DefKind::ConstParam
+            | DefKind::Static { .. }
+            | DefKind::AssocConst
+            | DefKind::Macro(_)
+            | DefKind::ExternCrate
+            | DefKind::Use
+            | DefKind::ForeignMod
+            | DefKind::AnonConst
+            | DefKind::InlineConst
+            | DefKind::Field
+            | DefKind::LifetimeParam
+            | DefKind::GlobalAsm
+            | DefKind::SyntheticCoroutineBody => false,
+        }
+    }
+
     #[inline]
     pub fn is_const_trait(self, def_id: DefId) -> bool {
         self.trait_def(def_id).constness == hir::Constness::Const
diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs
index 7e1255f..43bdce5 100644
--- a/compiler/rustc_middle/src/ty/parameterized.rs
+++ b/compiler/rustc_middle/src/ty/parameterized.rs
@@ -132,6 +132,7 @@
     ty::Ty,
     ty::FnSig,
     ty::GenericPredicates,
+    ty::ConstConditions,
     ty::TraitRef,
     ty::Const,
     ty::Predicate,
diff --git a/compiler/rustc_middle/src/ty/predicate.rs b/compiler/rustc_middle/src/ty/predicate.rs
index d20cb36..3ecaa3e 100644
--- a/compiler/rustc_middle/src/ty/predicate.rs
+++ b/compiler/rustc_middle/src/ty/predicate.rs
@@ -19,6 +19,7 @@
 pub type ExistentialTraitRef<'tcx> = ir::ExistentialTraitRef<TyCtxt<'tcx>>;
 pub type ExistentialProjection<'tcx> = ir::ExistentialProjection<TyCtxt<'tcx>>;
 pub type TraitPredicate<'tcx> = ir::TraitPredicate<TyCtxt<'tcx>>;
+pub type HostEffectPredicate<'tcx> = ir::HostEffectPredicate<TyCtxt<'tcx>>;
 pub type ClauseKind<'tcx> = ir::ClauseKind<TyCtxt<'tcx>>;
 pub type PredicateKind<'tcx> = ir::PredicateKind<TyCtxt<'tcx>>;
 pub type NormalizesTo<'tcx> = ir::NormalizesTo<TyCtxt<'tcx>>;
@@ -143,6 +144,7 @@
             | PredicateKind::AliasRelate(..)
             | PredicateKind::NormalizesTo(..) => false,
             PredicateKind::Clause(ClauseKind::Trait(_))
+            | PredicateKind::Clause(ClauseKind::HostEffect(..))
             | PredicateKind::Clause(ClauseKind::RegionOutlives(_))
             | PredicateKind::Clause(ClauseKind::TypeOutlives(_))
             | PredicateKind::Clause(ClauseKind::Projection(_))
@@ -644,6 +646,7 @@
         match predicate.skip_binder() {
             PredicateKind::Clause(ClauseKind::Trait(t)) => Some(predicate.rebind(t)),
             PredicateKind::Clause(ClauseKind::Projection(..))
+            | PredicateKind::Clause(ClauseKind::HostEffect(..))
             | PredicateKind::Clause(ClauseKind::ConstArgHasType(..))
             | PredicateKind::NormalizesTo(..)
             | PredicateKind::AliasRelate(..)
@@ -664,6 +667,7 @@
         match predicate.skip_binder() {
             PredicateKind::Clause(ClauseKind::Projection(t)) => Some(predicate.rebind(t)),
             PredicateKind::Clause(ClauseKind::Trait(..))
+            | PredicateKind::Clause(ClauseKind::HostEffect(..))
             | PredicateKind::Clause(ClauseKind::ConstArgHasType(..))
             | PredicateKind::NormalizesTo(..)
             | PredicateKind::AliasRelate(..)
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index b5495fa..0248aad 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -1208,7 +1208,7 @@
             }
         }
 
-        if self.tcx().features().return_type_notation
+        if self.tcx().features().return_type_notation()
             && let Some(ty::ImplTraitInTraitData::Trait { fn_def_id, .. }) =
                 self.tcx().opt_rpitit_info(def_id)
             && let ty::Alias(_, alias_ty) =
@@ -3075,6 +3075,15 @@
         p!(print(self.trait_ref.print_trait_sugared()))
     }
 
+    ty::HostEffectPredicate<'tcx> {
+        let constness = match self.host {
+            ty::HostPolarity::Const => { "const" }
+            ty::HostPolarity::Maybe => { "~const" }
+        };
+        p!(print(self.trait_ref.self_ty()), ": {constness} ");
+        p!(print(self.trait_ref.print_trait_sugared()))
+    }
+
     ty::TypeAndMut<'tcx> {
         p!(write("{}", self.mutbl.prefix_str()), print(self.ty))
     }
@@ -3087,6 +3096,7 @@
             ty::ClauseKind::RegionOutlives(predicate) => p!(print(predicate)),
             ty::ClauseKind::TypeOutlives(predicate) => p!(print(predicate)),
             ty::ClauseKind::Projection(predicate) => p!(print(predicate)),
+            ty::ClauseKind::HostEffect(predicate) => p!(print(predicate)),
             ty::ClauseKind::ConstArgHasType(ct, ty) => {
                 p!("the constant `", print(ct), "` has type `", print(ty), "`")
             },
diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs
index 4c7bcb1..504a3c8 100644
--- a/compiler/rustc_middle/src/ty/relate.rs
+++ b/compiler/rustc_middle/src/ty/relate.rs
@@ -1,7 +1,5 @@
 use std::iter;
 
-use rustc_hir as hir;
-use rustc_target::spec::abi;
 pub use rustc_type_ir::relate::*;
 
 use crate::ty::error::{ExpectedFound, TypeError};
@@ -121,26 +119,6 @@
     }
 }
 
-impl<'tcx> Relate<TyCtxt<'tcx>> for hir::Safety {
-    fn relate<R: TypeRelation<TyCtxt<'tcx>>>(
-        _relation: &mut R,
-        a: hir::Safety,
-        b: hir::Safety,
-    ) -> RelateResult<'tcx, hir::Safety> {
-        if a != b { Err(TypeError::SafetyMismatch(ExpectedFound::new(true, a, b))) } else { Ok(a) }
-    }
-}
-
-impl<'tcx> Relate<TyCtxt<'tcx>> for abi::Abi {
-    fn relate<R: TypeRelation<TyCtxt<'tcx>>>(
-        _relation: &mut R,
-        a: abi::Abi,
-        b: abi::Abi,
-    ) -> RelateResult<'tcx, abi::Abi> {
-        if a == b { Ok(a) } else { Err(TypeError::AbiMismatch(ExpectedFound::new(true, a, b))) }
-    }
-}
-
 impl<'tcx> Relate<TyCtxt<'tcx>> for ty::GenericArgsRef<'tcx> {
     fn relate<R: TypeRelation<TyCtxt<'tcx>>>(
         relation: &mut R,
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index cd9ff9b..4872d8c 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -264,8 +264,6 @@
 // interners).
 TrivialTypeTraversalAndLiftImpls! {
     ::rustc_hir::def_id::DefId,
-    ::rustc_hir::Safety,
-    ::rustc_target::spec::abi::Abi,
     crate::ty::ClosureKind,
     crate::ty::ParamConst,
     crate::ty::ParamTy,
@@ -276,6 +274,11 @@
     rustc_target::abi::Size,
 }
 
+TrivialLiftImpls! {
+    ::rustc_hir::Safety,
+    ::rustc_target::spec::abi::Abi,
+}
+
 ///////////////////////////////////////////////////////////////////////////
 // Lift implementations
 
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 74de378..d8362cc 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -750,7 +750,7 @@
 
     #[inline]
     pub fn new_diverging_default(tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
-        if tcx.features().never_type_fallback { tcx.types.never } else { tcx.types.unit }
+        if tcx.features().never_type_fallback() { tcx.types.never } else { tcx.types.unit }
     }
 
     // lang and diagnostic tys
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index 9a3049f..7fd7e46 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -17,10 +17,10 @@
 use rustc_target::abi::{Float, Integer, IntegerType, Size};
 use rustc_target::spec::abi::Abi;
 use smallvec::{SmallVec, smallvec};
-use tracing::{debug, instrument, trace};
+use tracing::{debug, instrument};
 
 use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
-use crate::query::{IntoQueryParam, Providers};
+use crate::query::Providers;
 use crate::ty::layout::{FloatExt, IntegerExt};
 use crate::ty::{
     self, Asyncness, FallibleTypeFolder, GenericArgKind, GenericArgsRef, Ty, TyCtxt, TypeFoldable,
@@ -865,48 +865,6 @@
             || self.extern_crate(key).is_some_and(|e| e.is_direct())
     }
 
-    /// Whether the item has a host effect param. This is different from `TyCtxt::is_const`,
-    /// because the item must also be "maybe const", and the crate where the item is
-    /// defined must also have the effects feature enabled.
-    pub fn has_host_param(self, def_id: impl IntoQueryParam<DefId>) -> bool {
-        self.generics_of(def_id).host_effect_index.is_some()
-    }
-
-    pub fn expected_host_effect_param_for_body(self, def_id: impl Into<DefId>) -> ty::Const<'tcx> {
-        let def_id = def_id.into();
-        // FIXME(effects): This is suspicious and should probably not be done,
-        // especially now that we enforce host effects and then properly handle
-        // effect vars during fallback.
-        let mut host_always_on =
-            !self.features().effects || self.sess.opts.unstable_opts.unleash_the_miri_inside_of_you;
-
-        // Compute the constness required by the context.
-        let const_context = self.hir().body_const_context(def_id);
-
-        let kind = self.def_kind(def_id);
-        debug_assert_ne!(kind, DefKind::ConstParam);
-
-        if self.has_attr(def_id, sym::rustc_do_not_const_check) {
-            trace!("do not const check this context");
-            host_always_on = true;
-        }
-
-        match const_context {
-            _ if host_always_on => self.consts.true_,
-            Some(hir::ConstContext::Static(_) | hir::ConstContext::Const { .. }) => {
-                self.consts.false_
-            }
-            Some(hir::ConstContext::ConstFn) => {
-                let host_idx = self
-                    .generics_of(def_id)
-                    .host_effect_index
-                    .expect("ConstContext::Maybe must have host effect param");
-                ty::GenericArgs::identity_for_item(self, def_id).const_at(host_idx)
-            }
-            None => self.consts.true_,
-        }
-    }
-
     /// Expand any [weak alias types][weak] contained within the given `value`.
     ///
     /// This should be used over other normalization routines in situations where
@@ -1826,8 +1784,8 @@
 /// cause an ICE that we otherwise may want to prevent.
 pub fn intrinsic_raw(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::IntrinsicDef> {
     if (matches!(tcx.fn_sig(def_id).skip_binder().abi(), Abi::RustIntrinsic)
-        && tcx.features().intrinsics)
-        || (tcx.has_attr(def_id, sym::rustc_intrinsic) && tcx.features().rustc_attrs)
+        && tcx.features().intrinsics())
+        || (tcx.has_attr(def_id, sym::rustc_intrinsic) && tcx.features().rustc_attrs())
     {
         Some(ty::IntrinsicDef {
             name: tcx.item_name(def_id.into()),
diff --git a/compiler/rustc_mir_build/src/build/expr/as_operand.rs b/compiler/rustc_mir_build/src/build/expr/as_operand.rs
index 1e67e75..112eac3 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_operand.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_operand.rs
@@ -163,7 +163,7 @@
 
         let tcx = this.tcx;
 
-        if tcx.features().unsized_fn_params {
+        if tcx.features().unsized_fn_params() {
             let ty = expr.ty;
             let param_env = this.param_env;
 
diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs
index 7170aeb..37cedd8 100644
--- a/compiler/rustc_mir_build/src/build/matches/test.rs
+++ b/compiler/rustc_mir_build/src/build/matches/test.rs
@@ -149,7 +149,7 @@
                 if let ty::Adt(def, _) = ty.kind()
                     && tcx.is_lang_item(def.did(), LangItem::String)
                 {
-                    if !tcx.features().string_deref_patterns {
+                    if !tcx.features().string_deref_patterns() {
                         span_bug!(
                             test.span,
                             "matching on `String` went through without enabling string_deref_patterns"
diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs
index dfc82f7..a7e56b8 100644
--- a/compiler/rustc_mir_build/src/build/scope.rs
+++ b/compiler/rustc_mir_build/src/build/scope.rs
@@ -1048,8 +1048,8 @@
         // | +------------|outer_scope cache|--+                    |
         // +------------------------------|middle_scope cache|------+
         //
-        // Now, a new, inner-most scope is added along with a new drop into
-        // both inner-most and outer-most scopes:
+        // Now, a new, innermost scope is added along with a new drop into
+        // both innermost and outermost scopes:
         //
         // +------------------------------------------------------------+
         // | +----------------------------------+                       |
@@ -1061,11 +1061,11 @@
         // +----=----------------|invalid middle_scope cache|-----------+
         //
         // If, when adding `drop(new)` we do not invalidate the cached blocks for both
-        // outer_scope and middle_scope, then, when building drops for the inner (right-most)
+        // outer_scope and middle_scope, then, when building drops for the inner (rightmost)
         // scope, the old, cached blocks, without `drop(new)` will get used, producing the
         // wrong results.
         //
-        // Note that this code iterates scopes from the inner-most to the outer-most,
+        // Note that this code iterates scopes from the innermost to the outermost,
         // invalidating caches of each scope visited. This way bare minimum of the
         // caches gets invalidated. i.e., if a new drop is added into the middle scope, the
         // cache of outer scope stays intact.
diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs
index 8512763..f3e6301 100644
--- a/compiler/rustc_mir_build/src/check_unsafety.rs
+++ b/compiler/rustc_mir_build/src/check_unsafety.rs
@@ -509,20 +509,12 @@
             }
             ExprKind::RawBorrow { arg, .. } => {
                 if let ExprKind::Scope { value: arg, .. } = self.thir[arg].kind
-                // THIR desugars UNSAFE_STATIC into *UNSAFE_STATIC_REF, where
-                // UNSAFE_STATIC_REF holds the addr of the UNSAFE_STATIC, so: take two steps
                     && let ExprKind::Deref { arg } = self.thir[arg].kind
-                    // FIXME(workingjubiee): we lack a clear reason to reject ThreadLocalRef here,
-                    // but we also have no conclusive reason to allow it either!
-                    && let ExprKind::StaticRef { .. } = self.thir[arg].kind
                 {
-                    // A raw ref to a place expr, even an "unsafe static", is okay!
-                    // We short-circuit to not recursively traverse this expression.
+                    // Taking a raw ref to a deref place expr is always safe.
+                    // Make sure the expression we're deref'ing is safe, though.
+                    visit::walk_expr(self, &self.thir[arg]);
                     return;
-                    // note: const_mut_refs enables this code, and it currently remains unsafe:
-                    // static mut BYTE: u8 = 0;
-                    // static mut BYTE_PTR: *mut u8 = unsafe { addr_of_mut!(BYTE) };
-                    // static mut DEREF_BYTE_PTR: *mut u8 = unsafe { addr_of_mut!(*BYTE_PTR) };
                 }
             }
             ExprKind::Deref { arg } => {
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index 5995d60..e282345 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -281,7 +281,14 @@
                 .unwrap_or_else(|e| panic!("could not compute layout for {param_env_ty:?}: {e:?}"))
                 .size;
 
-            let lit = ScalarInt::try_from_uint(discr_offset as u128, size).unwrap();
+            let (lit, overflowing) = ScalarInt::truncate_from_uint(discr_offset as u128, size);
+            if overflowing {
+                // An erroneous enum with too many variants for its repr will emit E0081 and E0370
+                self.tcx.dcx().span_delayed_bug(
+                    source.span,
+                    "overflowing enum wasn't rejected by hir analysis",
+                );
+            }
             let kind = ExprKind::NonHirLiteral { lit, user_ty: None };
             let offset = self.thir.exprs.push(Expr { temp_lifetime, ty: discr_ty, span, kind });
 
@@ -777,7 +784,7 @@
                 if_then_scope: region::Scope {
                     id: then.hir_id.local_id,
                     data: {
-                        if expr.span.at_least_rust_2024() && tcx.features().if_let_rescope {
+                        if expr.span.at_least_rust_2024() && tcx.features().if_let_rescope() {
                             region::ScopeData::IfThenRescope
                         } else {
                             region::ScopeData::IfThen
diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index ae77bce..8498df5 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -1126,7 +1126,7 @@
             .map(|witness| cx.print_witness_pat(witness))
             .collect::<Vec<String>>()
             .join(" | ");
-        if witnesses.iter().all(|p| p.is_never_pattern()) && cx.tcx.features().never_patterns {
+        if witnesses.iter().all(|p| p.is_never_pattern()) && cx.tcx.features().never_patterns() {
             // Arms with a never pattern don't take a body.
             pattern
         } else {
diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs
index faee40f..d0f62bd 100644
--- a/compiler/rustc_mir_dataflow/src/value_analysis.rs
+++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs
@@ -1177,7 +1177,7 @@
     /// The projection used to go from parent to this node (only None for root).
     proj_elem: Option<TrackElem>,
 
-    /// The left-most child.
+    /// The leftmost child.
     first_child: Option<PlaceIndex>,
 
     /// Index of the sibling to the right of this node.
diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs
index 0a413d6..cd29105 100644
--- a/compiler/rustc_mir_transform/src/coroutine.rs
+++ b/compiler/rustc_mir_transform/src/coroutine.rs
@@ -1497,7 +1497,7 @@
 ) {
     // No need to check if unsized_locals/unsized_fn_params is disabled,
     // since we will error during typeck.
-    if !tcx.features().unsized_locals && !tcx.features().unsized_fn_params {
+    if !tcx.features().unsized_locals() && !tcx.features().unsized_fn_params() {
         return;
     }
 
diff --git a/compiler/rustc_mir_transform/src/coverage/counters.rs b/compiler/rustc_mir_transform/src/coverage/counters.rs
index 9408815..cf9f698 100644
--- a/compiler/rustc_mir_transform/src/coverage/counters.rs
+++ b/compiler/rustc_mir_transform/src/coverage/counters.rs
@@ -5,7 +5,6 @@
 use rustc_data_structures::graph::DirectedGraph;
 use rustc_index::IndexVec;
 use rustc_index::bit_set::BitSet;
-use rustc_middle::bug;
 use rustc_middle::mir::coverage::{CounterId, CovTerm, Expression, ExpressionId, Op};
 use tracing::{debug, debug_span, instrument};
 
@@ -58,13 +57,13 @@
     counter_increment_sites: IndexVec<CounterId, CounterIncrementSite>,
 
     /// Coverage counters/expressions that are associated with individual BCBs.
-    bcb_counters: IndexVec<BasicCoverageBlock, Option<BcbCounter>>,
+    node_counters: IndexVec<BasicCoverageBlock, Option<BcbCounter>>,
     /// Coverage counters/expressions that are associated with the control-flow
     /// edge between two BCBs.
     ///
     /// We currently don't iterate over this map, but if we do in the future,
     /// switch it back to `FxIndexMap` to avoid query stability hazards.
-    bcb_edge_counters: FxHashMap<(BasicCoverageBlock, BasicCoverageBlock), BcbCounter>,
+    edge_counters: FxHashMap<(BasicCoverageBlock, BasicCoverageBlock), BcbCounter>,
 
     /// Table of expression data, associating each expression ID with its
     /// corresponding operator (+ or -) and its LHS/RHS operands.
@@ -78,20 +77,20 @@
     /// Ensures that each BCB node needing a counter has one, by creating physical
     /// counters or counter expressions for nodes and edges as required.
     pub(super) fn make_bcb_counters(
-        basic_coverage_blocks: &CoverageGraph,
+        graph: &CoverageGraph,
         bcb_needs_counter: &BitSet<BasicCoverageBlock>,
     ) -> Self {
-        let mut counters = MakeBcbCounters::new(basic_coverage_blocks, bcb_needs_counter);
-        counters.make_bcb_counters();
+        let mut builder = CountersBuilder::new(graph, bcb_needs_counter);
+        builder.make_bcb_counters();
 
-        counters.coverage_counters
+        builder.counters
     }
 
     fn with_num_bcbs(num_bcbs: usize) -> Self {
         Self {
             counter_increment_sites: IndexVec::new(),
-            bcb_counters: IndexVec::from_elem_n(None, num_bcbs),
-            bcb_edge_counters: FxHashMap::default(),
+            node_counters: IndexVec::from_elem_n(None, num_bcbs),
+            edge_counters: FxHashMap::default(),
             expressions: IndexVec::new(),
             expressions_memo: FxHashMap::default(),
         }
@@ -104,24 +103,18 @@
         BcbCounter::Counter { id }
     }
 
-    /// Creates a new physical counter attached a BCB node.
-    /// The node must not already have a counter.
+    /// Creates a new physical counter for a BCB node.
     fn make_phys_node_counter(&mut self, bcb: BasicCoverageBlock) -> BcbCounter {
-        let counter = self.make_counter_inner(CounterIncrementSite::Node { bcb });
-        debug!(?bcb, ?counter, "node gets a physical counter");
-        self.set_bcb_counter(bcb, counter)
+        self.make_counter_inner(CounterIncrementSite::Node { bcb })
     }
 
-    /// Creates a new physical counter attached to a BCB edge.
-    /// The edge must not already have a counter.
+    /// Creates a new physical counter for a BCB edge.
     fn make_phys_edge_counter(
         &mut self,
         from_bcb: BasicCoverageBlock,
         to_bcb: BasicCoverageBlock,
     ) -> BcbCounter {
-        let counter = self.make_counter_inner(CounterIncrementSite::Edge { from_bcb, to_bcb });
-        debug!(?from_bcb, ?to_bcb, ?counter, "edge gets a physical counter");
-        self.set_bcb_edge_counter(from_bcb, to_bcb, counter)
+        self.make_counter_inner(CounterIncrementSite::Edge { from_bcb, to_bcb })
     }
 
     fn make_expression(&mut self, lhs: BcbCounter, op: Op, rhs: BcbCounter) -> BcbCounter {
@@ -193,35 +186,31 @@
         self.counter_increment_sites.len()
     }
 
-    fn set_bcb_counter(&mut self, bcb: BasicCoverageBlock, counter_kind: BcbCounter) -> BcbCounter {
-        if let Some(replaced) = self.bcb_counters[bcb].replace(counter_kind) {
-            bug!(
-                "attempt to set a BasicCoverageBlock coverage counter more than once; \
-                {bcb:?} already had counter {replaced:?}",
-            );
-        } else {
-            counter_kind
-        }
+    fn set_node_counter(&mut self, bcb: BasicCoverageBlock, counter: BcbCounter) -> BcbCounter {
+        let existing = self.node_counters[bcb].replace(counter);
+        assert!(
+            existing.is_none(),
+            "node {bcb:?} already has a counter: {existing:?} => {counter:?}"
+        );
+        counter
     }
 
-    fn set_bcb_edge_counter(
+    fn set_edge_counter(
         &mut self,
         from_bcb: BasicCoverageBlock,
         to_bcb: BasicCoverageBlock,
-        counter_kind: BcbCounter,
+        counter: BcbCounter,
     ) -> BcbCounter {
-        if let Some(replaced) = self.bcb_edge_counters.insert((from_bcb, to_bcb), counter_kind) {
-            bug!(
-                "attempt to set an edge counter more than once; from_bcb: \
-                {from_bcb:?} already had counter {replaced:?}",
-            );
-        } else {
-            counter_kind
-        }
+        let existing = self.edge_counters.insert((from_bcb, to_bcb), counter);
+        assert!(
+            existing.is_none(),
+            "edge ({from_bcb:?} -> {to_bcb:?}) already has a counter: {existing:?} => {counter:?}"
+        );
+        counter
     }
 
     pub(super) fn term_for_bcb(&self, bcb: BasicCoverageBlock) -> Option<CovTerm> {
-        self.bcb_counters[bcb].map(|counter| counter.as_term())
+        self.node_counters[bcb].map(|counter| counter.as_term())
     }
 
     /// Returns an iterator over all the nodes/edges in the coverage graph that
@@ -238,7 +227,7 @@
     pub(super) fn bcb_nodes_with_coverage_expressions(
         &self,
     ) -> impl Iterator<Item = (BasicCoverageBlock, ExpressionId)> + Captures<'_> {
-        self.bcb_counters.iter_enumerated().filter_map(|(bcb, &counter_kind)| match counter_kind {
+        self.node_counters.iter_enumerated().filter_map(|(bcb, &counter)| match counter {
             // Yield the BCB along with its associated expression ID.
             Some(BcbCounter::Expression { id }) => Some((bcb, id)),
             // This BCB is associated with a counter or nothing, so skip it.
@@ -265,22 +254,20 @@
     }
 }
 
-/// Helper struct that allows counter creation to inspect the BCB graph.
-struct MakeBcbCounters<'a> {
-    coverage_counters: CoverageCounters,
-    basic_coverage_blocks: &'a CoverageGraph,
+/// Helper struct that allows counter creation to inspect the BCB graph, and
+/// the set of nodes that need counters.
+struct CountersBuilder<'a> {
+    counters: CoverageCounters,
+    graph: &'a CoverageGraph,
     bcb_needs_counter: &'a BitSet<BasicCoverageBlock>,
 }
 
-impl<'a> MakeBcbCounters<'a> {
-    fn new(
-        basic_coverage_blocks: &'a CoverageGraph,
-        bcb_needs_counter: &'a BitSet<BasicCoverageBlock>,
-    ) -> Self {
-        assert_eq!(basic_coverage_blocks.num_nodes(), bcb_needs_counter.domain_size());
+impl<'a> CountersBuilder<'a> {
+    fn new(graph: &'a CoverageGraph, bcb_needs_counter: &'a BitSet<BasicCoverageBlock>) -> Self {
+        assert_eq!(graph.num_nodes(), bcb_needs_counter.domain_size());
         Self {
-            coverage_counters: CoverageCounters::with_num_bcbs(basic_coverage_blocks.num_nodes()),
-            basic_coverage_blocks,
+            counters: CoverageCounters::with_num_bcbs(graph.num_nodes()),
+            graph,
             bcb_needs_counter,
         }
     }
@@ -293,13 +280,12 @@
         //
         // The traversal tries to ensure that, when a loop is encountered, all
         // nodes within the loop are visited before visiting any nodes outside
-        // the loop. It also keeps track of which loop(s) the traversal is
-        // currently inside.
-        let mut traversal = TraverseCoverageGraphWithLoops::new(self.basic_coverage_blocks);
+        // the loop.
+        let mut traversal = TraverseCoverageGraphWithLoops::new(self.graph);
         while let Some(bcb) = traversal.next() {
             let _span = debug_span!("traversal", ?bcb).entered();
             if self.bcb_needs_counter.contains(bcb) {
-                self.make_node_counter_and_out_edge_counters(&traversal, bcb);
+                self.make_node_counter_and_out_edge_counters(bcb);
             }
         }
 
@@ -312,36 +298,41 @@
 
     /// Make sure the given node has a node counter, and then make sure each of
     /// its out-edges has an edge counter (if appropriate).
-    #[instrument(level = "debug", skip(self, traversal))]
-    fn make_node_counter_and_out_edge_counters(
-        &mut self,
-        traversal: &TraverseCoverageGraphWithLoops<'_>,
-        from_bcb: BasicCoverageBlock,
-    ) {
+    #[instrument(level = "debug", skip(self))]
+    fn make_node_counter_and_out_edge_counters(&mut self, from_bcb: BasicCoverageBlock) {
         // First, ensure that this node has a counter of some kind.
         // We might also use that counter to compute one of the out-edge counters.
         let node_counter = self.get_or_make_node_counter(from_bcb);
 
-        let successors = self.basic_coverage_blocks.successors[from_bcb].as_slice();
+        let successors = self.graph.successors[from_bcb].as_slice();
 
         // If this node's out-edges won't sum to the node's counter,
         // then there's no reason to create edge counters here.
-        if !self.basic_coverage_blocks[from_bcb].is_out_summable {
+        if !self.graph[from_bcb].is_out_summable {
             return;
         }
 
-        // Determine the set of out-edges that don't yet have edge counters.
-        let candidate_successors = self.basic_coverage_blocks.successors[from_bcb]
+        // When choosing which out-edge should be given a counter expression, ignore edges that
+        // already have counters, or could use the existing counter of their target node.
+        let out_edge_has_counter = |to_bcb| {
+            if self.counters.edge_counters.contains_key(&(from_bcb, to_bcb)) {
+                return true;
+            }
+            self.graph.sole_predecessor(to_bcb) == Some(from_bcb)
+                && self.counters.node_counters[to_bcb].is_some()
+        };
+
+        // Determine the set of out-edges that could benefit from being given an expression.
+        let candidate_successors = self.graph.successors[from_bcb]
             .iter()
             .copied()
-            .filter(|&to_bcb| self.edge_has_no_counter(from_bcb, to_bcb))
+            .filter(|&to_bcb| !out_edge_has_counter(to_bcb))
             .collect::<Vec<_>>();
         debug!(?candidate_successors);
 
         // If there are out-edges without counters, choose one to be given an expression
         // (computed from this node and the other out-edges) instead of a physical counter.
-        let Some(expression_to_bcb) =
-            self.choose_out_edge_for_expression(traversal, &candidate_successors)
+        let Some(target_bcb) = self.choose_out_edge_for_expression(from_bcb, &candidate_successors)
         else {
             return;
         };
@@ -353,43 +344,44 @@
             .iter()
             .copied()
             // Skip the chosen edge, since we'll calculate its count from this sum.
-            .filter(|&to_bcb| to_bcb != expression_to_bcb)
+            .filter(|&edge_target_bcb| edge_target_bcb != target_bcb)
             .map(|to_bcb| self.get_or_make_edge_counter(from_bcb, to_bcb))
             .collect::<Vec<_>>();
-        let Some(sum_of_all_other_out_edges) =
-            self.coverage_counters.make_sum(&other_out_edge_counters)
+        let Some(sum_of_all_other_out_edges) = self.counters.make_sum(&other_out_edge_counters)
         else {
             return;
         };
 
         // Now create an expression for the chosen edge, by taking the counter
         // for its source node and subtracting the sum of its sibling out-edges.
-        let expression = self.coverage_counters.make_expression(
-            node_counter,
-            Op::Subtract,
-            sum_of_all_other_out_edges,
-        );
+        let expression =
+            self.counters.make_expression(node_counter, Op::Subtract, sum_of_all_other_out_edges);
 
-        debug!("{expression_to_bcb:?} gets an expression: {expression:?}");
-        if let Some(sole_pred) = self.basic_coverage_blocks.sole_predecessor(expression_to_bcb) {
-            // This edge normally wouldn't get its own counter, so attach the expression
-            // to its target node instead, so that `edge_has_no_counter` can see it.
-            assert_eq!(sole_pred, from_bcb);
-            self.coverage_counters.set_bcb_counter(expression_to_bcb, expression);
-        } else {
-            self.coverage_counters.set_bcb_edge_counter(from_bcb, expression_to_bcb, expression);
-        }
+        debug!("{target_bcb:?} gets an expression: {expression:?}");
+        self.counters.set_edge_counter(from_bcb, target_bcb, expression);
     }
 
     #[instrument(level = "debug", skip(self))]
     fn get_or_make_node_counter(&mut self, bcb: BasicCoverageBlock) -> BcbCounter {
         // If the BCB already has a counter, return it.
-        if let Some(counter_kind) = self.coverage_counters.bcb_counters[bcb] {
-            debug!("{bcb:?} already has a counter: {counter_kind:?}");
-            return counter_kind;
+        if let Some(counter) = self.counters.node_counters[bcb] {
+            debug!("{bcb:?} already has a counter: {counter:?}");
+            return counter;
         }
 
-        let predecessors = self.basic_coverage_blocks.predecessors[bcb].as_slice();
+        let counter = self.make_node_counter_inner(bcb);
+        self.counters.set_node_counter(bcb, counter)
+    }
+
+    fn make_node_counter_inner(&mut self, bcb: BasicCoverageBlock) -> BcbCounter {
+        // If the node's sole in-edge already has a counter, use that.
+        if let Some(sole_pred) = self.graph.sole_predecessor(bcb)
+            && let Some(&edge_counter) = self.counters.edge_counters.get(&(sole_pred, bcb))
+        {
+            return edge_counter;
+        }
+
+        let predecessors = self.graph.predecessors[bcb].as_slice();
 
         // Handle cases where we can't compute a node's count from its in-edges:
         // - START_BCB has no in-edges, so taking the sum would panic (or be wrong).
@@ -398,7 +390,9 @@
         //   leading to infinite recursion.
         if predecessors.len() <= 1 || predecessors.contains(&bcb) {
             debug!(?bcb, ?predecessors, "node has <=1 predecessors or is its own predecessor");
-            return self.coverage_counters.make_phys_node_counter(bcb);
+            let counter = self.counters.make_phys_node_counter(bcb);
+            debug!(?bcb, ?counter, "node gets a physical counter");
+            return counter;
         }
 
         // A BCB with multiple incoming edges can compute its count by ensuring that counters
@@ -408,13 +402,11 @@
             .copied()
             .map(|from_bcb| self.get_or_make_edge_counter(from_bcb, bcb))
             .collect::<Vec<_>>();
-        let sum_of_in_edges: BcbCounter = self
-            .coverage_counters
-            .make_sum(&in_edge_counters)
-            .expect("there must be at least one in-edge");
+        let sum_of_in_edges: BcbCounter =
+            self.counters.make_sum(&in_edge_counters).expect("there must be at least one in-edge");
 
         debug!("{bcb:?} gets a new counter (sum of predecessor counters): {sum_of_in_edges:?}");
-        self.coverage_counters.set_bcb_counter(bcb, sum_of_in_edges)
+        sum_of_in_edges
     }
 
     #[instrument(level = "debug", skip(self))]
@@ -423,9 +415,24 @@
         from_bcb: BasicCoverageBlock,
         to_bcb: BasicCoverageBlock,
     ) -> BcbCounter {
+        // If the edge already has a counter, return it.
+        if let Some(&counter) = self.counters.edge_counters.get(&(from_bcb, to_bcb)) {
+            debug!("Edge {from_bcb:?}->{to_bcb:?} already has a counter: {counter:?}");
+            return counter;
+        }
+
+        let counter = self.make_edge_counter_inner(from_bcb, to_bcb);
+        self.counters.set_edge_counter(from_bcb, to_bcb, counter)
+    }
+
+    fn make_edge_counter_inner(
+        &mut self,
+        from_bcb: BasicCoverageBlock,
+        to_bcb: BasicCoverageBlock,
+    ) -> BcbCounter {
         // If the target node has exactly one in-edge (i.e. this one), then just
         // use the node's counter, since it will have the same value.
-        if let Some(sole_pred) = self.basic_coverage_blocks.sole_predecessor(to_bcb) {
+        if let Some(sole_pred) = self.graph.sole_predecessor(to_bcb) {
             assert_eq!(sole_pred, from_bcb);
             // This call must take care not to invoke `get_or_make_edge` for
             // this edge, since that would result in infinite recursion!
@@ -434,33 +441,27 @@
 
         // If the source node has exactly one out-edge (i.e. this one) and would have
         // the same execution count as that edge, then just use the node's counter.
-        if let Some(simple_succ) = self.basic_coverage_blocks.simple_successor(from_bcb) {
+        if let Some(simple_succ) = self.graph.simple_successor(from_bcb) {
             assert_eq!(simple_succ, to_bcb);
             return self.get_or_make_node_counter(from_bcb);
         }
 
-        // If the edge already has a counter, return it.
-        if let Some(&counter_kind) =
-            self.coverage_counters.bcb_edge_counters.get(&(from_bcb, to_bcb))
-        {
-            debug!("Edge {from_bcb:?}->{to_bcb:?} already has a counter: {counter_kind:?}");
-            return counter_kind;
-        }
-
         // Make a new counter to count this edge.
-        self.coverage_counters.make_phys_edge_counter(from_bcb, to_bcb)
+        let counter = self.counters.make_phys_edge_counter(from_bcb, to_bcb);
+        debug!(?from_bcb, ?to_bcb, ?counter, "edge gets a physical counter");
+        counter
     }
 
     /// Given a set of candidate out-edges (represented by their successor node),
     /// choose one to be given a counter expression instead of a physical counter.
     fn choose_out_edge_for_expression(
         &self,
-        traversal: &TraverseCoverageGraphWithLoops<'_>,
+        from_bcb: BasicCoverageBlock,
         candidate_successors: &[BasicCoverageBlock],
     ) -> Option<BasicCoverageBlock> {
         // Try to find a candidate that leads back to the top of a loop,
         // because reloop edges tend to be executed more times than loop-exit edges.
-        if let Some(reloop_target) = self.find_good_reloop_edge(traversal, &candidate_successors) {
+        if let Some(reloop_target) = self.find_good_reloop_edge(from_bcb, &candidate_successors) {
             debug!("Selecting reloop target {reloop_target:?} to get an expression");
             return Some(reloop_target);
         }
@@ -479,7 +480,7 @@
     /// for them to be able to avoid a physical counter increment.
     fn find_good_reloop_edge(
         &self,
-        traversal: &TraverseCoverageGraphWithLoops<'_>,
+        from_bcb: BasicCoverageBlock,
         candidate_successors: &[BasicCoverageBlock],
     ) -> Option<BasicCoverageBlock> {
         // If there are no candidates, avoid iterating over the loop stack.
@@ -488,14 +489,15 @@
         }
 
         // Consider each loop on the current traversal context stack, top-down.
-        for reloop_bcbs in traversal.reloop_bcbs_per_loop() {
+        for loop_header_node in self.graph.loop_headers_containing(from_bcb) {
             // Try to find a candidate edge that doesn't exit this loop.
             for &target_bcb in candidate_successors {
                 // An edge is a reloop edge if its target dominates any BCB that has
                 // an edge back to the loop header. (Otherwise it's an exit edge.)
-                let is_reloop_edge = reloop_bcbs.iter().any(|&reloop_bcb| {
-                    self.basic_coverage_blocks.dominates(target_bcb, reloop_bcb)
-                });
+                let is_reloop_edge = self
+                    .graph
+                    .reloop_predecessors(loop_header_node)
+                    .any(|reloop_bcb| self.graph.dominates(target_bcb, reloop_bcb));
                 if is_reloop_edge {
                     // We found a good out-edge to be given an expression.
                     return Some(target_bcb);
@@ -508,21 +510,4 @@
 
         None
     }
-
-    #[inline]
-    fn edge_has_no_counter(
-        &self,
-        from_bcb: BasicCoverageBlock,
-        to_bcb: BasicCoverageBlock,
-    ) -> bool {
-        let edge_counter =
-            if let Some(sole_pred) = self.basic_coverage_blocks.sole_predecessor(to_bcb) {
-                assert_eq!(sole_pred, from_bcb);
-                self.coverage_counters.bcb_counters[to_bcb]
-            } else {
-                self.coverage_counters.bcb_edge_counters.get(&(from_bcb, to_bcb)).copied()
-            };
-
-        edge_counter.is_none()
-    }
 }
diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs
index d839f46..168262b 100644
--- a/compiler/rustc_mir_transform/src/coverage/graph.rs
+++ b/compiler/rustc_mir_transform/src/coverage/graph.rs
@@ -1,10 +1,11 @@
 use std::cmp::Ordering;
 use std::collections::VecDeque;
+use std::iter;
 use std::ops::{Index, IndexMut};
 
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fx::FxHashSet;
-use rustc_data_structures::graph::dominators::{self, Dominators};
+use rustc_data_structures::graph::dominators::Dominators;
 use rustc_data_structures::graph::{self, DirectedGraph, StartNode};
 use rustc_index::IndexVec;
 use rustc_index::bit_set::BitSet;
@@ -20,7 +21,17 @@
     bb_to_bcb: IndexVec<BasicBlock, Option<BasicCoverageBlock>>,
     pub(crate) successors: IndexVec<BasicCoverageBlock, Vec<BasicCoverageBlock>>,
     pub(crate) predecessors: IndexVec<BasicCoverageBlock, Vec<BasicCoverageBlock>>,
+
     dominators: Option<Dominators<BasicCoverageBlock>>,
+    /// Allows nodes to be compared in some total order such that _if_
+    /// `a` dominates `b`, then `a < b`. If neither node dominates the other,
+    /// their relative order is consistent but arbitrary.
+    dominator_order_rank: IndexVec<BasicCoverageBlock, u32>,
+    /// A loop header is a node that dominates one or more of its predecessors.
+    is_loop_header: BitSet<BasicCoverageBlock>,
+    /// For each node, the loop header node of its nearest enclosing loop.
+    /// This forms a linked list that can be traversed to find all enclosing loops.
+    enclosing_loop_header: IndexVec<BasicCoverageBlock, Option<BasicCoverageBlock>>,
 }
 
 impl CoverageGraph {
@@ -54,9 +65,47 @@
             }
         }
 
-        let mut this = Self { bcbs, bb_to_bcb, successors, predecessors, dominators: None };
+        let num_nodes = bcbs.len();
+        let mut this = Self {
+            bcbs,
+            bb_to_bcb,
+            successors,
+            predecessors,
+            dominators: None,
+            dominator_order_rank: IndexVec::from_elem_n(0, num_nodes),
+            is_loop_header: BitSet::new_empty(num_nodes),
+            enclosing_loop_header: IndexVec::from_elem_n(None, num_nodes),
+        };
+        assert_eq!(num_nodes, this.num_nodes());
 
-        this.dominators = Some(dominators::dominators(&this));
+        // Set the dominators first, because later init steps rely on them.
+        this.dominators = Some(graph::dominators::dominators(&this));
+
+        // Iterate over all nodes, such that dominating nodes are visited before
+        // the nodes they dominate. Either preorder or reverse postorder is fine.
+        let dominator_order = graph::iterate::reverse_post_order(&this, this.start_node());
+        // The coverage graph is created by traversal, so all nodes are reachable.
+        assert_eq!(dominator_order.len(), this.num_nodes());
+        for (rank, bcb) in (0u32..).zip(dominator_order) {
+            // The dominator rank of each node is its index in a dominator-order traversal.
+            this.dominator_order_rank[bcb] = rank;
+
+            // A node is a loop header if it dominates any of its predecessors.
+            if this.reloop_predecessors(bcb).next().is_some() {
+                this.is_loop_header.insert(bcb);
+            }
+
+            // If the immediate dominator is a loop header, that's our enclosing loop.
+            // Otherwise, inherit the immediate dominator's enclosing loop.
+            // (Dominator order ensures that we already processed the dominator.)
+            if let Some(dom) = this.dominators().immediate_dominator(bcb) {
+                this.enclosing_loop_header[bcb] = this
+                    .is_loop_header
+                    .contains(dom)
+                    .then_some(dom)
+                    .or_else(|| this.enclosing_loop_header[dom]);
+            }
+        }
 
         // The coverage graph's entry-point node (bcb0) always starts with bb0,
         // which never has predecessors. Any other blocks merged into bcb0 can't
@@ -152,8 +201,13 @@
     }
 
     #[inline(always)]
+    fn dominators(&self) -> &Dominators<BasicCoverageBlock> {
+        self.dominators.as_ref().unwrap()
+    }
+
+    #[inline(always)]
     pub(crate) fn dominates(&self, dom: BasicCoverageBlock, node: BasicCoverageBlock) -> bool {
-        self.dominators.as_ref().unwrap().dominates(dom, node)
+        self.dominators().dominates(dom, node)
     }
 
     #[inline(always)]
@@ -162,7 +216,7 @@
         a: BasicCoverageBlock,
         b: BasicCoverageBlock,
     ) -> Ordering {
-        self.dominators.as_ref().unwrap().cmp_in_dominator_order(a, b)
+        self.dominator_order_rank[a].cmp(&self.dominator_order_rank[b])
     }
 
     /// Returns the source of this node's sole in-edge, if it has exactly one.
@@ -193,6 +247,36 @@
             None
         }
     }
+
+    /// For each loop that contains the given node, yields the "loop header"
+    /// node representing that loop, from innermost to outermost. If the given
+    /// node is itself a loop header, it is yielded first.
+    pub(crate) fn loop_headers_containing(
+        &self,
+        bcb: BasicCoverageBlock,
+    ) -> impl Iterator<Item = BasicCoverageBlock> + Captures<'_> {
+        let self_if_loop_header = self.is_loop_header.contains(bcb).then_some(bcb).into_iter();
+
+        let mut curr = Some(bcb);
+        let strictly_enclosing = iter::from_fn(move || {
+            let enclosing = self.enclosing_loop_header[curr?];
+            curr = enclosing;
+            enclosing
+        });
+
+        self_if_loop_header.chain(strictly_enclosing)
+    }
+
+    /// For the given node, yields the subset of its predecessor nodes that
+    /// it dominates. If that subset is non-empty, the node is a "loop header",
+    /// and each of those predecessors represents an in-edge that jumps back to
+    /// the top of its loop.
+    pub(crate) fn reloop_predecessors(
+        &self,
+        to_bcb: BasicCoverageBlock,
+    ) -> impl Iterator<Item = BasicCoverageBlock> + Captures<'_> {
+        self.predecessors[to_bcb].iter().copied().filter(move |&pred| self.dominates(to_bcb, pred))
+    }
 }
 
 impl Index<BasicCoverageBlock> for CoverageGraph {
@@ -418,15 +502,12 @@
 pub(crate) struct TraverseCoverageGraphWithLoops<'a> {
     basic_coverage_blocks: &'a CoverageGraph,
 
-    backedges: IndexVec<BasicCoverageBlock, Vec<BasicCoverageBlock>>,
     context_stack: Vec<TraversalContext>,
     visited: BitSet<BasicCoverageBlock>,
 }
 
 impl<'a> TraverseCoverageGraphWithLoops<'a> {
     pub(crate) fn new(basic_coverage_blocks: &'a CoverageGraph) -> Self {
-        let backedges = find_loop_backedges(basic_coverage_blocks);
-
         let worklist = VecDeque::from([basic_coverage_blocks.start_node()]);
         let context_stack = vec![TraversalContext { loop_header: None, worklist }];
 
@@ -435,17 +516,7 @@
         // of the stack as loops are entered, and popped off of the stack when a loop's worklist is
         // exhausted.
         let visited = BitSet::new_empty(basic_coverage_blocks.num_nodes());
-        Self { basic_coverage_blocks, backedges, context_stack, visited }
-    }
-
-    /// For each loop on the loop context stack (top-down), yields a list of BCBs
-    /// within that loop that have an outgoing edge back to the loop header.
-    pub(crate) fn reloop_bcbs_per_loop(&self) -> impl Iterator<Item = &[BasicCoverageBlock]> {
-        self.context_stack
-            .iter()
-            .rev()
-            .filter_map(|context| context.loop_header)
-            .map(|header_bcb| self.backedges[header_bcb].as_slice())
+        Self { basic_coverage_blocks, context_stack, visited }
     }
 
     pub(crate) fn next(&mut self) -> Option<BasicCoverageBlock> {
@@ -467,7 +538,7 @@
             }
             debug!("Visiting {bcb:?}");
 
-            if self.backedges[bcb].len() > 0 {
+            if self.basic_coverage_blocks.is_loop_header.contains(bcb) {
                 debug!("{bcb:?} is a loop header! Start a new TraversalContext...");
                 self.context_stack
                     .push(TraversalContext { loop_header: Some(bcb), worklist: VecDeque::new() });
@@ -545,29 +616,6 @@
     }
 }
 
-fn find_loop_backedges(
-    basic_coverage_blocks: &CoverageGraph,
-) -> IndexVec<BasicCoverageBlock, Vec<BasicCoverageBlock>> {
-    let num_bcbs = basic_coverage_blocks.num_nodes();
-    let mut backedges = IndexVec::from_elem_n(Vec::<BasicCoverageBlock>::new(), num_bcbs);
-
-    // Identify loops by their backedges.
-    for (bcb, _) in basic_coverage_blocks.iter_enumerated() {
-        for &successor in &basic_coverage_blocks.successors[bcb] {
-            if basic_coverage_blocks.dominates(successor, bcb) {
-                let loop_header = successor;
-                let backedge_from_bcb = bcb;
-                debug!(
-                    "Found BCB backedge: {:?} -> loop_header: {:?}",
-                    backedge_from_bcb, loop_header
-                );
-                backedges[loop_header].push(backedge_from_bcb);
-            }
-        }
-    }
-    backedges
-}
-
 fn short_circuit_preorder<'a, 'tcx, F, Iter>(
     body: &'a mir::Body<'tcx>,
     filtered_successors: F,
diff --git a/compiler/rustc_mir_transform/src/coverage/mappings.rs b/compiler/rustc_mir_transform/src/coverage/mappings.rs
index bc86ae2..2db7c6c 100644
--- a/compiler/rustc_mir_transform/src/coverage/mappings.rs
+++ b/compiler/rustc_mir_transform/src/coverage/mappings.rs
@@ -363,7 +363,7 @@
             let ConditionInfo { condition_id, true_next_id, false_next_id } = branch.condition_info;
             [true_next_id, false_next_id]
                 .into_iter()
-                .filter_map(std::convert::identity)
+                .flatten()
                 .for_each(|next_id| indegree_stats[next_id] += 1);
             (condition_id, branch)
         })
diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs
index da7d20c..085c738 100644
--- a/compiler/rustc_mir_transform/src/coverage/spans.rs
+++ b/compiler/rustc_mir_transform/src/coverage/spans.rs
@@ -87,7 +87,7 @@
     covspans.retain(|covspan| {
         match covspan.expn_kind {
             // Retain only the first await-related or macro-expanded covspan with this span.
-            Some(ExpnKind::Desugaring(kind)) if kind == DesugaringKind::Await => {
+            Some(ExpnKind::Desugaring(DesugaringKind::Await)) => {
                 deduplicated_spans.insert(covspan.span)
             }
             Some(ExpnKind::Macro(MacroKind::Bang, _)) => deduplicated_spans.insert(covspan.span),
diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs
index daf8685..79c6237 100644
--- a/compiler/rustc_mir_transform/src/gvn.rs
+++ b/compiler/rustc_mir_transform/src/gvn.rs
@@ -288,7 +288,7 @@
             values: FxIndexSet::with_capacity_and_hasher(num_values, Default::default()),
             evaluated: IndexVec::with_capacity(num_values),
             next_opaque: Some(1),
-            feature_unsized_locals: tcx.features().unsized_locals,
+            feature_unsized_locals: tcx.features().unsized_locals(),
             ssa,
             dominators,
             reused_locals: BitSet::new_empty(local_decls.len()),
diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs
index c9f2476..42d6bdf 100644
--- a/compiler/rustc_mir_transform/src/inline.rs
+++ b/compiler/rustc_mir_transform/src/inline.rs
@@ -439,12 +439,7 @@
 
         // Reachability pass defines which functions are eligible for inlining. Generally inlining
         // other functions is incorrect because they could reference symbols that aren't exported.
-        let is_generic = callsite
-            .callee
-            .args
-            .non_erasable_generics(self.tcx, callsite.callee.def_id())
-            .next()
-            .is_some();
+        let is_generic = callsite.callee.args.non_erasable_generics().next().is_some();
         if !is_generic && !cross_crate_inlinable {
             return Err("not exported");
         }
diff --git a/compiler/rustc_mir_transform/src/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs
index 86c4b24..fa9a6bf 100644
--- a/compiler/rustc_mir_transform/src/promote_consts.rs
+++ b/compiler/rustc_mir_transform/src/promote_consts.rs
@@ -673,7 +673,7 @@
         }
         // Make sure the callee is a `const fn`.
         let is_const_fn = match *fn_ty.kind() {
-            ty::FnDef(def_id, _) => self.tcx.is_const_fn_raw(def_id),
+            ty::FnDef(def_id, _) => self.tcx.is_const_fn(def_id),
             _ => false,
         };
         if !is_const_fn {
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index b4d084d..8df6e63 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -504,7 +504,7 @@
     // Check for PMEs and emit a diagnostic if one happened. To try to show relevant edges of the
     // mono item graph.
     if tcx.dcx().err_count() > error_count
-        && starting_item.node.is_generic_fn(tcx)
+        && starting_item.node.is_generic_fn()
         && starting_item.node.is_user_defined()
     {
         let formatted_item = with_no_trimmed_paths!(starting_item.node.to_string());
@@ -1522,7 +1522,6 @@
     // it, to validate whether or not the impl is legal to instantiate at all.
     let only_region_params = |param: &ty::GenericParamDef, _: &_| match param.kind {
         GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(),
-        GenericParamDefKind::Const { is_host_effect: true, .. } => tcx.consts.true_.into(),
         GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
             unreachable!(
                 "`own_requires_monomorphization` check means that \
diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs
index 9bf7e67..e2a6d39 100644
--- a/compiler/rustc_monomorphize/src/partitioning.rs
+++ b/compiler/rustc_monomorphize/src/partitioning.rs
@@ -229,7 +229,7 @@
         }
 
         let characteristic_def_id = characteristic_def_id_of_mono_item(cx.tcx, mono_item);
-        let is_volatile = is_incremental_build && mono_item.is_generic_fn(cx.tcx);
+        let is_volatile = is_incremental_build && mono_item.is_generic_fn();
 
         let cgu_name = match characteristic_def_id {
             Some(def_id) => compute_codegen_unit_name(
@@ -822,7 +822,7 @@
         return Visibility::Hidden;
     }
 
-    let is_generic = instance.args.non_erasable_generics(tcx, def_id).next().is_some();
+    let is_generic = instance.args.non_erasable_generics().next().is_some();
 
     // Upstream `DefId` instances get different handling than local ones.
     let Some(def_id) = def_id.as_local() else {
diff --git a/compiler/rustc_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonicalizer.rs
index 23634d3..63608f9 100644
--- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs
+++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs
@@ -431,7 +431,6 @@
                     );
                     CanonicalVarKind::Const(self.delegate.universe_of_ct(vid).unwrap())
                 }
-                ty::InferConst::EffectVar(_) => CanonicalVarKind::Effect,
                 ty::InferConst::Fresh(_) => todo!(),
             },
             ty::ConstKind::Placeholder(placeholder) => match self.canonicalize_mode {
diff --git a/compiler/rustc_next_trait_solver/src/resolve.rs b/compiler/rustc_next_trait_solver/src/resolve.rs
index f2654f7..71c8771 100644
--- a/compiler/rustc_next_trait_solver/src/resolve.rs
+++ b/compiler/rustc_next_trait_solver/src/resolve.rs
@@ -76,9 +76,6 @@
                     resolved
                 }
             }
-            ty::ConstKind::Infer(ty::InferConst::EffectVar(vid)) => {
-                self.delegate.opportunistic_resolve_effect_var(vid)
-            }
             _ => {
                 if c.has_infer() {
                     c.super_fold_with(self)
diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
index c9c0d63..f6a5f20 100644
--- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
@@ -100,6 +100,15 @@
         })
     }
 
+    /// Assemble additional assumptions for an alias that are not included
+    /// in the item bounds of the alias. For now, this is limited to the
+    /// `implied_const_bounds` for an associated type.
+    fn consider_additional_alias_assumptions(
+        ecx: &mut EvalCtxt<'_, D>,
+        goal: Goal<I, Self>,
+        alias_ty: ty::AliasTy<I>,
+    ) -> Vec<Candidate<I>>;
+
     fn consider_impl_candidate(
         ecx: &mut EvalCtxt<'_, D>,
         goal: Goal<I, Self>,
@@ -270,11 +279,6 @@
         ecx: &mut EvalCtxt<'_, D>,
         goal: Goal<I, Self>,
     ) -> Vec<Candidate<I>>;
-
-    fn consider_builtin_effects_intersection_candidate(
-        ecx: &mut EvalCtxt<'_, D>,
-        goal: Goal<I, Self>,
-    ) -> Result<Candidate<I>, NoSolution>;
 }
 
 impl<D, I> EvalCtxt<'_, D>
@@ -481,9 +485,6 @@
                 Some(TraitSolverLangItem::TransmuteTrait) => {
                     G::consider_builtin_transmute_candidate(self, goal)
                 }
-                Some(TraitSolverLangItem::EffectsIntersection) => {
-                    G::consider_builtin_effects_intersection_candidate(self, goal)
-                }
                 _ => Err(NoSolution),
             }
         };
@@ -602,6 +603,8 @@
             ));
         }
 
+        candidates.extend(G::consider_additional_alias_assumptions(self, goal, alias_ty));
+
         if kind != ty::Projection {
             return;
         }
diff --git a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs
new file mode 100644
index 0000000..8d57ad8
--- /dev/null
+++ b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs
@@ -0,0 +1,345 @@
+//! Dealing with host effect goals, i.e. enforcing the constness in
+//! `T: const Trait` or `T: ~const Trait`.
+
+use rustc_type_ir::fast_reject::DeepRejectCtxt;
+use rustc_type_ir::inherent::*;
+use rustc_type_ir::{self as ty, Interner, elaborate};
+use tracing::instrument;
+
+use super::assembly::Candidate;
+use crate::delegate::SolverDelegate;
+use crate::solve::assembly::{self};
+use crate::solve::{
+    BuiltinImplSource, CandidateSource, Certainty, EvalCtxt, Goal, GoalSource, NoSolution,
+    QueryResult,
+};
+
+impl<D, I> assembly::GoalKind<D> for ty::HostEffectPredicate<I>
+where
+    D: SolverDelegate<Interner = I>,
+    I: Interner,
+{
+    fn self_ty(self) -> I::Ty {
+        self.self_ty()
+    }
+
+    fn trait_ref(self, _: I) -> ty::TraitRef<I> {
+        self.trait_ref
+    }
+
+    fn with_self_ty(self, cx: I, self_ty: I::Ty) -> Self {
+        self.with_self_ty(cx, self_ty)
+    }
+
+    fn trait_def_id(self, _: I) -> I::DefId {
+        self.def_id()
+    }
+
+    fn probe_and_match_goal_against_assumption(
+        ecx: &mut EvalCtxt<'_, D>,
+        source: rustc_type_ir::solve::CandidateSource<I>,
+        goal: Goal<I, Self>,
+        assumption: <I as Interner>::Clause,
+        then: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResult<I>,
+    ) -> Result<Candidate<I>, NoSolution> {
+        if let Some(host_clause) = assumption.as_host_effect_clause() {
+            if host_clause.def_id() == goal.predicate.def_id()
+                && host_clause.host().satisfies(goal.predicate.host)
+            {
+                if !DeepRejectCtxt::relate_rigid_rigid(ecx.cx()).args_may_unify(
+                    goal.predicate.trait_ref.args,
+                    host_clause.skip_binder().trait_ref.args,
+                ) {
+                    return Err(NoSolution);
+                }
+
+                ecx.probe_trait_candidate(source).enter(|ecx| {
+                    let assumption_trait_pred = ecx.instantiate_binder_with_infer(host_clause);
+                    ecx.eq(
+                        goal.param_env,
+                        goal.predicate.trait_ref,
+                        assumption_trait_pred.trait_ref,
+                    )?;
+                    then(ecx)
+                })
+            } else {
+                Err(NoSolution)
+            }
+        } else {
+            Err(NoSolution)
+        }
+    }
+
+    /// Register additional assumptions for aliases corresponding to `~const` item bounds.
+    ///
+    /// Unlike item bounds, they are not simply implied by the well-formedness of the alias.
+    /// Instead, they only hold if the const conditons on the alias also hold. This is why
+    /// we also register the const conditions of the alias after matching the goal against
+    /// the assumption.
+    fn consider_additional_alias_assumptions(
+        ecx: &mut EvalCtxt<'_, D>,
+        goal: Goal<I, Self>,
+        alias_ty: ty::AliasTy<I>,
+    ) -> Vec<Candidate<I>> {
+        let cx = ecx.cx();
+        let mut candidates = vec![];
+
+        // FIXME(effects): We elaborate here because the implied const bounds
+        // aren't necessarily elaborated. We probably should prefix this query
+        // with `explicit_`...
+        for clause in elaborate::elaborate(
+            cx,
+            cx.implied_const_bounds(alias_ty.def_id)
+                .iter_instantiated(cx, alias_ty.args)
+                .map(|trait_ref| trait_ref.to_host_effect_clause(cx, goal.predicate.host)),
+        ) {
+            candidates.extend(Self::probe_and_match_goal_against_assumption(
+                ecx,
+                CandidateSource::AliasBound,
+                goal,
+                clause,
+                |ecx| {
+                    // Const conditions must hold for the implied const bound to hold.
+                    ecx.add_goals(
+                        GoalSource::Misc,
+                        cx.const_conditions(alias_ty.def_id)
+                            .iter_instantiated(cx, alias_ty.args)
+                            .map(|trait_ref| {
+                                goal.with(
+                                    cx,
+                                    trait_ref.to_host_effect_clause(cx, goal.predicate.host),
+                                )
+                            }),
+                    );
+                    ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+                },
+            ));
+        }
+
+        candidates
+    }
+
+    fn consider_impl_candidate(
+        ecx: &mut EvalCtxt<'_, D>,
+        goal: Goal<I, Self>,
+        impl_def_id: <I as Interner>::DefId,
+    ) -> Result<Candidate<I>, NoSolution> {
+        let cx = ecx.cx();
+
+        let impl_trait_ref = cx.impl_trait_ref(impl_def_id);
+        if !DeepRejectCtxt::relate_rigid_infer(ecx.cx())
+            .args_may_unify(goal.predicate.trait_ref.args, impl_trait_ref.skip_binder().args)
+        {
+            return Err(NoSolution);
+        }
+
+        let impl_polarity = cx.impl_polarity(impl_def_id);
+        match impl_polarity {
+            ty::ImplPolarity::Negative => return Err(NoSolution),
+            ty::ImplPolarity::Reservation => {
+                unimplemented!("reservation impl for const trait: {:?}", goal)
+            }
+            ty::ImplPolarity::Positive => {}
+        };
+
+        if !cx.is_const_impl(impl_def_id) {
+            return Err(NoSolution);
+        }
+
+        ecx.probe_trait_candidate(CandidateSource::Impl(impl_def_id)).enter(|ecx| {
+            let impl_args = ecx.fresh_args_for_item(impl_def_id);
+            ecx.record_impl_args(impl_args);
+            let impl_trait_ref = impl_trait_ref.instantiate(cx, impl_args);
+
+            ecx.eq(goal.param_env, goal.predicate.trait_ref, impl_trait_ref)?;
+            let where_clause_bounds = cx
+                .predicates_of(impl_def_id)
+                .iter_instantiated(cx, impl_args)
+                .map(|pred| goal.with(cx, pred));
+            ecx.add_goals(GoalSource::ImplWhereBound, where_clause_bounds);
+
+            // For this impl to be `const`, we need to check its `~const` bounds too.
+            let const_conditions = cx
+                .const_conditions(impl_def_id)
+                .iter_instantiated(cx, impl_args)
+                .map(|bound_trait_ref| {
+                    goal.with(cx, bound_trait_ref.to_host_effect_clause(cx, goal.predicate.host))
+                });
+            ecx.add_goals(GoalSource::ImplWhereBound, const_conditions);
+
+            ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+        })
+    }
+
+    fn consider_error_guaranteed_candidate(
+        ecx: &mut EvalCtxt<'_, D>,
+        _guar: <I as Interner>::ErrorGuaranteed,
+    ) -> Result<Candidate<I>, NoSolution> {
+        ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
+            .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
+    }
+
+    fn consider_auto_trait_candidate(
+        _ecx: &mut EvalCtxt<'_, D>,
+        _goal: Goal<I, Self>,
+    ) -> Result<Candidate<I>, NoSolution> {
+        unreachable!("auto traits are never const")
+    }
+
+    fn consider_trait_alias_candidate(
+        _ecx: &mut EvalCtxt<'_, D>,
+        _goal: Goal<I, Self>,
+    ) -> Result<Candidate<I>, NoSolution> {
+        unreachable!("trait aliases are never const")
+    }
+
+    fn consider_builtin_sized_candidate(
+        _ecx: &mut EvalCtxt<'_, D>,
+        _goal: Goal<I, Self>,
+    ) -> Result<Candidate<I>, NoSolution> {
+        unreachable!("Sized is never const")
+    }
+
+    fn consider_builtin_copy_clone_candidate(
+        _ecx: &mut EvalCtxt<'_, D>,
+        _goal: Goal<I, Self>,
+    ) -> Result<Candidate<I>, NoSolution> {
+        todo!("Copy/Clone is not yet const")
+    }
+
+    fn consider_builtin_pointer_like_candidate(
+        _ecx: &mut EvalCtxt<'_, D>,
+        _goal: Goal<I, Self>,
+    ) -> Result<Candidate<I>, NoSolution> {
+        unreachable!("PointerLike is not const")
+    }
+
+    fn consider_builtin_fn_ptr_trait_candidate(
+        _ecx: &mut EvalCtxt<'_, D>,
+        _goal: Goal<I, Self>,
+    ) -> Result<Candidate<I>, NoSolution> {
+        todo!("Fn* are not yet const")
+    }
+
+    fn consider_builtin_fn_trait_candidates(
+        _ecx: &mut EvalCtxt<'_, D>,
+        _goal: Goal<I, Self>,
+        _kind: rustc_type_ir::ClosureKind,
+    ) -> Result<Candidate<I>, NoSolution> {
+        todo!("Fn* are not yet const")
+    }
+
+    fn consider_builtin_async_fn_trait_candidates(
+        _ecx: &mut EvalCtxt<'_, D>,
+        _goal: Goal<I, Self>,
+        _kind: rustc_type_ir::ClosureKind,
+    ) -> Result<Candidate<I>, NoSolution> {
+        todo!("AsyncFn* are not yet const")
+    }
+
+    fn consider_builtin_async_fn_kind_helper_candidate(
+        _ecx: &mut EvalCtxt<'_, D>,
+        _goal: Goal<I, Self>,
+    ) -> Result<Candidate<I>, NoSolution> {
+        unreachable!("AsyncFnKindHelper is not const")
+    }
+
+    fn consider_builtin_tuple_candidate(
+        _ecx: &mut EvalCtxt<'_, D>,
+        _goal: Goal<I, Self>,
+    ) -> Result<Candidate<I>, NoSolution> {
+        unreachable!("Tuple trait is not const")
+    }
+
+    fn consider_builtin_pointee_candidate(
+        _ecx: &mut EvalCtxt<'_, D>,
+        _goal: Goal<I, Self>,
+    ) -> Result<Candidate<I>, NoSolution> {
+        unreachable!("Pointee is not const")
+    }
+
+    fn consider_builtin_future_candidate(
+        _ecx: &mut EvalCtxt<'_, D>,
+        _goal: Goal<I, Self>,
+    ) -> Result<Candidate<I>, NoSolution> {
+        unreachable!("Future is not const")
+    }
+
+    fn consider_builtin_iterator_candidate(
+        _ecx: &mut EvalCtxt<'_, D>,
+        _goal: Goal<I, Self>,
+    ) -> Result<Candidate<I>, NoSolution> {
+        todo!("Iterator is not yet const")
+    }
+
+    fn consider_builtin_fused_iterator_candidate(
+        _ecx: &mut EvalCtxt<'_, D>,
+        _goal: Goal<I, Self>,
+    ) -> Result<Candidate<I>, NoSolution> {
+        unreachable!("FusedIterator is not const")
+    }
+
+    fn consider_builtin_async_iterator_candidate(
+        _ecx: &mut EvalCtxt<'_, D>,
+        _goal: Goal<I, Self>,
+    ) -> Result<Candidate<I>, NoSolution> {
+        unreachable!("AsyncIterator is not const")
+    }
+
+    fn consider_builtin_coroutine_candidate(
+        _ecx: &mut EvalCtxt<'_, D>,
+        _goal: Goal<I, Self>,
+    ) -> Result<Candidate<I>, NoSolution> {
+        unreachable!("Coroutine is not const")
+    }
+
+    fn consider_builtin_discriminant_kind_candidate(
+        _ecx: &mut EvalCtxt<'_, D>,
+        _goal: Goal<I, Self>,
+    ) -> Result<Candidate<I>, NoSolution> {
+        unreachable!("DiscriminantKind is not const")
+    }
+
+    fn consider_builtin_async_destruct_candidate(
+        _ecx: &mut EvalCtxt<'_, D>,
+        _goal: Goal<I, Self>,
+    ) -> Result<Candidate<I>, NoSolution> {
+        unreachable!("AsyncDestruct is not const")
+    }
+
+    fn consider_builtin_destruct_candidate(
+        _ecx: &mut EvalCtxt<'_, D>,
+        _goal: Goal<I, Self>,
+    ) -> Result<Candidate<I>, NoSolution> {
+        unreachable!("Destruct is not const")
+    }
+
+    fn consider_builtin_transmute_candidate(
+        _ecx: &mut EvalCtxt<'_, D>,
+        _goal: Goal<I, Self>,
+    ) -> Result<Candidate<I>, NoSolution> {
+        unreachable!("TransmuteFrom is not const")
+    }
+
+    fn consider_structural_builtin_unsize_candidates(
+        _ecx: &mut EvalCtxt<'_, D>,
+        _goal: Goal<I, Self>,
+    ) -> Vec<Candidate<I>> {
+        unreachable!("Unsize is not const")
+    }
+}
+
+impl<D, I> EvalCtxt<'_, D>
+where
+    D: SolverDelegate<Interner = I>,
+    I: Interner,
+{
+    #[instrument(level = "trace", skip(self))]
+    pub(super) fn compute_host_effect_goal(
+        &mut self,
+        goal: Goal<I, ty::HostEffectPredicate<I>>,
+    ) -> QueryResult<I> {
+        let candidates = self.assemble_and_evaluate_candidates(goal);
+        self.merge_candidates(candidates)
+    }
+}
diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs
index 71ce0cc..e2fd0dd 100644
--- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs
@@ -170,7 +170,7 @@
         //
         // We don't do so for `NormalizesTo` goals as we erased the expected term and
         // bailing with overflow here would prevent us from detecting a type-mismatch,
-        // causing a coherence error in diesel, see #131969. We still bail with verflow
+        // causing a coherence error in diesel, see #131969. We still bail with overflow
         // when later returning from the parent AliasRelate goal.
         if !self.is_normalizes_to_goal {
             let num_non_region_vars =
diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs
index cbefc82..7608253 100644
--- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs
@@ -291,7 +291,7 @@
             search_graph,
             nested_goals: NestedGoals::new(),
             tainted: Ok(()),
-            inspect: canonical_goal_evaluation.new_goal_evaluation_step(var_values, input),
+            inspect: canonical_goal_evaluation.new_goal_evaluation_step(var_values),
         };
 
         for &(key, ty) in &input.predefined_opaques_in_body.opaque_types {
@@ -443,6 +443,9 @@
                 ty::PredicateKind::Clause(ty::ClauseKind::Trait(predicate)) => {
                     self.compute_trait_goal(Goal { param_env, predicate })
                 }
+                ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(predicate)) => {
+                    self.compute_host_effect_goal(Goal { param_env, predicate })
+                }
                 ty::PredicateKind::Clause(ty::ClauseKind::Projection(predicate)) => {
                     self.compute_projection_goal(Goal { param_env, predicate })
                 }
diff --git a/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs b/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs
index 85474bf..1607fbb 100644
--- a/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs
@@ -13,7 +13,7 @@
 use crate::delegate::SolverDelegate;
 use crate::solve::eval_ctxt::canonical;
 use crate::solve::{
-    CanonicalInput, Certainty, GenerateProofTree, Goal, GoalEvaluationKind, GoalSource, QueryInput,
+    CanonicalInput, Certainty, GenerateProofTree, Goal, GoalEvaluationKind, GoalSource,
     QueryResult, inspect,
 };
 
@@ -119,6 +119,9 @@
     }
 }
 
+/// This only exists during proof tree building and does not have
+/// a corresponding struct in `inspect`. We need this to track a
+/// bunch of metadata about the current evaluation.
 #[derive_where(PartialEq, Eq, Debug; I: Interner)]
 struct WipCanonicalGoalEvaluationStep<I: Interner> {
     /// Unlike `EvalCtxt::var_values`, we append a new
@@ -128,7 +131,6 @@
     /// This is necessary as we otherwise don't unify these
     /// vars when instantiating multiple `CanonicalState`.
     var_values: Vec<I::GenericArg>,
-    instantiated_goal: QueryInput<I, I::Predicate>,
     probe_depth: usize,
     evaluation: WipProbe<I>,
 }
@@ -145,16 +147,12 @@
         current
     }
 
-    fn finalize(self) -> inspect::CanonicalGoalEvaluationStep<I> {
+    fn finalize(self) -> inspect::Probe<I> {
         let evaluation = self.evaluation.finalize();
         match evaluation.kind {
-            inspect::ProbeKind::Root { .. } => (),
+            inspect::ProbeKind::Root { .. } => evaluation,
             _ => unreachable!("unexpected root evaluation: {evaluation:?}"),
         }
-        inspect::CanonicalGoalEvaluationStep {
-            instantiated_goal: self.instantiated_goal,
-            evaluation,
-        }
     }
 }
 
@@ -328,11 +326,9 @@
     pub(crate) fn new_goal_evaluation_step(
         &mut self,
         var_values: ty::CanonicalVarValues<I>,
-        instantiated_goal: QueryInput<I, I::Predicate>,
     ) -> ProofTreeBuilder<D> {
         self.nested(|| WipCanonicalGoalEvaluationStep {
             var_values: var_values.var_values.to_vec(),
-            instantiated_goal,
             evaluation: WipProbe {
                 initial_num_var_values: var_values.len(),
                 steps: vec![],
diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs
index a475a58..6793779 100644
--- a/compiler/rustc_next_trait_solver/src/solve/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs
@@ -13,6 +13,7 @@
 
 mod alias_relate;
 mod assembly;
+mod effect_goals;
 mod eval_ctxt;
 pub mod inspect;
 mod normalizes_to;
@@ -182,12 +183,6 @@
         let (ct, ty) = goal.predicate;
 
         let ct_ty = match ct.kind() {
-            // FIXME: Ignore effect vars because canonicalization doesn't handle them correctly
-            // and if we stall on the var then we wind up creating ambiguity errors in a probe
-            // for this goal which contains an effect var. Which then ends up ICEing.
-            ty::ConstKind::Infer(ty::InferConst::EffectVar(_)) => {
-                return self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes);
-            }
             ty::ConstKind::Infer(_) => {
                 return self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS);
             }
diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs
index 4d8b193..7287cdf 100644
--- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs
@@ -193,6 +193,14 @@
         }
     }
 
+    fn consider_additional_alias_assumptions(
+        _ecx: &mut EvalCtxt<'_, D>,
+        _goal: Goal<I, Self>,
+        _alias_ty: ty::AliasTy<I>,
+    ) -> Vec<Candidate<I>> {
+        vec![]
+    }
+
     fn consider_impl_candidate(
         ecx: &mut EvalCtxt<'_, D>,
         goal: Goal<I, NormalizesTo<I>>,
@@ -911,68 +919,6 @@
     ) -> Result<Candidate<I>, NoSolution> {
         panic!("`TransmuteFrom` does not have an associated type: {:?}", goal)
     }
-
-    fn consider_builtin_effects_intersection_candidate(
-        ecx: &mut EvalCtxt<'_, D>,
-        goal: Goal<I, Self>,
-    ) -> Result<Candidate<I>, NoSolution> {
-        let ty::Tuple(types) = goal.predicate.self_ty().kind() else {
-            return Err(NoSolution);
-        };
-
-        let cx = ecx.cx();
-
-        let mut first_non_maybe = None;
-        let mut non_maybe_count = 0;
-        for ty in types.iter() {
-            if !matches!(ty::EffectKind::try_from_ty(cx, ty), Some(ty::EffectKind::Maybe)) {
-                first_non_maybe.get_or_insert(ty);
-                non_maybe_count += 1;
-            }
-        }
-
-        match non_maybe_count {
-            0 => {
-                let ty = ty::EffectKind::Maybe.to_ty(cx);
-                ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
-                    ecx.instantiate_normalizes_to_term(goal, ty.into());
-                    ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
-                })
-            }
-            1 => {
-                let ty = first_non_maybe.unwrap();
-                ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
-                    ecx.instantiate_normalizes_to_term(goal, ty.into());
-                    ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
-                })
-            }
-            _ => {
-                let mut min = ty::EffectKind::Maybe;
-
-                for ty in types.iter() {
-                    // We can't find the intersection if the types used are generic.
-                    //
-                    // FIXME(effects): do we want to look at where clauses to get some
-                    // clue for the case where generic types are being used?
-                    let Some(kind) = ty::EffectKind::try_from_ty(cx, ty) else {
-                        return Err(NoSolution);
-                    };
-
-                    let Some(result) = ty::EffectKind::intersection(min, kind) else {
-                        return Err(NoSolution);
-                    };
-
-                    min = result;
-                }
-
-                let ty = min.to_ty(cx);
-                ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
-                    ecx.instantiate_normalizes_to_term(goal, ty.into());
-                    ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
-                })
-            }
-        }
-    }
 }
 
 impl<D, I> EvalCtxt<'_, D>
diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
index a8d6536..08cc89d 100644
--- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
@@ -39,6 +39,14 @@
         self.def_id()
     }
 
+    fn consider_additional_alias_assumptions(
+        _ecx: &mut EvalCtxt<'_, D>,
+        _goal: Goal<I, Self>,
+        _alias_ty: ty::AliasTy<I>,
+    ) -> Vec<Candidate<I>> {
+        vec![]
+    }
+
     fn consider_impl_candidate(
         ecx: &mut EvalCtxt<'_, D>,
         goal: Goal<I, TraitPredicate<I>>,
@@ -719,47 +727,6 @@
             }
         })
     }
-
-    fn consider_builtin_effects_intersection_candidate(
-        ecx: &mut EvalCtxt<'_, D>,
-        goal: Goal<I, Self>,
-    ) -> Result<Candidate<I>, NoSolution> {
-        if goal.predicate.polarity != ty::PredicatePolarity::Positive {
-            return Err(NoSolution);
-        }
-
-        let ty::Tuple(types) = goal.predicate.self_ty().kind() else {
-            return Err(NoSolution);
-        };
-
-        let cx = ecx.cx();
-        let maybe_count = types
-            .iter()
-            .filter_map(|ty| ty::EffectKind::try_from_ty(cx, ty))
-            .filter(|&ty| ty == ty::EffectKind::Maybe)
-            .count();
-
-        // Don't do concrete type check unless there are more than one type that will influence the result.
-        // This would allow `(Maybe, T): Min` pass even if we know nothing about `T`.
-        if types.len() - maybe_count > 1 {
-            let mut min = ty::EffectKind::Maybe;
-
-            for ty in types.iter() {
-                let Some(kind) = ty::EffectKind::try_from_ty(ecx.cx(), ty) else {
-                    return Err(NoSolution);
-                };
-
-                let Some(result) = ty::EffectKind::intersection(min, kind) else {
-                    return Err(NoSolution);
-                };
-
-                min = result;
-            }
-        }
-
-        ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
-            .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
-    }
 }
 
 impl<D, I> EvalCtxt<'_, D>
diff --git a/compiler/rustc_parse/src/lexer/diagnostics.rs b/compiler/rustc_parse/src/lexer/diagnostics.rs
index 41108c9..e1f19be 100644
--- a/compiler/rustc_parse/src/lexer/diagnostics.rs
+++ b/compiler/rustc_parse/src/lexer/diagnostics.rs
@@ -85,7 +85,7 @@
         }
     }
 
-    // Find the inner-most span candidate for final report
+    // Find the innermost span candidate for final report
     let candidate_span =
         matched_spans.into_iter().rev().find(|&(_, same_ident)| !same_ident).map(|(span, _)| span);
 
diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl
index 3613b7b..e5e70ba 100644
--- a/compiler/rustc_passes/messages.ftl
+++ b/compiler/rustc_passes/messages.ftl
@@ -99,6 +99,10 @@
 passes_confusables = attribute should be applied to an inherent method
     .label = not an inherent method
 
+passes_const_stable_not_stable =
+    attribute `#[rustc_const_stable]` can only be applied to functions that are declared `#[stable]`
+    .label = attribute specified here
+
 passes_continue_labeled_block =
     `continue` pointing to a labeled block
     .label = labeled blocks cannot be `continue`'d
@@ -245,6 +249,19 @@
     unknown `doc` attribute `{$path}`
     .suggestion = use `doc = include_str!` instead
 
+passes_doc_test_unknown_passes =
+    unknown `doc` attribute `{$path}`
+    .note = `doc` attribute `{$path}` no longer functions; see issue #44136 <https://github.com/rust-lang/rust/issues/44136>
+    .label = no longer functions
+    .help = you may want to use `doc(document_private_items)`
+    .no_op_note = `doc({$path})` is now a no-op
+
+passes_doc_test_unknown_plugins =
+    unknown `doc` attribute `{$path}`
+    .note = `doc` attribute `{$path}` no longer functions; see issue #44136 <https://github.com/rust-lang/rust/issues/44136> and CVE-2018-1000622 <https://nvd.nist.gov/vuln/detail/CVE-2018-1000622>
+    .label = no longer functions
+    .no_op_note = `doc({$path})` is now a no-op
+
 passes_doc_test_unknown_spotlight =
     unknown `doc` attribute `{$path}`
     .note = `doc(spotlight)` was renamed to `doc(notable_trait)`
@@ -256,7 +273,7 @@
     .note = the diagnostic item is first defined in crate `{$orig_crate_name}`
 
 passes_duplicate_feature_err =
-    the feature `{$feature}` has already been declared
+    the feature `{$feature}` has already been enabled
 
 passes_duplicate_lang_item =
     found duplicate lang item `{$lang_item_name}`
@@ -452,10 +469,10 @@
     `#[may_dangle]` must be applied to a lifetime or type generic parameter in `Drop` impl
 
 passes_maybe_string_interpolation = you might have meant to use string interpolation in this string literal
+
 passes_missing_const_err =
-    attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const`
+    attributes `#[rustc_const_unstable]`, `#[rustc_const_stable]` and `#[rustc_const_stable_indirect]` require the function or method to be `const`
     .help = make the function or method const
-    .label = attribute specified here
 
 passes_missing_const_stab_attr =
     {$descr} has missing const stability attribute
@@ -605,6 +622,10 @@
 passes_repr_align_function =
     `repr(align)` attributes on functions are unstable
 
+passes_repr_align_greater_than_target_max =
+    alignment must not be greater than `isize::MAX` bytes
+    .note = `isize::MAX` is {$size} for the current target
+
 passes_repr_conflicting =
     conflicting representation hints
 
diff --git a/compiler/rustc_passes/src/abi_test.rs b/compiler/rustc_passes/src/abi_test.rs
index d0cc123..b126756 100644
--- a/compiler/rustc_passes/src/abi_test.rs
+++ b/compiler/rustc_passes/src/abi_test.rs
@@ -12,7 +12,7 @@
 use crate::errors::{AbiInvalidAttribute, AbiNe, AbiOf, UnrecognizedField};
 
 pub fn test_abi(tcx: TyCtxt<'_>) {
-    if !tcx.features().rustc_attrs {
+    if !tcx.features().rustc_attrs() {
         // if the `rustc_attrs` feature is not enabled, don't bother testing ABI
         return;
     }
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 8b30546..8c4592c 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -34,6 +34,7 @@
 use rustc_session::parse::feature_err;
 use rustc_span::symbol::{Symbol, kw, sym};
 use rustc_span::{BytePos, DUMMY_SP, Span};
+use rustc_target::abi::Size;
 use rustc_target::spec::abi::Abi;
 use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
 use rustc_trait_selection::infer::{TyCtxtInferExt, ValuePairs};
@@ -262,7 +263,7 @@
                     | sym::cfg_attr
                     // need to be fixed
                     | sym::cfi_encoding // FIXME(cfi_encoding)
-                    | sym::pointee // FIXME(derive_smart_pointer)
+                    | sym::pointee // FIXME(derive_coerce_pointee)
                     | sym::omit_gdb_pretty_printer_section // FIXME(omit_gdb_pretty_printer_section)
                     | sym::used // handled elsewhere to restrict to static items
                     | sym::repr // handled elsewhere to restrict to type decls items
@@ -918,12 +919,7 @@
         };
         match item_kind {
             Some(ItemKind::Impl(i)) => {
-                let is_valid = matches!(&i.self_ty.kind, hir::TyKind::Tup([_]))
-                    || if let hir::TyKind::BareFn(bare_fn_ty) = &i.self_ty.kind {
-                        bare_fn_ty.decl.inputs.len() == 1
-                    } else {
-                        false
-                    }
+                let is_valid = doc_fake_variadic_is_allowed_self_ty(i.self_ty)
                     || if let Some(&[hir::GenericArg::Type(ty)]) = i
                         .of_trait
                         .as_ref()
@@ -1183,19 +1179,11 @@
 
                         sym::masked => self.check_doc_masked(attr, meta, hir_id, target),
 
-                        // no_default_passes: deprecated
-                        // passes: deprecated
-                        // plugins: removed, but rustdoc warns about it itself
-                        sym::cfg
-                        | sym::hidden
-                        | sym::no_default_passes
-                        | sym::notable_trait
-                        | sym::passes
-                        | sym::plugins => {}
+                        sym::cfg | sym::hidden | sym::notable_trait => {}
 
                         sym::rust_logo => {
                             if self.check_attr_crate_level(attr, meta, hir_id)
-                                && !self.tcx.features().rustdoc_internals
+                                && !self.tcx.features().rustdoc_internals()
                             {
                                 feature_err(
                                     &self.tcx.sess,
@@ -1240,6 +1228,22 @@
                                         sugg: (attr.meta().unwrap().span, applicability),
                                     },
                                 );
+                            } else if i_meta.has_name(sym::passes)
+                                || i_meta.has_name(sym::no_default_passes)
+                            {
+                                self.tcx.emit_node_span_lint(
+                                    INVALID_DOC_ATTRIBUTES,
+                                    hir_id,
+                                    i_meta.span,
+                                    errors::DocTestUnknownPasses { path, span: i_meta.span },
+                                );
+                            } else if i_meta.has_name(sym::plugins) {
+                                self.tcx.emit_node_span_lint(
+                                    INVALID_DOC_ATTRIBUTES,
+                                    hir_id,
+                                    i_meta.span,
+                                    errors::DocTestUnknownPlugins { path, span: i_meta.span },
+                                );
                             } else {
                                 self.tcx.emit_node_span_lint(
                                     INVALID_DOC_ATTRIBUTES,
@@ -1766,7 +1770,7 @@
                 }
                 sym::align => {
                     if let (Target::Fn | Target::Method(MethodKind::Inherent), false) =
-                        (target, self.tcx.features().fn_align)
+                        (target, self.tcx.features().fn_align())
                     {
                         feature_err(
                             &self.tcx.sess,
@@ -1782,7 +1786,7 @@
                         | Target::Union
                         | Target::Enum
                         | Target::Fn
-                        | Target::Method(_) => continue,
+                        | Target::Method(_) => {}
                         _ => {
                             self.dcx().emit_err(
                                 errors::AttrApplication::StructEnumFunctionMethodUnion {
@@ -1792,6 +1796,8 @@
                             );
                         }
                     }
+
+                    self.check_align_value(hint);
                 }
                 sym::packed => {
                     if target != Target::Struct && target != Target::Union {
@@ -1889,6 +1895,45 @@
         }
     }
 
+    fn check_align_value(&self, item: &MetaItemInner) {
+        match item.singleton_lit_list() {
+            Some((
+                _,
+                MetaItemLit {
+                    kind: ast::LitKind::Int(literal, ast::LitIntType::Unsuffixed), ..
+                },
+            )) => {
+                let val = literal.get() as u64;
+                if val > 2_u64.pow(29) {
+                    // for values greater than 2^29, a different error will be emitted, make sure that happens
+                    self.dcx().span_delayed_bug(
+                        item.span(),
+                        "alignment greater than 2^29 should be errored on elsewhere",
+                    );
+                } else {
+                    // only do this check when <= 2^29 to prevent duplicate errors:
+                    // alignment greater than 2^29 not supported
+                    // alignment is too large for the current target
+
+                    let max =
+                        Size::from_bits(self.tcx.sess.target.pointer_width).signed_int_max() as u64;
+                    if val > max {
+                        self.dcx().emit_err(errors::InvalidReprAlignForTarget {
+                            span: item.span(),
+                            size: max,
+                        });
+                    }
+                }
+            }
+
+            // if the attribute is malformed, singleton_lit_list may not be of the expected type or may be None
+            // but an error will have already been emitted, so this code should just skip such attributes
+            Some((_, _)) | None => {
+                self.dcx().span_delayed_bug(item.span(), "malformed repr(align(N))");
+            }
+        }
+    }
+
     fn check_used(&self, attrs: &[Attribute], target: Target, target_span: Span) {
         let mut used_linker_span = None;
         let mut used_compiler_span = None;
@@ -1994,7 +2039,7 @@
     ) {
         match target {
             Target::Fn | Target::Method(_)
-                if self.tcx.is_const_fn_raw(hir_id.expect_owner().to_def_id()) => {}
+                if self.tcx.is_const_fn(hir_id.expect_owner().to_def_id()) => {}
             // FIXME(#80564): We permit struct fields and match arms to have an
             // `#[allow_internal_unstable]` attribute with just a lint, because we previously
             // erroneously allowed it and some crates used it accidentally, to be compatible
@@ -2292,10 +2337,10 @@
                 &mut diag,
                 &cause,
                 None,
-                Some(ValuePairs::PolySigs(ExpectedFound {
+                Some(param_env.and(ValuePairs::PolySigs(ExpectedFound {
                     expected: ty::Binder::dummy(expected_sig),
                     found: ty::Binder::dummy(sig),
-                })),
+                }))),
                 terr,
                 false,
             );
@@ -2622,3 +2667,20 @@
         },
     }
 }
+
+fn doc_fake_variadic_is_allowed_self_ty(self_ty: &hir::Ty<'_>) -> bool {
+    matches!(&self_ty.kind, hir::TyKind::Tup([_]))
+        || if let hir::TyKind::BareFn(bare_fn_ty) = &self_ty.kind {
+            bare_fn_ty.decl.inputs.len() == 1
+        } else {
+            false
+        }
+        || (if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = &self_ty.kind
+            && let Some(&[hir::GenericArg::Type(ty)]) =
+                path.segments.last().map(|last| last.args().args)
+        {
+            doc_fake_variadic_is_allowed_self_ty(ty)
+        } else {
+            false
+        })
+}
diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs
index 0dad94a..f5ece51 100644
--- a/compiler/rustc_passes/src/check_const.rs
+++ b/compiler/rustc_passes/src/check_const.rs
@@ -87,7 +87,7 @@
         let is_feature_allowed = |feature_gate| {
             // All features require that the corresponding gate be enabled,
             // even if the function has `#[rustc_allow_const_fn_unstable(the_gate)]`.
-            if !tcx.features().active(feature_gate) {
+            if !tcx.features().enabled(feature_gate) {
                 return false;
             }
 
@@ -105,7 +105,7 @@
 
             // If this crate is not using stability attributes, or this function is not claiming to be a
             // stable `const fn`, that is all that is required.
-            if !tcx.features().staged_api || tcx.has_attr(def_id, sym::rustc_const_unstable) {
+            if !tcx.features().staged_api() || tcx.has_attr(def_id, sym::rustc_const_unstable) {
                 return true;
             }
 
@@ -135,7 +135,7 @@
 
         let required_gates = required_gates.unwrap_or(&[]);
         let missing_gates: Vec<_> =
-            required_gates.iter().copied().filter(|&g| !features.active(g)).collect();
+            required_gates.iter().copied().filter(|&g| !features.enabled(g)).collect();
 
         match missing_gates.as_slice() {
             [] => {
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index f01ddbd..8bd767c1 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -324,6 +324,27 @@
 }
 
 #[derive(LintDiagnostic)]
+#[diag(passes_doc_test_unknown_passes)]
+#[note]
+#[help]
+#[note(passes_no_op_note)]
+pub(crate) struct DocTestUnknownPasses {
+    pub path: String,
+    #[label]
+    pub span: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(passes_doc_test_unknown_plugins)]
+#[note]
+#[note(passes_no_op_note)]
+pub(crate) struct DocTestUnknownPlugins {
+    pub path: String,
+    #[label]
+    pub span: Span,
+}
+
+#[derive(LintDiagnostic)]
 #[diag(passes_doc_test_unknown_include)]
 pub(crate) struct DocTestUnknownInclude {
     pub path: String,
@@ -546,6 +567,15 @@
     pub hint_spans: Vec<Span>,
 }
 
+#[derive(Diagnostic)]
+#[diag(passes_repr_align_greater_than_target_max, code = E0589)]
+#[note]
+pub(crate) struct InvalidReprAlignForTarget {
+    #[primary_span]
+    pub span: Span,
+    pub size: u64,
+}
+
 #[derive(LintDiagnostic)]
 #[diag(passes_repr_conflicting, code = E0566)]
 pub(crate) struct ReprConflictingLint;
@@ -1553,12 +1583,20 @@
     pub span: Span,
     pub feature: Symbol,
 }
+
 #[derive(Diagnostic)]
 #[diag(passes_missing_const_err)]
 pub(crate) struct MissingConstErr {
     #[primary_span]
     #[help]
     pub fn_sig_span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes_const_stable_not_stable)]
+pub(crate) struct ConstStableNotStable {
+    #[primary_span]
+    pub fn_sig_span: Span,
     #[label]
     pub const_span: Span,
 }
diff --git a/compiler/rustc_passes/src/layout_test.rs b/compiler/rustc_passes/src/layout_test.rs
index 3aef88e..93729a7 100644
--- a/compiler/rustc_passes/src/layout_test.rs
+++ b/compiler/rustc_passes/src/layout_test.rs
@@ -18,7 +18,7 @@
 };
 
 pub fn test_layout(tcx: TyCtxt<'_>) {
-    if !tcx.features().rustc_attrs {
+    if !tcx.features().rustc_attrs() {
         // if the `rustc_attrs` feature is not enabled, don't bother testing layout
         return;
     }
diff --git a/compiler/rustc_passes/src/lib_features.rs b/compiler/rustc_passes/src/lib_features.rs
index 91ba2fa..8a360c0 100644
--- a/compiler/rustc_passes/src/lib_features.rs
+++ b/compiler/rustc_passes/src/lib_features.rs
@@ -144,7 +144,7 @@
 fn lib_features(tcx: TyCtxt<'_>, LocalCrate: LocalCrate) -> LibFeatures {
     // If `staged_api` is not enabled then we aren't allowed to define lib
     // features; there is no point collecting them.
-    if !tcx.features().staged_api {
+    if !tcx.features().staged_api() {
         return LibFeatures::default();
     }
 
diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs
index 056318f..0ec151c 100644
--- a/compiler/rustc_passes/src/reachable.rs
+++ b/compiler/rustc_passes/src/reachable.rs
@@ -322,7 +322,7 @@
                     self.visit(ty);
                     // Manually visit to actually see the trait's `DefId`. Type visitors won't see it
                     if let Some(trait_ref) = dyn_ty.principal() {
-                        let ExistentialTraitRef { def_id, args } = trait_ref.skip_binder();
+                        let ExistentialTraitRef { def_id, args, .. } = trait_ref.skip_binder();
                         self.visit_def_id(def_id, "", &"");
                         self.visit(args);
                     }
diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs
index 751c87a..f69cc74 100644
--- a/compiler/rustc_passes/src/stability.rs
+++ b/compiler/rustc_passes/src/stability.rs
@@ -10,13 +10,13 @@
 };
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_data_structures::unord::{ExtendUnord, UnordMap, UnordSet};
-use rustc_feature::ACCEPTED_FEATURES;
+use rustc_feature::{ACCEPTED_LANG_FEATURES, EnabledLangFeature, EnabledLibFeature};
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId, LocalModDefId};
 use rustc_hir::hir_id::CRATE_HIR_ID;
 use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::{FieldDef, Item, ItemKind, TraitRef, Ty, TyKind, Variant};
+use rustc_hir::{Constness, FieldDef, Item, ItemKind, TraitRef, Ty, TyKind, Variant};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::middle::lib_features::{FeatureStability, LibFeatures};
 use rustc_middle::middle::privacy::EffectiveVisibilities;
@@ -27,7 +27,6 @@
 use rustc_session::lint::builtin::{INEFFECTIVE_UNSTABLE_TRAIT_IMPL, USELESS_DEPRECATED};
 use rustc_span::Span;
 use rustc_span::symbol::{Symbol, sym};
-use rustc_target::spec::abi::Abi;
 use tracing::{debug, info};
 
 use crate::errors;
@@ -107,6 +106,7 @@
         def_id: LocalDefId,
         item_sp: Span,
         fn_sig: Option<&'tcx hir::FnSig<'tcx>>,
+        is_foreign_item: bool,
         kind: AnnotationKind,
         inherit_deprecation: InheritDeprecation,
         inherit_const_stability: InheritConstStability,
@@ -144,7 +144,7 @@
             }
         }
 
-        if !self.tcx.features().staged_api {
+        if !self.tcx.features().staged_api() {
             // Propagate unstability. This can happen even for non-staged-api crates in case
             // -Zforce-unstable-if-unmarked is set.
             if let Some(stab) = self.parent_stab {
@@ -163,30 +163,62 @@
         }
 
         let stab = attr::find_stability(self.tcx.sess, attrs, item_sp);
-        let const_stab = attr::find_const_stability(self.tcx.sess, attrs, item_sp);
+        let const_stab = attr::find_const_stability(
+            self.tcx.sess,
+            attrs,
+            item_sp,
+            fn_sig.is_some_and(|s| s.header.is_const()),
+        );
         let body_stab = attr::find_body_stability(self.tcx.sess, attrs);
-        let mut const_span = None;
 
-        let const_stab = const_stab.map(|(const_stab, const_span_node)| {
-            self.index.const_stab_map.insert(def_id, const_stab);
-            const_span = Some(const_span_node);
-            const_stab
-        });
-
-        // If the current node is a function, has const stability attributes and if it doesn not have an intrinsic ABI,
-        // check if the function/method is const or the parent impl block is const
-        if let (Some(const_span), Some(fn_sig)) = (const_span, fn_sig)
-            && fn_sig.header.abi != Abi::RustIntrinsic
+        // If the current node is a function with const stability attributes (directly given or
+        // implied), check if the function/method is const or the parent impl block is const.
+        if let Some(fn_sig) = fn_sig
             && !fn_sig.header.is_const()
-            && (!self.in_trait_impl || !self.tcx.is_const_fn_raw(def_id.to_def_id()))
+            // We have to exclude foreign items as they might be intrinsics. Sadly we can't check
+            // their ABI; `fn_sig.abi` is *not* correct for foreign functions.
+            && !is_foreign_item
+            && const_stab.is_some()
+            && (!self.in_trait_impl || !self.tcx.is_const_fn(def_id.to_def_id()))
+        {
+            self.tcx.dcx().emit_err(errors::MissingConstErr { fn_sig_span: fn_sig.span });
+        }
+
+        // If this is marked const *stable*, it must also be regular-stable.
+        if let Some((const_stab, const_span)) = const_stab
+            && let Some(fn_sig) = fn_sig
+            && const_stab.is_const_stable()
+            && !stab.is_some_and(|(s, _)| s.is_stable())
         {
             self.tcx
                 .dcx()
-                .emit_err(errors::MissingConstErr { fn_sig_span: fn_sig.span, const_span });
+                .emit_err(errors::ConstStableNotStable { fn_sig_span: fn_sig.span, const_span });
         }
 
+        // Stable *language* features shouldn't be used as unstable library features.
+        // (Not doing this for stable library features is checked by tidy.)
+        if let Some((
+            ConstStability { level: Unstable { .. }, feature: Some(feature), .. },
+            const_span,
+        )) = const_stab
+        {
+            if ACCEPTED_LANG_FEATURES.iter().find(|f| f.name == feature).is_some() {
+                self.tcx.dcx().emit_err(errors::UnstableAttrForAlreadyStableFeature {
+                    span: const_span,
+                    item_sp,
+                });
+            }
+        }
+
+        let const_stab = const_stab.map(|(const_stab, _span)| {
+            self.index.const_stab_map.insert(def_id, const_stab);
+            const_stab
+        });
+
         // `impl const Trait for Type` items forward their const stability to their
         // immediate children.
+        // FIXME(effects): how is this supposed to interact with `#[rustc_const_stable_indirect]`?
+        // Currently, once that is set, we do not inherit anything from the parent any more.
         if const_stab.is_none() {
             debug!("annotate: const_stab not found, parent = {:?}", self.parent_const_stab);
             if let Some(parent) = self.parent_const_stab {
@@ -247,8 +279,10 @@
                 }
             }
 
+            // Stable *language* features shouldn't be used as unstable library features.
+            // (Not doing this for stable library features is checked by tidy.)
             if let Stability { level: Unstable { .. }, feature } = stab {
-                if ACCEPTED_FEATURES.iter().find(|f| f.name == feature).is_some() {
+                if ACCEPTED_LANG_FEATURES.iter().find(|f| f.name == feature).is_some() {
                     self.tcx
                         .dcx()
                         .emit_err(errors::UnstableAttrForAlreadyStableFeature { span, item_sp });
@@ -260,21 +294,13 @@
                 self.index.implications.insert(implied_by, feature);
             }
 
-            if let Some(ConstStability { level: Unstable { .. }, feature, .. }) = const_stab {
-                if ACCEPTED_FEATURES.iter().find(|f| f.name == feature).is_some() {
-                    self.tcx.dcx().emit_err(errors::UnstableAttrForAlreadyStableFeature {
-                        span: const_span.unwrap(), // If const_stab contains Some(..), same is true for const_span
-                        item_sp,
-                    });
-                }
-            }
             if let Some(ConstStability {
                 level: Unstable { implied_by: Some(implied_by), .. },
                 feature,
                 ..
             }) = const_stab
             {
-                self.index.implications.insert(implied_by, feature);
+                self.index.implications.insert(implied_by, feature.unwrap());
             }
 
             self.index.stab_map.insert(def_id, stab);
@@ -372,6 +398,7 @@
                         ctor_def_id,
                         i.span,
                         None,
+                        /* is_foreign_item */ false,
                         AnnotationKind::Required,
                         InheritDeprecation::Yes,
                         InheritConstStability::No,
@@ -390,6 +417,7 @@
             i.owner_id.def_id,
             i.span,
             fn_sig,
+            /* is_foreign_item */ false,
             kind,
             InheritDeprecation::Yes,
             const_stab_inherit,
@@ -409,6 +437,7 @@
             ti.owner_id.def_id,
             ti.span,
             fn_sig,
+            /* is_foreign_item */ false,
             AnnotationKind::Required,
             InheritDeprecation::Yes,
             InheritConstStability::No,
@@ -432,6 +461,7 @@
             ii.owner_id.def_id,
             ii.span,
             fn_sig,
+            /* is_foreign_item */ false,
             kind,
             InheritDeprecation::Yes,
             InheritConstStability::No,
@@ -447,6 +477,7 @@
             var.def_id,
             var.span,
             None,
+            /* is_foreign_item */ false,
             AnnotationKind::Required,
             InheritDeprecation::Yes,
             InheritConstStability::No,
@@ -457,6 +488,7 @@
                         ctor_def_id,
                         var.span,
                         None,
+                        /* is_foreign_item */ false,
                         AnnotationKind::Required,
                         InheritDeprecation::Yes,
                         InheritConstStability::No,
@@ -475,6 +507,7 @@
             s.def_id,
             s.span,
             None,
+            /* is_foreign_item */ false,
             AnnotationKind::Required,
             InheritDeprecation::Yes,
             InheritConstStability::No,
@@ -486,10 +519,15 @@
     }
 
     fn visit_foreign_item(&mut self, i: &'tcx hir::ForeignItem<'tcx>) {
+        let fn_sig = match &i.kind {
+            rustc_hir::ForeignItemKind::Fn(fn_sig, ..) => Some(fn_sig),
+            _ => None,
+        };
         self.annotate(
             i.owner_id.def_id,
             i.span,
-            None,
+            fn_sig,
+            /* is_foreign_item */ true,
             AnnotationKind::Required,
             InheritDeprecation::Yes,
             InheritConstStability::No,
@@ -512,6 +550,7 @@
             p.def_id,
             p.span,
             None,
+            /* is_foreign_item */ false,
             kind,
             InheritDeprecation::No,
             InheritConstStability::No,
@@ -540,8 +579,10 @@
         }
     }
 
-    fn check_missing_const_stability(&self, def_id: LocalDefId, span: Span) {
-        if !self.tcx.features().staged_api {
+    fn check_missing_or_wrong_const_stability(&self, def_id: LocalDefId, span: Span) {
+        // The visitor runs for "unstable-if-unmarked" crates, but we don't yet support
+        // that on the const side.
+        if !self.tcx.features().staged_api() {
             return;
         }
 
@@ -554,10 +595,11 @@
         }
 
         let is_const = self.tcx.is_const_fn(def_id.to_def_id())
-            || self.tcx.is_const_trait_impl_raw(def_id.to_def_id());
+            || self.tcx.is_const_trait_impl(def_id.to_def_id());
         let is_stable =
             self.tcx.lookup_stability(def_id).is_some_and(|stability| stability.level.is_stable());
-        let missing_const_stability_attribute = self.tcx.lookup_const_stability(def_id).is_none();
+        let missing_const_stability_attribute =
+            self.tcx.lookup_const_stability(def_id).is_none_or(|s| s.feature.is_none());
 
         if is_const && is_stable && missing_const_stability_attribute {
             let descr = self.tcx.def_descr(def_id.to_def_id());
@@ -587,7 +629,7 @@
         }
 
         // Ensure stable `const fn` have a const stability attribute.
-        self.check_missing_const_stability(i.owner_id.def_id, i.span);
+        self.check_missing_or_wrong_const_stability(i.owner_id.def_id, i.span);
 
         intravisit::walk_item(self, i)
     }
@@ -601,7 +643,7 @@
         let impl_def_id = self.tcx.hir().get_parent_item(ii.hir_id());
         if self.tcx.impl_trait_ref(impl_def_id).is_none() {
             self.check_missing_stability(ii.owner_id.def_id, ii.span);
-            self.check_missing_const_stability(ii.owner_id.def_id, ii.span);
+            self.check_missing_or_wrong_const_stability(ii.owner_id.def_id, ii.span);
         }
         intravisit::walk_impl_item(self, ii);
     }
@@ -670,6 +712,7 @@
             CRATE_DEF_ID,
             tcx.hir().span(CRATE_HIR_ID),
             None,
+            /* is_foreign_item */ false,
             AnnotationKind::Required,
             InheritDeprecation::Yes,
             InheritConstStability::No,
@@ -732,12 +775,23 @@
             // For implementations of traits, check the stability of each item
             // individually as it's possible to have a stable trait with unstable
             // items.
-            hir::ItemKind::Impl(hir::Impl { of_trait: Some(ref t), self_ty, items, .. }) => {
+            hir::ItemKind::Impl(hir::Impl {
+                constness,
+                of_trait: Some(ref t),
+                self_ty,
+                items,
+                ..
+            }) => {
                 let features = self.tcx.features();
-                if features.staged_api {
+                if features.staged_api() {
                     let attrs = self.tcx.hir().attrs(item.hir_id());
                     let stab = attr::find_stability(self.tcx.sess, attrs, item.span);
-                    let const_stab = attr::find_const_stability(self.tcx.sess, attrs, item.span);
+                    let const_stab = attr::find_const_stability(
+                        self.tcx.sess,
+                        attrs,
+                        item.span,
+                        matches!(constness, Constness::Const),
+                    );
 
                     // If this impl block has an #[unstable] attribute, give an
                     // error if all involved types and traits are stable, because
@@ -762,8 +816,8 @@
 
                     // `#![feature(const_trait_impl)]` is unstable, so any impl declared stable
                     // needs to have an error emitted.
-                    if features.const_trait_impl
-                        && self.tcx.is_const_trait_impl_raw(item.owner_id.to_def_id())
+                    if features.const_trait_impl()
+                        && self.tcx.is_const_trait_impl(item.owner_id.to_def_id())
                         && const_stab.is_some_and(|(stab, _)| stab.is_const_stable())
                     {
                         self.tcx.dcx().emit_err(errors::TraitImplConstStable { span: item.span });
@@ -926,7 +980,7 @@
 /// libraries, identify activated features that don't exist and error about them.
 pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) {
     let is_staged_api =
-        tcx.sess.opts.unstable_opts.force_unstable_if_unmarked || tcx.features().staged_api;
+        tcx.sess.opts.unstable_opts.force_unstable_if_unmarked || tcx.features().staged_api();
     if is_staged_api {
         let effective_visibilities = &tcx.effective_visibilities(());
         let mut missing = MissingStabilityAnnotations { tcx, effective_visibilities };
@@ -935,33 +989,33 @@
         tcx.hir().visit_all_item_likes_in_crate(&mut missing);
     }
 
-    let declared_lang_features = &tcx.features().declared_lang_features;
+    let enabled_lang_features = tcx.features().enabled_lang_features();
     let mut lang_features = UnordSet::default();
-    for &(feature, span, since) in declared_lang_features {
-        if let Some(since) = since {
+    for EnabledLangFeature { gate_name, attr_sp, stable_since } in enabled_lang_features {
+        if let Some(version) = stable_since {
             // Warn if the user has enabled an already-stable lang feature.
-            unnecessary_stable_feature_lint(tcx, span, feature, since);
+            unnecessary_stable_feature_lint(tcx, *attr_sp, *gate_name, *version);
         }
-        if !lang_features.insert(feature) {
+        if !lang_features.insert(gate_name) {
             // Warn if the user enables a lang feature multiple times.
-            tcx.dcx().emit_err(errors::DuplicateFeatureErr { span, feature });
+            tcx.dcx().emit_err(errors::DuplicateFeatureErr { span: *attr_sp, feature: *gate_name });
         }
     }
 
-    let declared_lib_features = &tcx.features().declared_lib_features;
+    let enabled_lib_features = tcx.features().enabled_lib_features();
     let mut remaining_lib_features = FxIndexMap::default();
-    for (feature, span) in declared_lib_features {
-        if remaining_lib_features.contains_key(&feature) {
+    for EnabledLibFeature { gate_name, attr_sp } in enabled_lib_features {
+        if remaining_lib_features.contains_key(gate_name) {
             // Warn if the user enables a lib feature multiple times.
-            tcx.dcx().emit_err(errors::DuplicateFeatureErr { span: *span, feature: *feature });
+            tcx.dcx().emit_err(errors::DuplicateFeatureErr { span: *attr_sp, feature: *gate_name });
         }
-        remaining_lib_features.insert(feature, *span);
+        remaining_lib_features.insert(*gate_name, *attr_sp);
     }
     // `stdbuild` has special handling for `libc`, so we need to
     // recognise the feature when building std.
     // Likewise, libtest is handled specially, so `test` isn't
     // available as we'd like it to be.
-    // FIXME: only remove `libc` when `stdbuild` is active.
+    // FIXME: only remove `libc` when `stdbuild` is enabled.
     // FIXME: remove special casing for `test`.
     // FIXME(#120456) - is `swap_remove` correct?
     remaining_lib_features.swap_remove(&sym::libc);
@@ -987,7 +1041,7 @@
     /// time, less loading from metadata is performed and thus compiler performance is improved.
     fn check_features<'tcx>(
         tcx: TyCtxt<'tcx>,
-        remaining_lib_features: &mut FxIndexMap<&Symbol, Span>,
+        remaining_lib_features: &mut FxIndexMap<Symbol, Span>,
         remaining_implications: &mut UnordMap<Symbol, Symbol>,
         defined_features: &LibFeatures,
         all_implications: &UnordMap<Symbol, Symbol>,
@@ -1021,7 +1075,7 @@
     // All local crate implications need to have the feature that implies it confirmed to exist.
     let mut remaining_implications = tcx.stability_implications(LOCAL_CRATE).clone();
 
-    // We always collect the lib features declared in the current crate, even if there are
+    // We always collect the lib features enabled in the current crate, even if there are
     // no unknown features, because the collection also does feature attribute validation.
     let local_defined_features = tcx.lib_features(LOCAL_CRATE);
     if !remaining_lib_features.is_empty() || !remaining_implications.is_empty() {
@@ -1057,7 +1111,7 @@
     }
 
     for (feature, span) in remaining_lib_features {
-        tcx.dcx().emit_err(errors::UnknownFeature { span, feature: *feature });
+        tcx.dcx().emit_err(errors::UnknownFeature { span, feature });
     }
 
     for (&implied_by, &feature) in remaining_implications.to_sorted_stable_ord() {
diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs
index 70a9319..0e132b2 100644
--- a/compiler/rustc_pattern_analysis/src/rustc.rs
+++ b/compiler/rustc_pattern_analysis/src/rustc.rs
@@ -891,7 +891,7 @@
                 print::write_slice_like(&mut s, &prefix, has_dot_dot, &suffix).unwrap();
                 s
             }
-            Never if self.tcx.features().never_patterns => "!".to_string(),
+            Never if self.tcx.features().never_patterns() => "!".to_string(),
             Never | Wildcard | NonExhaustive | Hidden | PrivateUninhabited => "_".to_string(),
             Missing { .. } => bug!(
                 "trying to convert a `Missing` constructor into a `Pat`; this is probably a bug,
@@ -915,7 +915,7 @@
         | Constructor::NonExhaustive
         | Constructor::Hidden
         | Constructor::PrivateUninhabited => true,
-        Constructor::Never if !tcx.features().never_patterns => true,
+        Constructor::Never if !tcx.features().never_patterns() => true,
         _ => false,
     }
 }
@@ -929,7 +929,7 @@
     type PatData = &'p Pat<'tcx>;
 
     fn is_exhaustive_patterns_feature_on(&self) -> bool {
-        self.tcx.features().exhaustive_patterns
+        self.tcx.features().exhaustive_patterns()
     }
 
     fn ctor_arity(&self, ctor: &crate::constructor::Constructor<Self>, ty: &Self::Ty) -> usize {
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index f67c4cb..0595414 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -32,8 +32,8 @@
 use rustc_middle::query::Providers;
 use rustc_middle::ty::print::PrintTraitRefExt as _;
 use rustc_middle::ty::{
-    self, Const, GenericArgs, GenericParamDefKind, TraitRef, Ty, TyCtxt, TypeSuperVisitable,
-    TypeVisitable, TypeVisitor,
+    self, Const, GenericParamDefKind, TraitRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
+    TypeVisitor,
 };
 use rustc_middle::{bug, span_bug};
 use rustc_session::lint;
@@ -137,6 +137,10 @@
             ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref, polarity: _ }) => {
                 self.visit_trait(trait_ref)
             }
+            ty::ClauseKind::HostEffect(pred) => {
+                try_visit!(self.visit_trait(pred.trait_ref));
+                pred.host.visit_with(self)
+            }
             ty::ClauseKind::Projection(ty::ProjectionPredicate {
                 projection_term: projection_ty,
                 term,
@@ -246,10 +250,10 @@
                         ty::ExistentialPredicate::Trait(trait_ref) => trait_ref,
                         ty::ExistentialPredicate::Projection(proj) => proj.trait_ref(tcx),
                         ty::ExistentialPredicate::AutoTrait(def_id) => {
-                            ty::ExistentialTraitRef { def_id, args: GenericArgs::empty() }
+                            ty::ExistentialTraitRef::new(tcx, def_id, ty::GenericArgs::empty())
                         }
                     };
-                    let ty::ExistentialTraitRef { def_id, args: _ } = trait_ref;
+                    let ty::ExistentialTraitRef { def_id, .. } = trait_ref;
                     try_visit!(self.def_id_visitor.visit_def_id(def_id, "trait", &trait_ref));
                 }
             }
diff --git a/compiler/rustc_query_system/src/ich/impls_syntax.rs b/compiler/rustc_query_system/src/ich/impls_syntax.rs
index 5e45097..5a72e80 100644
--- a/compiler/rustc_query_system/src/ich/impls_syntax.rs
+++ b/compiler/rustc_query_system/src/ich/impls_syntax.rs
@@ -111,13 +111,25 @@
 impl<'tcx> HashStable<StableHashingContext<'tcx>> for rustc_feature::Features {
     fn hash_stable(&self, hcx: &mut StableHashingContext<'tcx>, hasher: &mut StableHasher) {
         // Unfortunately we cannot exhaustively list fields here, since the
-        // struct is macro generated.
-        self.declared_lang_features.hash_stable(hcx, hasher);
-        self.declared_lib_features.hash_stable(hcx, hasher);
+        // struct has private fields (to ensure its invariant is maintained)
+        self.enabled_lang_features().hash_stable(hcx, hasher);
+        self.enabled_lib_features().hash_stable(hcx, hasher);
+    }
+}
 
-        self.all_features()[..].hash_stable(hcx, hasher);
-        for feature in rustc_feature::UNSTABLE_FEATURES.iter() {
-            feature.feature.name.hash_stable(hcx, hasher);
-        }
+impl<'tcx> HashStable<StableHashingContext<'tcx>> for rustc_feature::EnabledLangFeature {
+    fn hash_stable(&self, hcx: &mut StableHashingContext<'tcx>, hasher: &mut StableHasher) {
+        let rustc_feature::EnabledLangFeature { gate_name, attr_sp, stable_since } = self;
+        gate_name.hash_stable(hcx, hasher);
+        attr_sp.hash_stable(hcx, hasher);
+        stable_since.hash_stable(hcx, hasher);
+    }
+}
+
+impl<'tcx> HashStable<StableHashingContext<'tcx>> for rustc_feature::EnabledLibFeature {
+    fn hash_stable(&self, hcx: &mut StableHashingContext<'tcx>, hasher: &mut StableHasher) {
+        let rustc_feature::EnabledLibFeature { gate_name, attr_sp } = self;
+        gate_name.hash_stable(hcx, hasher);
+        attr_sp.hash_stable(hcx, hasher);
     }
 }
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index 0ca6bb8..bdf940a 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -177,7 +177,9 @@
 
         let loaded_macro = self.cstore().load_macro_untracked(def_id, self.tcx);
         let macro_data = match loaded_macro {
-            LoadedMacro::MacroDef(item, edition) => self.compile_macro(&item, edition),
+            LoadedMacro::MacroDef { def, ident, attrs, span, edition } => {
+                self.compile_macro(&def, ident, &attrs, span, ast::DUMMY_NODE_ID, edition)
+            }
             LoadedMacro::ProcMacro(ext) => MacroData::new(Lrc::new(ext)),
         };
 
@@ -1321,7 +1323,7 @@
                         // Visit attributes after items for backward compatibility.
                         // This way they can use `macro_rules` defined later.
                         self.visit_vis(&item.vis);
-                        self.visit_ident(item.ident);
+                        self.visit_ident(&item.ident);
                         item.kind.walk(item, AssocCtxt::Trait, self);
                         visit::walk_list!(self, visit_attribute, &item.attrs);
                     }
diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs
index 0047f2c..a825458 100644
--- a/compiler/rustc_resolve/src/def_collector.rs
+++ b/compiler/rustc_resolve/src/def_collector.rs
@@ -199,8 +199,10 @@
             },
             ItemKind::Const(..) => DefKind::Const,
             ItemKind::Fn(..) | ItemKind::Delegation(..) => DefKind::Fn,
-            ItemKind::MacroDef(..) => {
-                let macro_data = self.resolver.compile_macro(i, self.resolver.tcx.sess.edition());
+            ItemKind::MacroDef(def) => {
+                let edition = self.resolver.tcx.sess.edition();
+                let macro_data =
+                    self.resolver.compile_macro(def, i.ident, &i.attrs, i.span, i.id, edition);
                 let macro_kind = macro_data.ext.macro_kind();
                 opt_macro_data = Some(macro_data);
                 DefKind::Macro(macro_kind)
diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs
index 8ae7790..b80e0e1 100644
--- a/compiler/rustc_resolve/src/ident.rs
+++ b/compiler/rustc_resolve/src/ident.rs
@@ -606,7 +606,7 @@
                     Scope::BuiltinTypes => match this.builtin_types_bindings.get(&ident.name) {
                         Some(binding) => {
                             if matches!(ident.name, sym::f16)
-                                && !this.tcx.features().f16
+                                && !this.tcx.features().f16()
                                 && !ident.span.allows_unstable(sym::f16)
                                 && finalize.is_some()
                                 && innermost_result.is_none()
@@ -620,7 +620,7 @@
                                 .emit();
                             }
                             if matches!(ident.name, sym::f128)
-                                && !this.tcx.features().f128
+                                && !this.tcx.features().f128()
                                 && !ident.span.allows_unstable(sym::f128)
                                 && finalize.is_some()
                                 && innermost_result.is_none()
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 98db36b..adb0ba7 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -1205,7 +1205,7 @@
     }
 
     fn visit_assoc_item_constraint(&mut self, constraint: &'ast AssocItemConstraint) {
-        self.visit_ident(constraint.ident);
+        self.visit_ident(&constraint.ident);
         if let Some(ref gen_args) = constraint.gen_args {
             // Forbid anonymous lifetimes in GAT parameters until proper semantics are decided.
             self.with_lifetime_rib(LifetimeRibKind::AnonymousReportError, |this| {
@@ -2683,7 +2683,7 @@
                 self.with_generic_param_rib(
                     &generics.params,
                     RibKind::Item(
-                        if self.r.tcx.features().generic_const_items {
+                        if self.r.tcx.features().generic_const_items() {
                             HasGenericParams::Yes(generics.span)
                         } else {
                             HasGenericParams::No
@@ -2888,7 +2888,7 @@
                     RibKind::Normal => {
                         // FIXME(non_lifetime_binders): Stop special-casing
                         // const params to error out here.
-                        if self.r.tcx.features().non_lifetime_binders
+                        if self.r.tcx.features().non_lifetime_binders()
                             && matches!(param.kind, GenericParamKind::Type { .. })
                         {
                             Res::Def(def_kind, def_id.to_def_id())
@@ -4411,10 +4411,10 @@
                 let tcx = self.r.tcx();
 
                 let gate_err_sym_msg = match prim {
-                    PrimTy::Float(FloatTy::F16) if !tcx.features().f16 => {
+                    PrimTy::Float(FloatTy::F16) if !tcx.features().f16() => {
                         Some((sym::f16, "the type `f16` is unstable"))
                     }
-                    PrimTy::Float(FloatTy::F128) if !tcx.features().f128 => {
+                    PrimTy::Float(FloatTy::F128) if !tcx.features().f128() => {
                         Some((sym::f128, "the type `f128` is unstable"))
                     }
                     _ => None,
@@ -4565,7 +4565,7 @@
             }
             AnonConstKind::InlineConst => ConstantHasGenerics::Yes,
             AnonConstKind::ConstArg(_) => {
-                if self.r.tcx.features().generic_const_exprs || is_trivial_const_arg {
+                if self.r.tcx.features().generic_const_exprs() || is_trivial_const_arg {
                     ConstantHasGenerics::Yes
                 } else {
                     ConstantHasGenerics::No(NoConstantGenericsReason::NonTrivialConstArg)
@@ -4582,7 +4582,7 @@
 
     fn resolve_expr_field(&mut self, f: &'ast ExprField, e: &'ast Expr) {
         self.resolve_expr(&f.expr, Some(e));
-        self.visit_ident(f.ident);
+        self.visit_ident(&f.ident);
         walk_list!(self, visit_attribute, f.attrs.iter());
     }
 
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 50fbdca..f0632a2 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -1198,7 +1198,7 @@
             // const generics. Of course, `Struct` and `Enum` may contain ty params, too, but the
             // benefits of including them here outweighs the small number of false positives.
             Some(Res::Def(DefKind::Struct | DefKind::Enum, _))
-                if self.r.tcx.features().adt_const_params =>
+                if self.r.tcx.features().adt_const_params() =>
             {
                 Applicability::MaybeIncorrect
             }
@@ -2773,7 +2773,7 @@
                     // Avoid suggesting placing lifetime parameters on constant items unless the relevant
                     // feature is enabled. Suggest the parent item as a possible location if applicable.
                     if let LifetimeBinderKind::ConstItem = kind
-                        && !self.r.tcx().features().generic_const_items
+                        && !self.r.tcx().features().generic_const_items()
                     {
                         continue;
                     }
@@ -2934,7 +2934,7 @@
                     .emit();
             }
             NoConstantGenericsReason::NonTrivialConstArg => {
-                assert!(!self.r.tcx.features().generic_const_exprs);
+                assert!(!self.r.tcx.features().generic_const_exprs());
                 self.r
                     .dcx()
                     .create_err(errors::ParamInNonTrivialAnonConst {
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index e43c871..1dc2777 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -661,7 +661,7 @@
         }
 
         // We are trying to avoid reporting this error if other related errors were reported.
-        if res != Res::Err && inner_attr && !self.tcx.features().custom_inner_attributes {
+        if res != Res::Err && inner_attr && !self.tcx.features().custom_inner_attributes() {
             let is_macro = match res {
                 Res::Def(..) => true,
                 Res::NonMacroAttr(..) => false,
@@ -690,7 +690,7 @@
             && namespace.ident.name == sym::diagnostic
             && !(attribute.ident.name == sym::on_unimplemented
                 || (attribute.ident.name == sym::do_not_recommend
-                    && self.tcx.features().do_not_recommend))
+                    && self.tcx.features().do_not_recommend()))
         {
             let distance =
                 edit_distance(attribute.ident.name.as_str(), sym::on_unimplemented.as_str(), 5);
@@ -1007,10 +1007,8 @@
             {
                 let feature = stability.feature;
 
-                let is_allowed = |feature| {
-                    self.tcx.features().declared_features.contains(&feature)
-                        || span.allows_unstable(feature)
-                };
+                let is_allowed =
+                    |feature| self.tcx.features().enabled(feature) || span.allows_unstable(feature);
                 let allowed_by_implication = implied_by.is_some_and(|feature| is_allowed(feature));
                 if !is_allowed(feature) && !allowed_by_implication {
                     let lint_buffer = &mut self.lint_buffer;
@@ -1124,9 +1122,25 @@
     /// Compile the macro into a `SyntaxExtension` and its rule spans.
     ///
     /// Possibly replace its expander to a pre-defined one for built-in macros.
-    pub(crate) fn compile_macro(&mut self, item: &ast::Item, edition: Edition) -> MacroData {
-        let (mut ext, mut rule_spans) =
-            compile_declarative_macro(self.tcx.sess, self.tcx.features(), item, edition);
+    pub(crate) fn compile_macro(
+        &mut self,
+        macro_def: &ast::MacroDef,
+        ident: Ident,
+        attrs: &[ast::Attribute],
+        span: Span,
+        node_id: NodeId,
+        edition: Edition,
+    ) -> MacroData {
+        let (mut ext, mut rule_spans) = compile_declarative_macro(
+            self.tcx.sess,
+            self.tcx.features(),
+            macro_def,
+            ident,
+            attrs,
+            span,
+            node_id,
+            edition,
+        );
 
         if let Some(builtin_name) = ext.builtin_name {
             // The macro was marked with `#[rustc_builtin_macro]`.
@@ -1134,28 +1148,22 @@
                 // The macro is a built-in, replace its expander function
                 // while still taking everything else from the source code.
                 // If we already loaded this builtin macro, give a better error message than 'no such builtin macro'.
-                match mem::replace(builtin_macro, BuiltinMacroState::AlreadySeen(item.span)) {
+                match mem::replace(builtin_macro, BuiltinMacroState::AlreadySeen(span)) {
                     BuiltinMacroState::NotYetSeen(builtin_ext) => {
                         ext.kind = builtin_ext;
                         rule_spans = Vec::new();
                     }
-                    BuiltinMacroState::AlreadySeen(span) => {
-                        self.dcx().emit_err(errors::AttemptToDefineBuiltinMacroTwice {
-                            span: item.span,
-                            note_span: span,
-                        });
+                    BuiltinMacroState::AlreadySeen(note_span) => {
+                        self.dcx()
+                            .emit_err(errors::AttemptToDefineBuiltinMacroTwice { span, note_span });
                     }
                 }
             } else {
-                self.dcx().emit_err(errors::CannotFindBuiltinMacroWithName {
-                    span: item.span,
-                    ident: item.ident,
-                });
+                self.dcx().emit_err(errors::CannotFindBuiltinMacroWithName { span, ident });
             }
         }
 
-        let ItemKind::MacroDef(def) = &item.kind else { unreachable!() };
-        MacroData { ext: Lrc::new(ext), rule_spans, macro_rules: def.macro_rules }
+        MacroData { ext: Lrc::new(ext), rule_spans, macro_rules: macro_def.macro_rules }
     }
 
     fn path_accessible(
diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs
index 83dccee..cba79a0 100644
--- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs
+++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs
@@ -245,11 +245,15 @@
                             alias_ty.to_ty(tcx),
                         );
                         debug!("Resolved {:?} -> {resolved}", alias_ty.to_ty(tcx));
-                        ty::ExistentialPredicate::Projection(ty::ExistentialProjection {
-                            def_id: assoc_ty.def_id,
-                            args: ty::ExistentialTraitRef::erase_self_ty(tcx, super_trait_ref).args,
-                            term: resolved.into(),
-                        })
+                        ty::ExistentialPredicate::Projection(
+                            ty::ExistentialProjection::erase_self_ty(
+                                tcx,
+                                ty::ProjectionPredicate {
+                                    projection_term: alias_ty.into(),
+                                    term: resolved.into(),
+                                },
+                            ),
+                        )
                     })
                 })
         })
@@ -318,10 +322,11 @@
             .lang_items()
             .drop_trait()
             .unwrap_or_else(|| bug!("typeid_for_instance: couldn't get drop_trait lang item"));
-        let predicate = ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef {
+        let predicate = ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef::new_from_args(
+            tcx,
             def_id,
-            args: List::empty(),
-        });
+            ty::List::empty(),
+        ));
         let predicates = tcx.mk_poly_existential_predicates(&[ty::Binder::dummy(predicate)]);
         let self_ty = Ty::new_dynamic(tcx, predicates, tcx.lifetimes.re_erased, ty::Dyn);
         instance.args = tcx.mk_args_trait(self_ty, List::empty());
diff --git a/compiler/rustc_session/messages.ftl b/compiler/rustc_session/messages.ftl
index 1816d12..893c532 100644
--- a/compiler/rustc_session/messages.ftl
+++ b/compiler/rustc_session/messages.ftl
@@ -136,3 +136,6 @@
     dropping unsupported crate type `{$crate_type}` for target `{$target_triple}`
 
 session_unsupported_dwarf_version = requested DWARF version {$dwarf_version} is greater than 5
+
+session_unsupported_regparm = `-Zregparm={$regparm}` is unsupported (valid values 0-3)
+session_unsupported_regparm_arch = `-Zregparm=N` is only supported on x86
diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs
index dbb74d1..20e8fb3 100644
--- a/compiler/rustc_session/src/errors.rs
+++ b/compiler/rustc_session/src/errors.rs
@@ -486,6 +486,16 @@
 pub(crate) struct FunctionReturnThunkExternRequiresNonLargeCodeModel;
 
 #[derive(Diagnostic)]
+#[diag(session_unsupported_regparm)]
+pub(crate) struct UnsupportedRegparm {
+    pub(crate) regparm: u32,
+}
+
+#[derive(Diagnostic)]
+#[diag(session_unsupported_regparm_arch)]
+pub(crate) struct UnsupportedRegparmArch;
+
+#[derive(Diagnostic)]
 #[diag(session_failed_to_create_profiler)]
 pub(crate) struct FailedToCreateProfiler {
     pub(crate) err: String,
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index f9964b5..54a4621 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -2000,6 +2000,11 @@
         "enable queries of the dependency graph for regression testing (default: no)"),
     randomize_layout: bool = (false, parse_bool, [TRACKED],
         "randomize the layout of types (default: no)"),
+    regparm: Option<u32> = (None, parse_opt_number, [TRACKED],
+        "On x86-32 targets, setting this to N causes the compiler to pass N arguments \
+        in registers EAX, EDX, and ECX instead of on the stack for\
+        \"C\", \"cdecl\", and \"stdcall\" fn.\
+        It is UNSOUND to link together crates that use different values for this flag!"),
     relax_elf_relocations: Option<bool> = (None, parse_opt_bool, [TRACKED],
         "whether ELF relocations can be relaxed"),
     remap_cwd_prefix: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index 27879d8..1963cf4 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -1337,6 +1337,15 @@
         }
     }
 
+    if let Some(regparm) = sess.opts.unstable_opts.regparm {
+        if regparm > 3 {
+            sess.dcx().emit_err(errors::UnsupportedRegparm { regparm });
+        }
+        if sess.target.arch != "x86" {
+            sess.dcx().emit_err(errors::UnsupportedRegparmArch);
+        }
+    }
+
     // The code model check applies to `thunk` and `thunk-extern`, but not `thunk-inline`, so it is
     // kept as a `match` to force a change if new ones are added, even if we currently only support
     // `thunk-extern` like Clang.
diff --git a/compiler/rustc_smir/src/rustc_internal/internal.rs b/compiler/rustc_smir/src/rustc_internal/internal.rs
index e9c3b3f..7be7db1 100644
--- a/compiler/rustc_smir/src/rustc_internal/internal.rs
+++ b/compiler/rustc_smir/src/rustc_internal/internal.rs
@@ -380,11 +380,12 @@
     type T<'tcx> = rustc_ty::ExistentialProjection<'tcx>;
 
     fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> {
-        rustc_ty::ExistentialProjection {
-            def_id: self.def_id.0.internal(tables, tcx),
-            args: self.generic_args.internal(tables, tcx),
-            term: self.term.internal(tables, tcx),
-        }
+        rustc_ty::ExistentialProjection::new_from_args(
+            tcx,
+            self.def_id.0.internal(tables, tcx),
+            self.generic_args.internal(tables, tcx),
+            self.term.internal(tables, tcx),
+        )
     }
 }
 
@@ -403,10 +404,11 @@
     type T<'tcx> = rustc_ty::ExistentialTraitRef<'tcx>;
 
     fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> {
-        rustc_ty::ExistentialTraitRef {
-            def_id: self.def_id.0.internal(tables, tcx),
-            args: self.generic_args.internal(tables, tcx),
-        }
+        rustc_ty::ExistentialTraitRef::new_from_args(
+            tcx,
+            self.def_id.0.internal(tables, tcx),
+            self.generic_args.internal(tables, tcx),
+        )
     }
 }
 
diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs
index 8fa8f2a..9514ec8 100644
--- a/compiler/rustc_smir/src/rustc_smir/context.rs
+++ b/compiler/rustc_smir/src/rustc_smir/context.rs
@@ -161,8 +161,7 @@
     fn predicates_of(&self, def_id: stable_mir::DefId) -> stable_mir::ty::GenericPredicates {
         let mut tables = self.0.borrow_mut();
         let def_id = tables[def_id];
-        let GenericPredicates { parent, predicates, effects_min_tys: _ } =
-            tables.tcx.predicates_of(def_id);
+        let GenericPredicates { parent, predicates } = tables.tcx.predicates_of(def_id);
         stable_mir::ty::GenericPredicates {
             parent: parent.map(|did| tables.trait_def(did)),
             predicates: predicates
@@ -183,8 +182,7 @@
     ) -> stable_mir::ty::GenericPredicates {
         let mut tables = self.0.borrow_mut();
         let def_id = tables[def_id];
-        let GenericPredicates { parent, predicates, effects_min_tys: _ } =
-            tables.tcx.explicit_predicates_of(def_id);
+        let GenericPredicates { parent, predicates } = tables.tcx.explicit_predicates_of(def_id);
         stable_mir::ty::GenericPredicates {
             parent: parent.map(|did| tables.trait_def(did)),
             predicates: predicates
diff --git a/compiler/rustc_smir/src/rustc_smir/convert/abi.rs b/compiler/rustc_smir/src/rustc_smir/convert/abi.rs
index 06f01ae..dbfcde56f 100644
--- a/compiler/rustc_smir/src/rustc_smir/convert/abi.rs
+++ b/compiler/rustc_smir/src/rustc_smir/convert/abi.rs
@@ -50,7 +50,7 @@
 }
 
 impl<'tcx> Stable<'tcx>
-    for rustc_abi::LayoutS<rustc_target::abi::FieldIdx, rustc_target::abi::VariantIdx>
+    for rustc_abi::LayoutData<rustc_target::abi::FieldIdx, rustc_target::abi::VariantIdx>
 {
     type T = LayoutShape;
 
diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
index b937228..8f05f859 100644
--- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
+++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
@@ -68,7 +68,7 @@
     type T = stable_mir::ty::ExistentialTraitRef;
 
     fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
-        let ty::ExistentialTraitRef { def_id, args } = self;
+        let ty::ExistentialTraitRef { def_id, args, .. } = self;
         stable_mir::ty::ExistentialTraitRef {
             def_id: tables.trait_def(*def_id),
             generic_args: args.stable(tables),
@@ -95,7 +95,7 @@
     type T = stable_mir::ty::ExistentialProjection;
 
     fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
-        let ty::ExistentialProjection { def_id, args, term } = self;
+        let ty::ExistentialProjection { def_id, args, term, .. } = self;
         stable_mir::ty::ExistentialProjection {
             def_id: tables.trait_def(*def_id),
             generic_args: args.stable(tables),
@@ -588,7 +588,6 @@
                 .has_late_bound_regions
                 .as_ref()
                 .map(|late_bound_regions| late_bound_regions.stable(tables)),
-            host_effect_index: self.host_effect_index,
         }
     }
 }
@@ -603,7 +602,7 @@
             ty::GenericParamDefKind::Type { has_default, synthetic } => {
                 GenericParamDefKind::Type { has_default: *has_default, synthetic: *synthetic }
             }
-            ty::GenericParamDefKind::Const { has_default, is_host_effect: _, synthetic: _ } => {
+            ty::GenericParamDefKind::Const { has_default, synthetic: _ } => {
                 GenericParamDefKind::Const { has_default: *has_default }
             }
         }
@@ -690,6 +689,9 @@
             ClauseKind::ConstEvaluatable(const_) => {
                 stable_mir::ty::ClauseKind::ConstEvaluatable(const_.stable(tables))
             }
+            ClauseKind::HostEffect(..) => {
+                todo!()
+            }
         }
     }
 }
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 3ab4820..890c4fd 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -171,9 +171,11 @@
         CallOnceFuture,
         CallRefFuture,
         Capture,
+        Cell,
         Center,
         Cleanup,
         Clone,
+        CoercePointee,
         CoerceUnsized,
         Command,
         ConstParamTy,
@@ -195,14 +197,6 @@
         Display,
         DoubleEndedIterator,
         Duration,
-        EffectsCompat,
-        EffectsIntersection,
-        EffectsIntersectionOutput,
-        EffectsMaybe,
-        EffectsNoRuntime,
-        EffectsRuntime,
-        EffectsTyCompat,
-        Effects__,
         Encodable,
         Encoder,
         Enumerate,
@@ -315,7 +309,6 @@
         Sized,
         SliceIndex,
         SliceIter,
-        SmartPointer,
         Some,
         SpanCtxt,
         String,
@@ -417,6 +410,7 @@
         arm,
         arm_target_feature,
         array,
+        as_mut_ptr,
         as_ptr,
         as_ref,
         as_str,
@@ -740,6 +734,7 @@
         deref_pure,
         deref_target,
         derive,
+        derive_coerce_pointee,
         derive_const,
         derive_default_enum,
         derive_smart_pointer,
@@ -1133,6 +1128,7 @@
         lazy_normalization_consts,
         lazy_type_alias,
         le,
+        legacy_receiver,
         len,
         let_chains,
         let_else,
@@ -1573,7 +1569,6 @@
         readonly,
         realloc,
         reason,
-        receiver,
         recursion_limit,
         reexport_test_harness_main,
         ref_pat_eat_one_layer_2024,
@@ -1668,6 +1663,7 @@
         rustc_confusables,
         rustc_const_panic_str,
         rustc_const_stable,
+        rustc_const_stable_indirect,
         rustc_const_unstable,
         rustc_conversion_suggestion,
         rustc_deallocator,
@@ -1737,7 +1733,6 @@
         rustc_reallocator,
         rustc_regions,
         rustc_reservation_impl,
-        rustc_runtime,
         rustc_safe_intrinsic,
         rustc_serialize,
         rustc_skip_during_method_dispatch,
diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs
index 78e6b9e..5c5ab43 100644
--- a/compiler/rustc_symbol_mangling/src/lib.rs
+++ b/compiler/rustc_symbol_mangling/src/lib.rs
@@ -135,7 +135,7 @@
         // This closure determines the instantiating crate for instances that
         // need an instantiating-crate-suffix for their symbol name, in order
         // to differentiate between local copies.
-        if is_generic(instance, tcx) {
+        if is_generic(instance) {
             // For generics we might find re-usable upstream instances. If there
             // is one, we rely on the symbol being instantiated locally.
             instance.upstream_monomorphization(tcx).unwrap_or(LOCAL_CRATE)
@@ -241,7 +241,7 @@
     // the ID of the instantiating crate. This avoids symbol conflicts
     // in case the same instances is emitted in two crates of the same
     // project.
-    let avoid_cross_crate_conflicts = is_generic(instance, tcx) || is_globally_shared_function;
+    let avoid_cross_crate_conflicts = is_generic(instance) || is_globally_shared_function;
 
     let instantiating_crate = avoid_cross_crate_conflicts.then(compute_instantiating_crate);
 
@@ -276,6 +276,6 @@
     symbol
 }
 
-fn is_generic<'tcx>(instance: Instance<'tcx>, tcx: TyCtxt<'tcx>) -> bool {
-    instance.args.non_erasable_generics(tcx, instance.def_id()).next().is_some()
+fn is_generic<'tcx>(instance: Instance<'tcx>) -> bool {
+    instance.args.non_erasable_generics().next().is_some()
 }
diff --git a/compiler/rustc_symbol_mangling/src/test.rs b/compiler/rustc_symbol_mangling/src/test.rs
index 8cfb65c..73bd8d7 100644
--- a/compiler/rustc_symbol_mangling/src/test.rs
+++ b/compiler/rustc_symbol_mangling/src/test.rs
@@ -18,7 +18,7 @@
     // if the `rustc_attrs` feature is not enabled, then the
     // attributes we are interested in cannot be present anyway, so
     // skip the walk.
-    if !tcx.features().rustc_attrs {
+    if !tcx.features().rustc_attrs() {
         return;
     }
 
diff --git a/compiler/rustc_target/src/callconv/loongarch.rs b/compiler/rustc_target/src/callconv/loongarch.rs
index 4a21935..ffec763 100644
--- a/compiler/rustc_target/src/callconv/loongarch.rs
+++ b/compiler/rustc_target/src/callconv/loongarch.rs
@@ -1,6 +1,7 @@
 use crate::abi::call::{ArgAbi, ArgExtension, CastTarget, FnAbi, PassMode, Reg, RegKind, Uniform};
 use crate::abi::{self, Abi, FieldsShape, HasDataLayout, Size, TyAbiInterface, TyAndLayout};
 use crate::spec::HasTargetSpec;
+use crate::spec::abi::Abi as SpecAbi;
 
 #[derive(Copy, Clone)]
 enum RegPassKind {
@@ -359,3 +360,30 @@
         );
     }
 }
+
+pub(crate) fn compute_rust_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>, abi: SpecAbi)
+where
+    Ty: TyAbiInterface<'a, C> + Copy,
+    C: HasDataLayout + HasTargetSpec,
+{
+    if abi == SpecAbi::RustIntrinsic {
+        return;
+    }
+
+    let grlen = cx.data_layout().pointer_size.bits();
+
+    for arg in fn_abi.args.iter_mut() {
+        if arg.is_ignore() {
+            continue;
+        }
+
+        // LLVM integers types do not differentiate between signed or unsigned integers.
+        // Some LoongArch instructions do not have a `.w` suffix version, they use all the
+        // GRLEN bits. By explicitly setting the `signext` or `zeroext` attribute
+        // according to signedness to avoid unnecessary integer extending instructions.
+        //
+        // This is similar to the RISC-V case, see
+        // https://github.com/rust-lang/rust/issues/114508 for details.
+        extend_integer_width(arg, grlen);
+    }
+}
diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs
index 8322464..25b001b 100644
--- a/compiler/rustc_target/src/callconv/mod.rs
+++ b/compiler/rustc_target/src/callconv/mod.rs
@@ -1,12 +1,15 @@
-use std::fmt;
 use std::str::FromStr;
+use std::{fmt, iter};
 
 pub use rustc_abi::{Reg, RegKind};
 use rustc_macros::HashStable_Generic;
 use rustc_span::Symbol;
 
-use crate::abi::{self, Abi, Align, HasDataLayout, Size, TyAbiInterface, TyAndLayout};
-use crate::spec::{self, HasTargetSpec, HasWasmCAbiOpt, WasmCAbi};
+use crate::abi::{
+    self, Abi, AddressSpace, Align, HasDataLayout, Pointer, Size, TyAbiInterface, TyAndLayout,
+};
+use crate::spec::abi::Abi as SpecAbi;
+use crate::spec::{self, HasTargetSpec, HasWasmCAbiOpt, HasX86AbiOpt, WasmCAbi};
 
 mod aarch64;
 mod amdgpu;
@@ -631,7 +634,7 @@
     ) -> Result<(), AdjustForForeignAbiError>
     where
         Ty: TyAbiInterface<'a, C> + Copy,
-        C: HasDataLayout + HasTargetSpec + HasWasmCAbiOpt,
+        C: HasDataLayout + HasTargetSpec + HasWasmCAbiOpt + HasX86AbiOpt,
     {
         if abi == spec::abi::Abi::X86Interrupt {
             if let Some(arg) = self.args.first_mut() {
@@ -643,14 +646,18 @@
         let spec = cx.target_spec();
         match &spec.arch[..] {
             "x86" => {
-                let flavor = if let spec::abi::Abi::Fastcall { .. }
-                | spec::abi::Abi::Vectorcall { .. } = abi
-                {
-                    x86::Flavor::FastcallOrVectorcall
-                } else {
-                    x86::Flavor::General
+                let (flavor, regparm) = match abi {
+                    spec::abi::Abi::Fastcall { .. } | spec::abi::Abi::Vectorcall { .. } => {
+                        (x86::Flavor::FastcallOrVectorcall, None)
+                    }
+                    spec::abi::Abi::C { .. }
+                    | spec::abi::Abi::Cdecl { .. }
+                    | spec::abi::Abi::Stdcall { .. } => {
+                        (x86::Flavor::General, cx.x86_abi_opt().regparm)
+                    }
+                    _ => (x86::Flavor::General, None),
                 };
-                x86::compute_abi_info(cx, self, flavor);
+                x86::compute_abi_info(cx, self, x86::X86Options { flavor, regparm });
             }
             "x86_64" => match abi {
                 spec::abi::Abi::SysV64 { .. } => x86_64::compute_abi_info(cx, self),
@@ -716,6 +723,118 @@
 
         Ok(())
     }
+
+    pub fn adjust_for_rust_abi<C>(&mut self, cx: &C, abi: SpecAbi)
+    where
+        Ty: TyAbiInterface<'a, C> + Copy,
+        C: HasDataLayout + HasTargetSpec,
+    {
+        let spec = cx.target_spec();
+        match &spec.arch[..] {
+            "x86" => x86::compute_rust_abi_info(cx, self, abi),
+            "riscv32" | "riscv64" => riscv::compute_rust_abi_info(cx, self, abi),
+            "loongarch64" => loongarch::compute_rust_abi_info(cx, self, abi),
+            _ => {}
+        };
+
+        for (arg_idx, arg) in self
+            .args
+            .iter_mut()
+            .enumerate()
+            .map(|(idx, arg)| (Some(idx), arg))
+            .chain(iter::once((None, &mut self.ret)))
+        {
+            if arg.is_ignore() {
+                continue;
+            }
+
+            if arg_idx.is_none() && arg.layout.size > Pointer(AddressSpace::DATA).size(cx) * 2 {
+                // Return values larger than 2 registers using a return area
+                // pointer. LLVM and Cranelift disagree about how to return
+                // values that don't fit in the registers designated for return
+                // values. LLVM will force the entire return value to be passed
+                // by return area pointer, while Cranelift will look at each IR level
+                // return value independently and decide to pass it in a
+                // register or not, which would result in the return value
+                // being passed partially in registers and partially through a
+                // return area pointer.
+                //
+                // While Cranelift may need to be fixed as the LLVM behavior is
+                // generally more correct with respect to the surface language,
+                // forcing this behavior in rustc itself makes it easier for
+                // other backends to conform to the Rust ABI and for the C ABI
+                // rustc already handles this behavior anyway.
+                //
+                // In addition LLVM's decision to pass the return value in
+                // registers or using a return area pointer depends on how
+                // exactly the return type is lowered to an LLVM IR type. For
+                // example `Option<u128>` can be lowered as `{ i128, i128 }`
+                // in which case the x86_64 backend would use a return area
+                // pointer, or it could be passed as `{ i32, i128 }` in which
+                // case the x86_64 backend would pass it in registers by taking
+                // advantage of an LLVM ABI extension that allows using 3
+                // registers for the x86_64 sysv call conv rather than the
+                // officially specified 2 registers.
+                //
+                // FIXME: Technically we should look at the amount of available
+                // return registers rather than guessing that there are 2
+                // registers for return values. In practice only a couple of
+                // architectures have less than 2 return registers. None of
+                // which supported by Cranelift.
+                //
+                // NOTE: This adjustment is only necessary for the Rust ABI as
+                // for other ABI's the calling convention implementations in
+                // rustc_target already ensure any return value which doesn't
+                // fit in the available amount of return registers is passed in
+                // the right way for the current target.
+                arg.make_indirect();
+                continue;
+            }
+
+            match arg.layout.abi {
+                Abi::Aggregate { .. } => {}
+
+                // This is a fun case! The gist of what this is doing is
+                // that we want callers and callees to always agree on the
+                // ABI of how they pass SIMD arguments. If we were to *not*
+                // make these arguments indirect then they'd be immediates
+                // in LLVM, which means that they'd used whatever the
+                // appropriate ABI is for the callee and the caller. That
+                // means, for example, if the caller doesn't have AVX
+                // enabled but the callee does, then passing an AVX argument
+                // across this boundary would cause corrupt data to show up.
+                //
+                // This problem is fixed by unconditionally passing SIMD
+                // arguments through memory between callers and callees
+                // which should get them all to agree on ABI regardless of
+                // target feature sets. Some more information about this
+                // issue can be found in #44367.
+                //
+                // Note that the intrinsic ABI is exempt here as
+                // that's how we connect up to LLVM and it's unstable
+                // anyway, we control all calls to it in libstd.
+                Abi::Vector { .. } if abi != SpecAbi::RustIntrinsic && spec.simd_types_indirect => {
+                    arg.make_indirect();
+                    continue;
+                }
+
+                _ => continue,
+            }
+            // Compute `Aggregate` ABI.
+
+            let is_indirect_not_on_stack =
+                matches!(arg.mode, PassMode::Indirect { on_stack: false, .. });
+            assert!(is_indirect_not_on_stack);
+
+            let size = arg.layout.size;
+            if !arg.layout.is_unsized() && size <= Pointer(AddressSpace::DATA).size(cx) {
+                // We want to pass small aggregates as immediates, but using
+                // an LLVM aggregate type for this leads to bad optimizations,
+                // so we pick an appropriately sized integer type instead.
+                arg.cast_to(Reg { kind: RegKind::Integer, size });
+            }
+        }
+    }
 }
 
 impl FromStr for Conv {
diff --git a/compiler/rustc_target/src/callconv/riscv.rs b/compiler/rustc_target/src/callconv/riscv.rs
index be6bc701..f96169e 100644
--- a/compiler/rustc_target/src/callconv/riscv.rs
+++ b/compiler/rustc_target/src/callconv/riscv.rs
@@ -7,6 +7,7 @@
 use crate::abi::call::{ArgAbi, ArgExtension, CastTarget, FnAbi, PassMode, Reg, RegKind, Uniform};
 use crate::abi::{self, Abi, FieldsShape, HasDataLayout, Size, TyAbiInterface, TyAndLayout};
 use crate::spec::HasTargetSpec;
+use crate::spec::abi::Abi as SpecAbi;
 
 #[derive(Copy, Clone)]
 enum RegPassKind {
@@ -365,3 +366,29 @@
         );
     }
 }
+
+pub(crate) fn compute_rust_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>, abi: SpecAbi)
+where
+    Ty: TyAbiInterface<'a, C> + Copy,
+    C: HasDataLayout + HasTargetSpec,
+{
+    if abi == SpecAbi::RustIntrinsic {
+        return;
+    }
+
+    let xlen = cx.data_layout().pointer_size.bits();
+
+    for arg in fn_abi.args.iter_mut() {
+        if arg.is_ignore() {
+            continue;
+        }
+
+        // LLVM integers types do not differentiate between signed or unsigned integers.
+        // Some RISC-V instructions do not have a `.w` suffix version, they use all the
+        // XLEN bits. By explicitly setting the `signext` or `zeroext` attribute
+        // according to signedness to avoid unnecessary integer extending instructions.
+        //
+        // See https://github.com/rust-lang/rust/issues/114508 for details.
+        extend_integer_width(arg, xlen);
+    }
+}
diff --git a/compiler/rustc_target/src/callconv/x86.rs b/compiler/rustc_target/src/callconv/x86.rs
index d9af83d..e907bee 100644
--- a/compiler/rustc_target/src/callconv/x86.rs
+++ b/compiler/rustc_target/src/callconv/x86.rs
@@ -1,6 +1,9 @@
 use crate::abi::call::{ArgAttribute, FnAbi, PassMode, Reg, RegKind};
-use crate::abi::{Abi, Align, HasDataLayout, TyAbiInterface, TyAndLayout};
+use crate::abi::{
+    Abi, AddressSpace, Align, Float, HasDataLayout, Pointer, TyAbiInterface, TyAndLayout,
+};
 use crate::spec::HasTargetSpec;
+use crate::spec::abi::Abi as SpecAbi;
 
 #[derive(PartialEq)]
 pub(crate) enum Flavor {
@@ -8,7 +11,12 @@
     FastcallOrVectorcall,
 }
 
-pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>, flavor: Flavor)
+pub(crate) struct X86Options {
+    pub flavor: Flavor,
+    pub regparm: Option<u32>,
+}
+
+pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>, opts: X86Options)
 where
     Ty: TyAbiInterface<'a, C> + Copy,
     C: HasDataLayout + HasTargetSpec,
@@ -128,58 +136,109 @@
         }
     }
 
-    if flavor == Flavor::FastcallOrVectorcall {
-        // Mark arguments as InReg like clang does it,
-        // so our fastcall/vectorcall is compatible with C/C++ fastcall/vectorcall.
+    fill_inregs(cx, fn_abi, opts, false);
+}
 
-        // Clang reference: lib/CodeGen/TargetInfo.cpp
-        // See X86_32ABIInfo::shouldPrimitiveUseInReg(), X86_32ABIInfo::updateFreeRegs()
+pub(crate) fn fill_inregs<'a, Ty, C>(
+    cx: &C,
+    fn_abi: &mut FnAbi<'a, Ty>,
+    opts: X86Options,
+    rust_abi: bool,
+) where
+    Ty: TyAbiInterface<'a, C> + Copy,
+{
+    if opts.flavor != Flavor::FastcallOrVectorcall && opts.regparm.is_none_or(|x| x == 0) {
+        return;
+    }
+    // Mark arguments as InReg like clang does it,
+    // so our fastcall/vectorcall is compatible with C/C++ fastcall/vectorcall.
 
-        // IsSoftFloatABI is only set to true on ARM platforms,
-        // which in turn can't be x86?
+    // Clang reference: lib/CodeGen/TargetInfo.cpp
+    // See X86_32ABIInfo::shouldPrimitiveUseInReg(), X86_32ABIInfo::updateFreeRegs()
 
-        let mut free_regs = 2;
+    // IsSoftFloatABI is only set to true on ARM platforms,
+    // which in turn can't be x86?
 
-        for arg in fn_abi.args.iter_mut() {
-            let attrs = match arg.mode {
-                PassMode::Ignore
-                | PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: _ } => {
-                    continue;
-                }
-                PassMode::Direct(ref mut attrs) => attrs,
-                PassMode::Pair(..)
-                | PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ }
-                | PassMode::Cast { .. } => {
-                    unreachable!("x86 shouldn't be passing arguments by {:?}", arg.mode)
-                }
-            };
+    // 2 for fastcall/vectorcall, regparm limited by 3 otherwise
+    let mut free_regs = opts.regparm.unwrap_or(2).into();
 
-            // At this point we know this must be a primitive of sorts.
-            let unit = arg.layout.homogeneous_aggregate(cx).unwrap().unit().unwrap();
-            assert_eq!(unit.size, arg.layout.size);
-            if unit.kind == RegKind::Float {
+    // For types generating PassMode::Cast, InRegs will not be set.
+    // Maybe, this is a FIXME
+    let has_casts = fn_abi.args.iter().any(|arg| matches!(arg.mode, PassMode::Cast { .. }));
+    if has_casts && rust_abi {
+        return;
+    }
+
+    for arg in fn_abi.args.iter_mut() {
+        let attrs = match arg.mode {
+            PassMode::Ignore | PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: _ } => {
                 continue;
             }
-
-            let size_in_regs = (arg.layout.size.bits() + 31) / 32;
-
-            if size_in_regs == 0 {
-                continue;
+            PassMode::Direct(ref mut attrs) => attrs,
+            PassMode::Pair(..)
+            | PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ }
+            | PassMode::Cast { .. } => {
+                unreachable!("x86 shouldn't be passing arguments by {:?}", arg.mode)
             }
+        };
 
-            if size_in_regs > free_regs {
-                break;
+        // At this point we know this must be a primitive of sorts.
+        let unit = arg.layout.homogeneous_aggregate(cx).unwrap().unit().unwrap();
+        assert_eq!(unit.size, arg.layout.size);
+        if matches!(unit.kind, RegKind::Float | RegKind::Vector) {
+            continue;
+        }
+
+        let size_in_regs = (arg.layout.size.bits() + 31) / 32;
+
+        if size_in_regs == 0 {
+            continue;
+        }
+
+        if size_in_regs > free_regs {
+            break;
+        }
+
+        free_regs -= size_in_regs;
+
+        if arg.layout.size.bits() <= 32 && unit.kind == RegKind::Integer {
+            attrs.set(ArgAttribute::InReg);
+        }
+
+        if free_regs == 0 {
+            break;
+        }
+    }
+}
+
+pub(crate) fn compute_rust_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>, abi: SpecAbi)
+where
+    Ty: TyAbiInterface<'a, C> + Copy,
+    C: HasDataLayout + HasTargetSpec,
+{
+    // Avoid returning floats in x87 registers on x86 as loading and storing from x87
+    // registers will quiet signalling NaNs. Also avoid using SSE registers since they
+    // are not always available (depending on target features).
+    if !fn_abi.ret.is_ignore()
+        // Intrinsics themselves are not actual "real" functions, so theres no need to change their ABIs.
+        && abi != SpecAbi::RustIntrinsic
+    {
+        let has_float = match fn_abi.ret.layout.abi {
+            Abi::Scalar(s) => matches!(s.primitive(), Float(_)),
+            Abi::ScalarPair(s1, s2) => {
+                matches!(s1.primitive(), Float(_)) || matches!(s2.primitive(), Float(_))
             }
-
-            free_regs -= size_in_regs;
-
-            if arg.layout.size.bits() <= 32 && unit.kind == RegKind::Integer {
-                attrs.set(ArgAttribute::InReg);
+            _ => false, // anyway not passed via registers on x86
+        };
+        if has_float {
+            if fn_abi.ret.layout.size <= Pointer(AddressSpace::DATA).size(cx) {
+                // Same size or smaller than pointer, return in a register.
+                fn_abi.ret.cast_to(Reg { kind: RegKind::Integer, size: fn_abi.ret.layout.size });
+            } else {
+                // Larger than a pointer, return indirectly.
+                fn_abi.ret.make_indirect();
             }
-
-            if free_regs == 0 {
-                break;
-            }
+            return;
         }
     }
 }
diff --git a/compiler/rustc_target/src/spec/abi/mod.rs b/compiler/rustc_target/src/spec/abi/mod.rs
index cac0cf9..c209515 100644
--- a/compiler/rustc_target/src/spec/abi/mod.rs
+++ b/compiler/rustc_target/src/spec/abi/mod.rs
@@ -184,7 +184,7 @@
 ) -> Result<(), AbiDisabled> {
     let s = is_stable(name);
     if let Err(AbiDisabled::Unstable { feature, .. }) = s {
-        if features.active(feature) || span.allows_unstable(feature) {
+        if features.enabled(feature) || span.allows_unstable(feature) {
             return Ok(());
         }
     }
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index 24f5646..f4cbe47 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -1803,6 +1803,7 @@
 
     ("wasm32-unknown-emscripten", wasm32_unknown_emscripten),
     ("wasm32-unknown-unknown", wasm32_unknown_unknown),
+    ("wasm32v1-none", wasm32v1_none),
     ("wasm32-wasi", wasm32_wasi),
     ("wasm32-wasip1", wasm32_wasip1),
     ("wasm32-wasip2", wasm32_wasip2),
@@ -2096,6 +2097,18 @@
     fn wasm_c_abi_opt(&self) -> WasmCAbi;
 }
 
+/// x86 (32-bit) abi options.
+#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
+pub struct X86Abi {
+    /// On x86-32 targets, the regparm N causes the compiler to pass arguments
+    /// in registers EAX, EDX, and ECX instead of on the stack.
+    pub regparm: Option<u32>,
+}
+
+pub trait HasX86AbiOpt {
+    fn x86_abi_opt(&self) -> X86Abi;
+}
+
 type StaticCow<T> = Cow<'static, T>;
 
 /// Optional aspects of a target specification.
diff --git a/compiler/rustc_target/src/spec/targets/i586_pc_nto_qnx700.rs b/compiler/rustc_target/src/spec/targets/i586_pc_nto_qnx700.rs
index 2519b93..7648f81 100644
--- a/compiler/rustc_target/src/spec/targets/i586_pc_nto_qnx700.rs
+++ b/compiler/rustc_target/src/spec/targets/i586_pc_nto_qnx700.rs
@@ -21,6 +21,7 @@
                 "-Vgcc_ntox86_cxx",
             ]),
             env: "nto70".into(),
+            vendor: "pc".into(),
             stack_probes: StackProbeType::Inline,
             ..base::nto_qnx::opts()
         },
diff --git a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs
index 68d5119..603c0f9 100644
--- a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs
@@ -15,7 +15,7 @@
         options: TargetOptions {
             code_model: Some(CodeModel::Medium),
             cpu: "generic".into(),
-            features: "+f,+d".into(),
+            features: "+f,+d,+lsx".into(),
             llvm_abiname: "lp64d".into(),
             max_atomic_width: Some(64),
             supported_sanitizers: SanitizerSet::ADDRESS
diff --git a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_musl.rs
index 25d3559..d7044dd 100644
--- a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_musl.rs
@@ -15,7 +15,7 @@
         options: TargetOptions {
             code_model: Some(CodeModel::Medium),
             cpu: "generic".into(),
-            features: "+f,+d".into(),
+            features: "+f,+d,+lsx".into(),
             llvm_abiname: "lp64d".into(),
             max_atomic_width: Some(64),
             crt_static_default: false,
diff --git a/compiler/rustc_target/src/spec/targets/riscv32i_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32i_unknown_none_elf.rs
index 1995de9..0e0e13f 100644
--- a/compiler/rustc_target/src/spec/targets/riscv32i_unknown_none_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv32i_unknown_none_elf.rs
@@ -20,6 +20,7 @@
             max_atomic_width: Some(32),
             atomic_cas: false,
             features: "+forced-atomics".into(),
+            llvm_abiname: "ilp32".into(),
             panic_strategy: PanicStrategy::Abort,
             relocation_model: RelocModel::Static,
             emit_debug_gdb_scripts: false,
diff --git a/compiler/rustc_target/src/spec/targets/riscv32im_risc0_zkvm_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32im_risc0_zkvm_elf.rs
index bd37cf8..669c170 100644
--- a/compiler/rustc_target/src/spec/targets/riscv32im_risc0_zkvm_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv32im_risc0_zkvm_elf.rs
@@ -29,6 +29,7 @@
             atomic_cas: true,
 
             features: "+m".into(),
+            llvm_abiname: "ilp32".into(),
             executables: true,
             panic_strategy: PanicStrategy::Abort,
             relocation_model: RelocModel::Static,
diff --git a/compiler/rustc_target/src/spec/targets/riscv32im_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32im_unknown_none_elf.rs
index 32df30d..477a6c0 100644
--- a/compiler/rustc_target/src/spec/targets/riscv32im_unknown_none_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv32im_unknown_none_elf.rs
@@ -20,6 +20,7 @@
             max_atomic_width: Some(32),
             atomic_cas: false,
             features: "+m,+forced-atomics".into(),
+            llvm_abiname: "ilp32".into(),
             panic_strategy: PanicStrategy::Abort,
             relocation_model: RelocModel::Static,
             emit_debug_gdb_scripts: false,
diff --git a/compiler/rustc_target/src/spec/targets/riscv32ima_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32ima_unknown_none_elf.rs
index 61c8870..6814678 100644
--- a/compiler/rustc_target/src/spec/targets/riscv32ima_unknown_none_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv32ima_unknown_none_elf.rs
@@ -19,6 +19,7 @@
             cpu: "generic-rv32".into(),
             max_atomic_width: Some(32),
             features: "+m,+a".into(),
+            llvm_abiname: "ilp32".into(),
             panic_strategy: PanicStrategy::Abort,
             relocation_model: RelocModel::Static,
             emit_debug_gdb_scripts: false,
diff --git a/compiler/rustc_target/src/spec/targets/riscv32imac_esp_espidf.rs b/compiler/rustc_target/src/spec/targets/riscv32imac_esp_espidf.rs
index 9795af5..e12c3af 100644
--- a/compiler/rustc_target/src/spec/targets/riscv32imac_esp_espidf.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv32imac_esp_espidf.rs
@@ -27,6 +27,7 @@
             atomic_cas: true,
 
             features: "+m,+a,+c".into(),
+            llvm_abiname: "ilp32".into(),
             panic_strategy: PanicStrategy::Abort,
             relocation_model: RelocModel::Static,
             emit_debug_gdb_scripts: false,
diff --git a/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_none_elf.rs
index cc28198..adc76f3 100644
--- a/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_none_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_none_elf.rs
@@ -19,6 +19,7 @@
             cpu: "generic-rv32".into(),
             max_atomic_width: Some(32),
             features: "+m,+a,+c".into(),
+            llvm_abiname: "ilp32".into(),
             panic_strategy: PanicStrategy::Abort,
             relocation_model: RelocModel::Static,
             emit_debug_gdb_scripts: false,
diff --git a/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_nuttx_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_nuttx_elf.rs
index 62397dca..31c9180 100644
--- a/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_nuttx_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_nuttx_elf.rs
@@ -21,6 +21,7 @@
             cpu: "generic-rv32".into(),
             max_atomic_width: Some(32),
             features: "+m,+a,+c".into(),
+            llvm_abiname: "ilp32".into(),
             panic_strategy: PanicStrategy::Unwind,
             relocation_model: RelocModel::Static,
             ..Default::default()
diff --git a/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_xous_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_xous_elf.rs
index 0eaabc6..88d112a 100644
--- a/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_xous_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_xous_elf.rs
@@ -20,6 +20,7 @@
             cpu: "generic-rv32".into(),
             max_atomic_width: Some(32),
             features: "+m,+a,+c".into(),
+            llvm_abiname: "ilp32".into(),
             panic_strategy: PanicStrategy::Unwind,
             relocation_model: RelocModel::Static,
             ..Default::default()
diff --git a/compiler/rustc_target/src/spec/targets/riscv32imc_esp_espidf.rs b/compiler/rustc_target/src/spec/targets/riscv32imc_esp_espidf.rs
index 9ae84ac..cec97f8 100644
--- a/compiler/rustc_target/src/spec/targets/riscv32imc_esp_espidf.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv32imc_esp_espidf.rs
@@ -30,6 +30,7 @@
             atomic_cas: true,
 
             features: "+m,+c".into(),
+            llvm_abiname: "ilp32".into(),
             panic_strategy: PanicStrategy::Abort,
             relocation_model: RelocModel::Static,
             emit_debug_gdb_scripts: false,
diff --git a/compiler/rustc_target/src/spec/targets/riscv32imc_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32imc_unknown_none_elf.rs
index 0ae49de..0e00fc6 100644
--- a/compiler/rustc_target/src/spec/targets/riscv32imc_unknown_none_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv32imc_unknown_none_elf.rs
@@ -20,6 +20,7 @@
             max_atomic_width: Some(32),
             atomic_cas: false,
             features: "+m,+c,+forced-atomics".into(),
+            llvm_abiname: "ilp32".into(),
             panic_strategy: PanicStrategy::Abort,
             relocation_model: RelocModel::Static,
             emit_debug_gdb_scripts: false,
diff --git a/compiler/rustc_target/src/spec/targets/riscv32imc_unknown_nuttx_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32imc_unknown_nuttx_elf.rs
index 5f3917e..e865498 100644
--- a/compiler/rustc_target/src/spec/targets/riscv32imc_unknown_nuttx_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv32imc_unknown_nuttx_elf.rs
@@ -21,6 +21,7 @@
             cpu: "generic-rv32".into(),
             max_atomic_width: Some(32),
             features: "+m,+c".into(),
+            llvm_abiname: "ilp32".into(),
             panic_strategy: PanicStrategy::Unwind,
             relocation_model: RelocModel::Static,
             ..Default::default()
diff --git a/compiler/rustc_target/src/spec/targets/riscv64imac_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv64imac_unknown_none_elf.rs
index d514f8e..d62ecc0 100644
--- a/compiler/rustc_target/src/spec/targets/riscv64imac_unknown_none_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv64imac_unknown_none_elf.rs
@@ -22,6 +22,7 @@
             cpu: "generic-rv64".into(),
             max_atomic_width: Some(64),
             features: "+m,+a,+c".into(),
+            llvm_abiname: "lp64".into(),
             panic_strategy: PanicStrategy::Abort,
             relocation_model: RelocModel::Static,
             code_model: Some(CodeModel::Medium),
diff --git a/compiler/rustc_target/src/spec/targets/riscv64imac_unknown_nuttx_elf.rs b/compiler/rustc_target/src/spec/targets/riscv64imac_unknown_nuttx_elf.rs
index a737e46..9c18166 100644
--- a/compiler/rustc_target/src/spec/targets/riscv64imac_unknown_nuttx_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv64imac_unknown_nuttx_elf.rs
@@ -24,6 +24,7 @@
             cpu: "generic-rv64".into(),
             max_atomic_width: Some(64),
             features: "+m,+a,+c".into(),
+            llvm_abiname: "lp64".into(),
             panic_strategy: PanicStrategy::Abort,
             relocation_model: RelocModel::Static,
             code_model: Some(CodeModel::Medium),
diff --git a/compiler/rustc_target/src/spec/targets/wasm32v1_none.rs b/compiler/rustc_target/src/spec/targets/wasm32v1_none.rs
new file mode 100644
index 0000000..bf35ae0
--- /dev/null
+++ b/compiler/rustc_target/src/spec/targets/wasm32v1_none.rs
@@ -0,0 +1,51 @@
+//! A "bare wasm" target representing a WebAssembly output that does not import
+//! anything from its environment and also specifies an _upper_ bound on the set
+//! of WebAssembly proposals that are supported.
+//!
+//! It's equivalent to the `wasm32-unknown-unknown` target with the additional
+//! flags `-Ctarget-cpu=mvp` and `-Ctarget-feature=+mutable-globals`. This
+//! enables just the features specified in <https://www.w3.org/TR/wasm-core-1/>
+//!
+//! This is a _separate target_ because using `wasm32-unknown-unknown` with
+//! those target flags doesn't automatically rebuild libcore / liballoc with
+//! them, and in order to get those libraries rebuilt you need to use the
+//! nightly Rust feature `-Zbuild-std`. This target is for people who want to
+//! use stable Rust, and target a stable set pf WebAssembly features.
+
+use crate::spec::{Cc, LinkerFlavor, Target, base};
+
+pub(crate) fn target() -> Target {
+    let mut options = base::wasm::options();
+    options.os = "none".into();
+
+    // WebAssembly 1.0 shipped in 2019 and included exactly one proposal
+    // after the initial "MVP" feature set: "mutable-globals".
+    options.cpu = "mvp".into();
+    options.features = "+mutable-globals".into();
+
+    options.add_pre_link_args(LinkerFlavor::WasmLld(Cc::No), &[
+        // For now this target just never has an entry symbol no matter the output
+        // type, so unconditionally pass this.
+        "--no-entry",
+    ]);
+    options.add_pre_link_args(LinkerFlavor::WasmLld(Cc::Yes), &[
+        // Make sure clang uses LLD as its linker and is configured appropriately
+        // otherwise
+        "--target=wasm32-unknown-unknown",
+        "-Wl,--no-entry",
+    ]);
+
+    Target {
+        llvm_target: "wasm32-unknown-unknown".into(),
+        metadata: crate::spec::TargetMetadata {
+            description: Some("WebAssembly".into()),
+            tier: Some(2),
+            host_tools: Some(false),
+            std: Some(false),
+        },
+        pointer_width: 32,
+        data_layout: "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20".into(),
+        arch: "wasm32".into(),
+        options,
+    }
+}
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_pc_nto_qnx710.rs b/compiler/rustc_target/src/spec/targets/x86_64_pc_nto_qnx710.rs
index 1aa8249..245a5f0 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_pc_nto_qnx710.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_pc_nto_qnx710.rs
@@ -21,6 +21,7 @@
                 "-Vgcc_ntox86_64_cxx",
             ]),
             env: "nto71".into(),
+            vendor: "pc".into(),
             ..base::nto_qnx::opts()
         },
     }
diff --git a/compiler/rustc_target/src/spec/tests/tests_impl.rs b/compiler/rustc_target/src/spec/tests/tests_impl.rs
index fc5bd84..cc5931b 100644
--- a/compiler/rustc_target/src/spec/tests/tests_impl.rs
+++ b/compiler/rustc_target/src/spec/tests/tests_impl.rs
@@ -121,7 +121,13 @@
         // Check dynamic linking stuff
         // BPF: when targeting user space vms (like rbpf), those can load dynamic libraries.
         // hexagon: when targeting QuRT, that OS can load dynamic libraries.
-        if self.os == "none" && (self.arch != "bpf" && self.arch != "hexagon") {
+        // wasm{32,64}: dynamic linking is inherent in the definition of the VM.
+        if self.os == "none"
+            && (self.arch != "bpf"
+                && self.arch != "hexagon"
+                && self.arch != "wasm32"
+                && self.arch != "wasm64")
+        {
             assert!(!self.dynamic_linking);
         }
         if self.only_cdylib
@@ -152,6 +158,17 @@
         if self.crt_static_default || self.crt_static_allows_dylibs {
             assert!(self.crt_static_respected);
         }
+
+        // Check that RISC-V targets always specify which ABI they use.
+        match &*self.arch {
+            "riscv32" => {
+                assert_matches!(&*self.llvm_abiname, "ilp32" | "ilp32f" | "ilp32d" | "ilp32e")
+            }
+            "riscv64" => {
+                assert_matches!(&*self.llvm_abiname, "lp64" | "lp64f" | "lp64d" | "lp64q")
+            }
+            _ => {}
+        }
     }
 
     // Add your target to the whitelist if it has `std` library
diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs
index e92366d..3df8f05 100644
--- a/compiler/rustc_target/src/target_features.rs
+++ b/compiler/rustc_target/src/target_features.rs
@@ -167,6 +167,8 @@
     ("pacg", Stable, &[]),
     // FEAT_PAN
     ("pan", Stable, &[]),
+    // FEAT_PAuth_LR
+    ("pauth-lr", Unstable(sym::aarch64_unstable_target_feature), &[]),
     // FEAT_PMUv3
     ("pmuv3", Stable, &[]),
     // FEAT_RNG
@@ -316,7 +318,7 @@
     ("lahfsahf", Unstable(sym::lahfsahf_target_feature), &[]),
     ("lzcnt", Stable, &[]),
     ("movbe", Stable, &[]),
-    ("pclmulqdq", Stable, &[]),
+    ("pclmulqdq", Stable, &["sse2"]),
     ("popcnt", Stable, &[]),
     ("prfchw", Unstable(sym::prfchw_target_feature), &[]),
     ("rdrand", Stable, &[]),
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
index df5800a..574cf1e 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
@@ -75,6 +75,7 @@
 use crate::infer;
 use crate::infer::relate::{self, RelateResult, TypeRelation};
 use crate::infer::{InferCtxt, TypeTrace, ValuePairs};
+use crate::solve::deeply_normalize_for_diagnostics;
 use crate::traits::{
     IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode,
 };
@@ -145,21 +146,31 @@
     pub fn report_mismatched_types(
         &self,
         cause: &ObligationCause<'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
         expected: Ty<'tcx>,
         actual: Ty<'tcx>,
         err: TypeError<'tcx>,
     ) -> Diag<'a> {
-        self.report_and_explain_type_error(TypeTrace::types(cause, true, expected, actual), err)
+        self.report_and_explain_type_error(
+            TypeTrace::types(cause, true, expected, actual),
+            param_env,
+            err,
+        )
     }
 
     pub fn report_mismatched_consts(
         &self,
         cause: &ObligationCause<'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
         expected: ty::Const<'tcx>,
         actual: ty::Const<'tcx>,
         err: TypeError<'tcx>,
     ) -> Diag<'a> {
-        self.report_and_explain_type_error(TypeTrace::consts(cause, true, expected, actual), err)
+        self.report_and_explain_type_error(
+            TypeTrace::consts(cause, true, expected, actual),
+            param_env,
+            err,
+        )
     }
 
     pub fn get_impl_future_output_ty(&self, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
@@ -381,7 +392,7 @@
                         Some(ty) if expected == ty => {
                             let source_map = self.tcx.sess.source_map();
                             err.span_suggestion(
-                                source_map.end_point(cause.span()),
+                                source_map.end_point(cause.span),
                                 "try removing this `?`",
                                 "",
                                 Applicability::MachineApplicable,
@@ -401,6 +412,7 @@
                 source,
                 ref prior_non_diverging_arms,
                 scrut_span,
+                expr_span,
                 ..
             }) => match source {
                 hir::MatchSource::TryDesugar(scrut_hir_id) => {
@@ -419,7 +431,7 @@
                             Some(ty) if expected == ty => {
                                 let source_map = self.tcx.sess.source_map();
                                 err.span_suggestion(
-                                    source_map.end_point(cause.span()),
+                                    source_map.end_point(cause.span),
                                     "try removing this `?`",
                                     "",
                                     Applicability::MachineApplicable,
@@ -449,12 +461,12 @@
                             format!("this and all prior arms are found to be of type `{t}`"),
                         );
                     }
-                    let outer = if any_multiline_arm || !source_map.is_multiline(cause.span) {
+                    let outer = if any_multiline_arm || !source_map.is_multiline(expr_span) {
                         // Cover just `match` and the scrutinee expression, not
                         // the entire match body, to reduce diagram noise.
-                        cause.span.shrink_to_lo().to(scrut_span)
+                        expr_span.shrink_to_lo().to(scrut_span)
                     } else {
-                        cause.span
+                        expr_span
                     };
                     let msg = "`match` arms have incompatible types";
                     err.span_label(outer, msg);
@@ -1133,11 +1145,11 @@
         diag: &mut Diag<'_>,
         cause: &ObligationCause<'tcx>,
         secondary_span: Option<(Span, Cow<'static, str>, bool)>,
-        mut values: Option<ValuePairs<'tcx>>,
+        mut values: Option<ty::ParamEnvAnd<'tcx, ValuePairs<'tcx>>>,
         terr: TypeError<'tcx>,
         prefer_label: bool,
     ) {
-        let span = cause.span();
+        let span = cause.span;
 
         // For some types of errors, expected-found does not make
         // sense, so just ignore the values we were given.
@@ -1241,8 +1253,11 @@
         }
         let (expected_found, exp_found, is_simple_error, values) = match values {
             None => (None, Mismatch::Fixed("type"), false, None),
-            Some(values) => {
-                let values = self.resolve_vars_if_possible(values);
+            Some(ty::ParamEnvAnd { param_env, value: values }) => {
+                let mut values = self.resolve_vars_if_possible(values);
+                if self.next_trait_solver() {
+                    values = deeply_normalize_for_diagnostics(self, param_env, values);
+                }
                 let (is_simple_error, exp_found) = match values {
                     ValuePairs::Terms(ExpectedFound { expected, found }) => {
                         match (expected.unpack(), found.unpack()) {
@@ -1628,7 +1643,7 @@
         terr: TypeError<'tcx>,
     ) -> Vec<TypeErrorAdditionalDiags> {
         let mut suggestions = Vec::new();
-        let span = trace.cause.span();
+        let span = trace.cause.span;
         let values = self.resolve_vars_if_possible(trace.values);
         if let Some((expected, found)) = values.ty() {
             match (expected.kind(), found.kind()) {
@@ -1773,18 +1788,26 @@
     pub fn report_and_explain_type_error(
         &self,
         trace: TypeTrace<'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
         terr: TypeError<'tcx>,
     ) -> Diag<'a> {
         debug!("report_and_explain_type_error(trace={:?}, terr={:?})", trace, terr);
 
-        let span = trace.cause.span();
+        let span = trace.cause.span;
         let failure_code = trace.cause.as_failure_code_diag(
             terr,
             span,
             self.type_error_additional_suggestions(&trace, terr),
         );
         let mut diag = self.dcx().create_err(failure_code);
-        self.note_type_err(&mut diag, &trace.cause, None, Some(trace.values), terr, false);
+        self.note_type_err(
+            &mut diag,
+            &trace.cause,
+            None,
+            Some(param_env.and(trace.values)),
+            terr,
+            false,
+        );
         diag
     }
 
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs
index 14c2bf1..4398af7 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs
@@ -237,7 +237,7 @@
         expected_args: GenericArgsRef<'tcx>,
         actual_args: GenericArgsRef<'tcx>,
     ) -> Diag<'tcx> {
-        let span = cause.span();
+        let span = cause.span;
 
         let (leading_ellipsis, satisfy_span, where_span, dup_span, def_id) =
             if let ObligationCauseCode::WhereClause(def_id, span)
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs
index 62204f6..0cf7c43 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs
@@ -894,7 +894,7 @@
         // FIXME: we would want to call `resolve_vars_if_possible` on `ty` before suggesting.
 
         let trait_bounds = bounds.iter().filter_map(|bound| match bound {
-            hir::GenericBound::Trait(ptr) if ptr.modifiers == hir::TraitBoundModifier::None => {
+            hir::GenericBound::Trait(ptr) if ptr.modifiers == hir::TraitBoundModifiers::NONE => {
                 Some(ptr)
             }
             _ => None,
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs
index 94610a9..833358b2 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs
@@ -295,7 +295,11 @@
         let mut err = match origin {
             infer::Subtype(box trace) => {
                 let terr = TypeError::RegionsDoesNotOutlive(sup, sub);
-                let mut err = self.report_and_explain_type_error(trace, terr);
+                let mut err = self.report_and_explain_type_error(
+                    trace,
+                    self.tcx.param_env(generic_param_scope),
+                    terr,
+                );
                 match (*sub, *sup) {
                     (ty::RePlaceholder(_), ty::RePlaceholder(_)) => {}
                     (ty::RePlaceholder(_), _) => {
@@ -646,7 +650,11 @@
             }
             infer::Subtype(box trace) => {
                 let terr = TypeError::RegionsPlaceholderMismatch;
-                return self.report_and_explain_type_error(trace, terr);
+                return self.report_and_explain_type_error(
+                    trace,
+                    self.tcx.param_env(generic_param_scope),
+                    terr,
+                );
             }
             _ => {
                 return self.report_concrete_failure(
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
index 549beaf..6014ed5 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
@@ -156,8 +156,6 @@
                             (leaf_trait_predicate, &obligation)
                         };
 
-                        let (main_trait_predicate, leaf_trait_predicate, predicate_constness) = self.get_effects_trait_pred_override(main_trait_predicate, leaf_trait_predicate, span);
-
                         let main_trait_ref = main_trait_predicate.to_poly_trait_ref();
                         let leaf_trait_ref = leaf_trait_predicate.to_poly_trait_ref();
 
@@ -228,7 +226,7 @@
                         let err_msg = self.get_standard_error_message(
                             main_trait_predicate,
                             message,
-                            predicate_constness,
+                            None,
                             append_const_msg,
                             post_message,
                         );
@@ -289,13 +287,6 @@
                             );
                         }
 
-                        if tcx.is_lang_item(leaf_trait_ref.def_id(), LangItem::Drop)
-                            && matches!(predicate_constness, Some(ty::BoundConstness::ConstIfConst | ty::BoundConstness::Const))
-                        {
-                            err.note("`~const Drop` was renamed to `~const Destruct`");
-                            err.note("See <https://github.com/rust-lang/rust/pull/94901> for more details");
-                        }
-
                         let explanation = get_explanation_based_on_obligation(
                             self.tcx,
                             &obligation,
@@ -541,6 +532,29 @@
                         err
                     }
 
+                    ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(predicate)) => {
+                        // FIXME(effects): We should recompute the predicate with `~const`
+                        // if it's `const`, and if it holds, explain that this bound only
+                        // *conditionally* holds. If that fails, we should also do selection
+                        // to drill this down to an impl or built-in source, so we can
+                        // point at it and explain that while the trait *is* implemented,
+                        // that implementation is not const.
+                        let err_msg = self.get_standard_error_message(
+                            bound_predicate.rebind(ty::TraitPredicate {
+                                trait_ref: predicate.trait_ref,
+                                polarity: ty::PredicatePolarity::Positive,
+                            }),
+                            None,
+                            Some(match predicate.host {
+                                ty::HostPolarity::Maybe => ty::BoundConstness::ConstIfConst,
+                                ty::HostPolarity::Const => ty::BoundConstness::Const,
+                            }),
+                            None,
+                            String::new(),
+                        );
+                        struct_span_code_err!(self.dcx(), span, E0277, "{}", err_msg)
+                    }
+
                     ty::PredicateKind::Subtype(predicate) => {
                         // Errors for Subtype predicates show up as
                         // `FulfillmentErrorCode::SubtypeError`,
@@ -1290,7 +1304,6 @@
                         (
                             Some((
                                 data.projection_term,
-                                false,
                                 self.resolve_vars_if_possible(normalized_term),
                                 data.term,
                             )),
@@ -1335,7 +1348,7 @@
                             derive_better_type_error(lhs, rhs)
                     {
                         (
-                            Some((lhs, true, self.resolve_vars_if_possible(expected_term), rhs)),
+                            Some((lhs, self.resolve_vars_if_possible(expected_term), rhs)),
                             better_type_err,
                         )
                     } else if let Some(rhs) = rhs.to_alias_term()
@@ -1343,7 +1356,7 @@
                             derive_better_type_error(rhs, lhs)
                     {
                         (
-                            Some((rhs, true, self.resolve_vars_if_possible(expected_term), lhs)),
+                            Some((rhs, self.resolve_vars_if_possible(expected_term), lhs)),
                             better_type_err,
                         )
                     } else {
@@ -1354,7 +1367,7 @@
             };
 
             let msg = values
-                .and_then(|(predicate, _, normalized_term, expected_term)| {
+                .and_then(|(predicate, normalized_term, expected_term)| {
                     self.maybe_detailed_projection_msg(predicate, normalized_term, expected_term)
                 })
                 .unwrap_or_else(|| {
@@ -1431,8 +1444,12 @@
                 &mut diag,
                 &obligation.cause,
                 secondary_span,
-                values.map(|(_, _, normalized_ty, expected_ty)| {
-                    infer::ValuePairs::Terms(ExpectedFound::new(true, expected_ty, normalized_ty))
+                values.map(|(_, normalized_ty, expected_ty)| {
+                    obligation.param_env.and(infer::ValuePairs::Terms(ExpectedFound::new(
+                        true,
+                        expected_ty,
+                        normalized_ty,
+                    )))
                 }),
                 err,
                 false,
@@ -1818,6 +1835,7 @@
                     if impl_trait_ref.references_error() {
                         return false;
                     }
+                    let self_ty = impl_trait_ref.self_ty().to_string();
                     err.highlighted_help(vec![
                         StringPart::normal(format!(
                             "the trait `{}` ",
@@ -1825,16 +1843,24 @@
                         )),
                         StringPart::highlighted("is"),
                         StringPart::normal(" implemented for `"),
-                        StringPart::highlighted(impl_trait_ref.self_ty().to_string()),
+                        if let [TypeError::Sorts(_)] = &terrs[..] {
+                            StringPart::normal(self_ty)
+                        } else {
+                            StringPart::highlighted(self_ty)
+                        },
                         StringPart::normal("`"),
                     ]);
 
                     if let [TypeError::Sorts(exp_found)] = &terrs[..] {
                         let exp_found = self.resolve_vars_if_possible(*exp_found);
-                        err.help(format!(
-                            "for that trait implementation, expected `{}`, found `{}`",
-                            exp_found.expected, exp_found.found
-                        ));
+                        err.highlighted_help(vec![
+                            StringPart::normal("for that trait implementation, "),
+                            StringPart::normal("expected `"),
+                            StringPart::highlighted(exp_found.expected.to_string()),
+                            StringPart::normal("`, found `"),
+                            StringPart::highlighted(exp_found.found.to_string()),
+                            StringPart::normal("`"),
+                        ]);
                     }
 
                     true
@@ -2143,6 +2169,7 @@
         // First, attempt to add note to this error with an async-await-specific
         // message, and fall back to regular note otherwise.
         if !self.maybe_note_obligation_cause_for_async_await(err, obligation) {
+            let mut long_ty_file = None;
             self.note_obligation_cause_code(
                 obligation.cause.body_id,
                 err,
@@ -2151,7 +2178,15 @@
                 obligation.cause.code(),
                 &mut vec![],
                 &mut Default::default(),
+                &mut long_ty_file,
             );
+            if let Some(file) = long_ty_file {
+                err.note(format!(
+                    "the full name for the type has been written to '{}'",
+                    file.display(),
+                ));
+                err.note("consider using `--verbose` to print the full type name to the console");
+            }
             self.suggest_unsized_bound_if_applicable(err, obligation);
             if let Some(span) = err.span.primary_span()
                 && let Some(mut diag) =
@@ -2371,52 +2406,6 @@
         })
     }
 
-    /// For effects predicates such as `<u32 as Add>::Effects: Compat<host>`, pretend that the
-    /// predicate that failed was `u32: Add`. Return the constness of such predicate to later
-    /// print as `u32: ~const Add`.
-    fn get_effects_trait_pred_override(
-        &self,
-        p: ty::PolyTraitPredicate<'tcx>,
-        leaf: ty::PolyTraitPredicate<'tcx>,
-        span: Span,
-    ) -> (ty::PolyTraitPredicate<'tcx>, ty::PolyTraitPredicate<'tcx>, Option<ty::BoundConstness>)
-    {
-        let trait_ref = p.to_poly_trait_ref();
-        if !self.tcx.is_lang_item(trait_ref.def_id(), LangItem::EffectsCompat) {
-            return (p, leaf, None);
-        }
-
-        let Some(ty::Alias(ty::AliasTyKind::Projection, projection)) =
-            trait_ref.self_ty().no_bound_vars().map(Ty::kind)
-        else {
-            return (p, leaf, None);
-        };
-
-        let constness = trait_ref.skip_binder().args.const_at(1);
-
-        let constness = if constness == self.tcx.consts.true_ || constness.is_ct_infer() {
-            None
-        } else if constness == self.tcx.consts.false_ {
-            Some(ty::BoundConstness::Const)
-        } else if matches!(constness.kind(), ty::ConstKind::Param(_)) {
-            Some(ty::BoundConstness::ConstIfConst)
-        } else {
-            self.dcx().span_bug(span, format!("Unknown constness argument: {constness:?}"));
-        };
-
-        let new_pred = p.map_bound(|mut trait_pred| {
-            trait_pred.trait_ref = projection.trait_ref(self.tcx);
-            trait_pred
-        });
-
-        let new_leaf = leaf.map_bound(|mut trait_pred| {
-            trait_pred.trait_ref = projection.trait_ref(self.tcx);
-            trait_pred
-        });
-
-        (new_pred, new_leaf, constness)
-    }
-
     fn add_tuple_trait_message(
         &self,
         obligation_cause_code: &ObligationCauseCode<'tcx>,
@@ -2654,6 +2643,7 @@
         };
         self.report_and_explain_type_error(
             TypeTrace::trait_refs(&cause, true, expected_trait_ref, found_trait_ref),
+            obligation.param_env,
             terr,
         )
     }
@@ -2744,6 +2734,7 @@
         {
             return Ok(self.report_and_explain_type_error(
                 TypeTrace::trait_refs(&obligation.cause, true, expected_trait_ref, found_trait_ref),
+                obligation.param_env,
                 ty::error::TypeError::Mismatch,
             ));
         }
@@ -3026,7 +3017,7 @@
         obligation: &PredicateObligation<'tcx>,
         span: Span,
     ) -> Result<Diag<'a>, ErrorGuaranteed> {
-        if !self.tcx.features().generic_const_exprs {
+        if !self.tcx.features().generic_const_exprs() {
             let guar = self
                 .dcx()
                 .struct_span_err(span, "constant expression depends on a generic parameter")
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs
index ba57909..b108a93 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs
@@ -287,6 +287,7 @@
             FulfillmentErrorCode::Subtype(ref expected_found, ref err) => self
                 .report_mismatched_types(
                     &error.obligation.cause,
+                    error.obligation.param_env,
                     expected_found.expected,
                     expected_found.found,
                     *err,
@@ -295,6 +296,7 @@
             FulfillmentErrorCode::ConstEquate(ref expected_found, ref err) => {
                 let mut diag = self.report_mismatched_consts(
                     &error.obligation.cause,
+                    error.obligation.param_env,
                     expected_found.expected,
                     expected_found.found,
                     *err,
@@ -303,6 +305,7 @@
                 if let ObligationCauseCode::WhereClause(..)
                 | ObligationCauseCode::WhereClauseInExpr(..) = code
                 {
+                    let mut long_ty_file = None;
                     self.note_obligation_cause_code(
                         error.obligation.cause.body_id,
                         &mut diag,
@@ -311,7 +314,17 @@
                         code,
                         &mut vec![],
                         &mut Default::default(),
+                        &mut long_ty_file,
                     );
+                    if let Some(file) = long_ty_file {
+                        diag.note(format!(
+                            "the full name for the type has been written to '{}'",
+                            file.display(),
+                        ));
+                        diag.note(
+                            "consider using `--verbose` to print the full type name to the console",
+                        );
+                    }
                 }
                 diag.emit()
             }
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs
index f4c5733..c47c216 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs
@@ -144,6 +144,7 @@
             obligation.cause.span,
             suggest_increasing_limit,
             |err| {
+                let mut long_ty_file = None;
                 self.note_obligation_cause_code(
                     obligation.cause.body_id,
                     err,
@@ -152,7 +153,17 @@
                     obligation.cause.code(),
                     &mut vec![],
                     &mut Default::default(),
+                    &mut long_ty_file,
                 );
+                if let Some(file) = long_ty_file {
+                    err.note(format!(
+                        "the full name for the type has been written to '{}'",
+                        file.display(),
+                    ));
+                    err.note(
+                        "consider using `--verbose` to print the full type name to the console",
+                    );
+                }
             },
         );
     }
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
index 677905a..a7d1f1b 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
@@ -3,6 +3,7 @@
 use std::assert_matches::debug_assert_matches;
 use std::borrow::Cow;
 use std::iter;
+use std::path::PathBuf;
 
 use itertools::{EitherOrBoth, Itertools};
 use rustc_data_structures::fx::FxHashSet;
@@ -2703,6 +2704,7 @@
         // Add a note for the item obligation that remains - normally a note pointing to the
         // bound that introduced the obligation (e.g. `T: Send`).
         debug!(?next_code);
+        let mut long_ty_file = None;
         self.note_obligation_cause_code(
             obligation.cause.body_id,
             err,
@@ -2711,6 +2713,7 @@
             next_code.unwrap(),
             &mut Vec::new(),
             &mut Default::default(),
+            &mut long_ty_file,
         );
     }
 
@@ -2723,11 +2726,10 @@
         cause_code: &ObligationCauseCode<'tcx>,
         obligated_types: &mut Vec<Ty<'tcx>>,
         seen_requirements: &mut FxHashSet<DefId>,
+        long_ty_file: &mut Option<PathBuf>,
     ) where
         T: Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>>,
     {
-        let mut long_ty_file = None;
-
         let tcx = self.tcx;
         let predicate = predicate.upcast(tcx);
         let suggest_remove_deref = |err: &mut Diag<'_, G>, expr: &hir::Expr<'_>| {
@@ -2957,9 +2959,9 @@
             }
             ObligationCauseCode::Coercion { source, target } => {
                 let source =
-                    tcx.short_ty_string(self.resolve_vars_if_possible(source), &mut long_ty_file);
+                    tcx.short_ty_string(self.resolve_vars_if_possible(source), long_ty_file);
                 let target =
-                    tcx.short_ty_string(self.resolve_vars_if_possible(target), &mut long_ty_file);
+                    tcx.short_ty_string(self.resolve_vars_if_possible(target), long_ty_file);
                 err.note(with_forced_trimmed_paths!(format!(
                     "required for the cast from `{source}` to `{target}`",
                 )));
@@ -3044,7 +3046,7 @@
                 if local {
                     err.note("all local variables must have a statically known size");
                 }
-                if !tcx.features().unsized_locals {
+                if !tcx.features().unsized_locals() {
                     err.help("unsized locals are gated as an unstable feature");
                 }
             }
@@ -3125,7 +3127,7 @@
                     err.note("all function arguments must have a statically known size");
                 }
                 if tcx.sess.opts.unstable_features.is_nightly_build()
-                    && !tcx.features().unsized_fn_params
+                    && !tcx.features().unsized_fn_params()
                 {
                     err.help("unsized fn params are gated as an unstable feature");
                 }
@@ -3249,7 +3251,7 @@
                 };
 
                 if !is_upvar_tys_infer_tuple {
-                    let ty_str = tcx.short_ty_string(ty, &mut long_ty_file);
+                    let ty_str = tcx.short_ty_string(ty, long_ty_file);
                     let msg = format!("required because it appears within the type `{ty_str}`");
                     match ty.kind() {
                         ty::Adt(def, _) => match tcx.opt_item_ident(def.did()) {
@@ -3327,6 +3329,7 @@
                             &data.parent_code,
                             obligated_types,
                             seen_requirements,
+                            long_ty_file,
                         )
                     });
                 } else {
@@ -3339,6 +3342,7 @@
                             cause_code.peel_derives(),
                             obligated_types,
                             seen_requirements,
+                            long_ty_file,
                         )
                     });
                 }
@@ -3347,8 +3351,8 @@
                 let mut parent_trait_pred =
                     self.resolve_vars_if_possible(data.derived.parent_trait_pred);
                 let parent_def_id = parent_trait_pred.def_id();
-                let self_ty_str = tcx
-                    .short_ty_string(parent_trait_pred.skip_binder().self_ty(), &mut long_ty_file);
+                let self_ty_str =
+                    tcx.short_ty_string(parent_trait_pred.skip_binder().self_ty(), long_ty_file);
                 let trait_name = parent_trait_pred.print_modifiers_and_trait_path().to_string();
                 let msg = format!("required for `{self_ty_str}` to implement `{trait_name}`");
                 let mut is_auto_trait = false;
@@ -3444,10 +3448,8 @@
                         count,
                         pluralize!(count)
                     ));
-                    let self_ty = tcx.short_ty_string(
-                        parent_trait_pred.skip_binder().self_ty(),
-                        &mut long_ty_file,
-                    );
+                    let self_ty = tcx
+                        .short_ty_string(parent_trait_pred.skip_binder().self_ty(), long_ty_file);
                     err.note(format!(
                         "required for `{self_ty}` to implement `{}`",
                         parent_trait_pred.print_modifiers_and_trait_path()
@@ -3463,6 +3465,7 @@
                         &data.parent_code,
                         obligated_types,
                         seen_requirements,
+                        long_ty_file,
                     )
                 });
             }
@@ -3479,6 +3482,7 @@
                         &data.parent_code,
                         obligated_types,
                         seen_requirements,
+                        long_ty_file,
                     )
                 });
             }
@@ -3493,6 +3497,7 @@
                         nested,
                         obligated_types,
                         seen_requirements,
+                        long_ty_file,
                     )
                 });
                 let mut multispan = MultiSpan::from(span);
@@ -3523,6 +3528,7 @@
                         parent_code,
                         obligated_types,
                         seen_requirements,
+                        long_ty_file,
                     )
                 });
             }
@@ -3562,7 +3568,7 @@
             }
             ObligationCauseCode::OpaqueReturnType(expr_info) => {
                 if let Some((expr_ty, hir_id)) = expr_info {
-                    let expr_ty = self.tcx.short_ty_string(expr_ty, &mut long_ty_file);
+                    let expr_ty = self.tcx.short_ty_string(expr_ty, long_ty_file);
                     let expr = self.infcx.tcx.hir().expect_expr(hir_id);
                     err.span_label(
                         expr.span,
@@ -3574,14 +3580,6 @@
                 }
             }
         }
-
-        if let Some(file) = long_ty_file {
-            err.note(format!(
-                "the full name for the type has been written to '{}'",
-                file.display(),
-            ));
-            err.note("consider using `--verbose` to print the full type name to the console");
-        }
     }
 
     #[instrument(
@@ -3594,52 +3592,64 @@
         trait_pred: ty::PolyTraitPredicate<'tcx>,
         span: Span,
     ) {
-        if let Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)) =
-            self.tcx.coroutine_kind(obligation.cause.body_id)
+        let future_trait = self.tcx.require_lang_item(LangItem::Future, None);
+
+        let self_ty = self.resolve_vars_if_possible(trait_pred.self_ty());
+        let impls_future = self.type_implements_trait(
+            future_trait,
+            [self.tcx.instantiate_bound_regions_with_erased(self_ty)],
+            obligation.param_env,
+        );
+        if !impls_future.must_apply_modulo_regions() {
+            return;
+        }
+
+        let item_def_id = self.tcx.associated_item_def_ids(future_trait)[0];
+        // `<T as Future>::Output`
+        let projection_ty = trait_pred.map_bound(|trait_pred| {
+            Ty::new_projection(
+                self.tcx,
+                item_def_id,
+                // Future::Output has no args
+                [trait_pred.self_ty()],
+            )
+        });
+        let InferOk { value: projection_ty, .. } =
+            self.at(&obligation.cause, obligation.param_env).normalize(projection_ty);
+
+        debug!(
+            normalized_projection_type = ?self.resolve_vars_if_possible(projection_ty)
+        );
+        let try_obligation = self.mk_trait_obligation_with_new_self_ty(
+            obligation.param_env,
+            trait_pred.map_bound(|trait_pred| (trait_pred, projection_ty.skip_binder())),
+        );
+        debug!(try_trait_obligation = ?try_obligation);
+        if self.predicate_may_hold(&try_obligation)
+            && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
+            && snippet.ends_with('?')
         {
-            let future_trait = self.tcx.require_lang_item(LangItem::Future, None);
-
-            let self_ty = self.resolve_vars_if_possible(trait_pred.self_ty());
-            let impls_future = self.type_implements_trait(
-                future_trait,
-                [self.tcx.instantiate_bound_regions_with_erased(self_ty)],
-                obligation.param_env,
-            );
-            if !impls_future.must_apply_modulo_regions() {
-                return;
-            }
-
-            let item_def_id = self.tcx.associated_item_def_ids(future_trait)[0];
-            // `<T as Future>::Output`
-            let projection_ty = trait_pred.map_bound(|trait_pred| {
-                Ty::new_projection(
-                    self.tcx,
-                    item_def_id,
-                    // Future::Output has no args
-                    [trait_pred.self_ty()],
-                )
-            });
-            let InferOk { value: projection_ty, .. } =
-                self.at(&obligation.cause, obligation.param_env).normalize(projection_ty);
-
-            debug!(
-                normalized_projection_type = ?self.resolve_vars_if_possible(projection_ty)
-            );
-            let try_obligation = self.mk_trait_obligation_with_new_self_ty(
-                obligation.param_env,
-                trait_pred.map_bound(|trait_pred| (trait_pred, projection_ty.skip_binder())),
-            );
-            debug!(try_trait_obligation = ?try_obligation);
-            if self.predicate_may_hold(&try_obligation)
-                && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
-                && snippet.ends_with('?')
-            {
-                err.span_suggestion_verbose(
-                    span.with_hi(span.hi() - BytePos(1)).shrink_to_hi(),
-                    "consider `await`ing on the `Future`",
-                    ".await",
-                    Applicability::MaybeIncorrect,
-                );
+            match self.tcx.coroutine_kind(obligation.cause.body_id) {
+                Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)) => {
+                    err.span_suggestion_verbose(
+                        span.with_hi(span.hi() - BytePos(1)).shrink_to_hi(),
+                        "consider `await`ing on the `Future`",
+                        ".await",
+                        Applicability::MaybeIncorrect,
+                    );
+                }
+                _ => {
+                    let mut span: MultiSpan = span.with_lo(span.hi() - BytePos(1)).into();
+                    span.push_span_label(
+                        self.tcx.def_span(obligation.cause.body_id),
+                        "this is not `async`",
+                    );
+                    err.span_note(
+                        span,
+                        "this implements `Future` and its output type supports \
+                        `?`, but the future cannot be awaited in a synchronous function",
+                    );
+                }
             }
         }
     }
@@ -4498,7 +4508,7 @@
         trait_ref: ty::PolyTraitRef<'tcx>,
     ) {
         // Don't suggest if RTN is active -- we should prefer a where-clause bound instead.
-        if self.tcx.features().return_type_notation {
+        if self.tcx.features().return_type_notation() {
             return;
         }
 
diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
index 4975a9c..e735020 100644
--- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
+++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
@@ -344,7 +344,7 @@
         };
 
         let mut nested_goals = vec![];
-        self.candidates_recur(&mut candidates, &mut nested_goals, &last_eval_step.evaluation);
+        self.candidates_recur(&mut candidates, &mut nested_goals, &last_eval_step);
 
         candidates
     }
diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
index 12aeee0..934fe9e 100644
--- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs
+++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
@@ -806,7 +806,8 @@
                 | ty::PredicateKind::Subtype(..)
                 // FIXME(generic_const_exprs): you can absolutely add this as a where clauses
                 | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..))
-                | ty::PredicateKind::Coerce(..) => {}
+                | ty::PredicateKind::Coerce(..)
+                | ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(..)) => {}
                 ty::PredicateKind::Ambiguous => return false,
             };
         }
diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
index c258832..1be3c96 100644
--- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -40,7 +40,7 @@
         ty::ConstKind::Infer(_) => return Err(NotConstEvaluatable::MentionsInfer),
     };
 
-    if tcx.features().generic_const_exprs {
+    if tcx.features().generic_const_exprs() {
         let ct = tcx.expand_abstract_consts(unexpanded_ct);
 
         let is_anon_ct = if let ty::ConstKind::Unevaluated(uv) = ct.kind() {
diff --git a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
index 364a13b..a068f25 100644
--- a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
+++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
@@ -245,6 +245,7 @@
         | ty::ClauseKind::RegionOutlives(..)
         // FIXME(generic_const_exprs): this can mention `Self`
         | ty::ClauseKind::ConstEvaluatable(..)
+        | ty::ClauseKind::HostEffect(..)
          => None,
     }
 }
@@ -254,7 +255,7 @@
     trait_def_id: DefId,
 ) -> SmallVec<[Span; 1]> {
     // If non_lifetime_binders is disabled, then exit early
-    if !tcx.features().non_lifetime_binders {
+    if !tcx.features().non_lifetime_binders() {
         return SmallVec::new();
     }
     tcx.explicit_super_predicates_of(trait_def_id)
@@ -284,7 +285,8 @@
         | ty::ClauseKind::Projection(_)
         | ty::ClauseKind::ConstArgHasType(_, _)
         | ty::ClauseKind::WellFormed(_)
-        | ty::ClauseKind::ConstEvaluatable(_) => false,
+        | ty::ClauseKind::ConstEvaluatable(_)
+        | ty::ClauseKind::HostEffect(..) => false,
     })
 }
 
@@ -327,7 +329,7 @@
             .collect(),
         // Associated types can only be dyn-compatible if they have `Self: Sized` bounds.
         ty::AssocKind::Type => {
-            if !tcx.features().generic_associated_types_extended
+            if !tcx.features().generic_associated_types_extended()
                 && !tcx.generics_of(item.def_id).is_own_empty()
                 && !item.is_impl_trait_in_trait()
             {
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index e56f186..1754418 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -372,7 +372,11 @@
                 | ty::PredicateKind::Subtype(_)
                 | ty::PredicateKind::Coerce(_)
                 | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..))
-                | ty::PredicateKind::ConstEquate(..) => {
+                | ty::PredicateKind::ConstEquate(..)
+                // FIXME(effects): We may need to do this using the higher-ranked
+                // pred instead of just instantiating it with placeholders b/c of
+                // higher-ranked implied bound issues in the old solver.
+                | ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(..)) => {
                     let pred = ty::Binder::dummy(infcx.enter_forall_and_leak_universe(binder));
                     let mut obligations = PredicateObligations::with_capacity(1);
                     obligations.push(obligation.with(infcx.tcx, pred));
@@ -398,6 +402,10 @@
                     )
                 }
 
+                ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(..)) => {
+                    ProcessResult::Changed(Default::default())
+                }
+
                 ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(data)) => {
                     if infcx.considering_regions {
                         infcx.region_outlives_predicate(&obligation.cause, Binder::dummy(data));
@@ -450,7 +458,6 @@
                         ty::ConstKind::Infer(var) => {
                             let var = match var {
                                 ty::InferConst::Var(vid) => TyOrConstInferVar::Const(vid),
-                                ty::InferConst::EffectVar(vid) => TyOrConstInferVar::Effect(vid),
                                 ty::InferConst::Fresh(_) => {
                                     bug!("encountered fresh const in fulfill")
                                 }
@@ -598,7 +605,7 @@
                 ty::PredicateKind::ConstEquate(c1, c2) => {
                     let tcx = self.selcx.tcx();
                     assert!(
-                        tcx.features().generic_const_exprs,
+                        tcx.features().generic_const_exprs(),
                         "`ConstEquate` without a feature gate: {c1:?} {c2:?}",
                     );
                     // FIXME: we probably should only try to unify abstract constants
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index cffb9b5..cdf2488 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -346,7 +346,7 @@
     let mut predicates: Vec<_> = util::elaborate(
         tcx,
         unnormalized_env.caller_bounds().into_iter().map(|predicate| {
-            if tcx.features().generic_const_exprs {
+            if tcx.features().generic_const_exprs() {
                 return predicate;
             }
 
diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs
index d246d37..12e00ec 100644
--- a/compiler/rustc_trait_selection/src/traits/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/normalize.rs
@@ -402,7 +402,7 @@
     #[instrument(skip(self), level = "debug")]
     fn fold_const(&mut self, constant: ty::Const<'tcx>) -> ty::Const<'tcx> {
         let tcx = self.selcx.tcx();
-        if tcx.features().generic_const_exprs
+        if tcx.features().generic_const_exprs()
             || !needs_normalization(&constant, self.param_env.reveal())
         {
             constant
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index cc634b6..0803dd7 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -189,7 +189,7 @@
             ProjectAndUnifyResult::MismatchedProjectionTypes(e) => Err(e),
             ProjectAndUnifyResult::Holds(obligations)
                 if old_universe != new_universe
-                    && selcx.tcx().features().generic_associated_types_extended =>
+                    && selcx.tcx().features().generic_associated_types_extended() =>
             {
                 // If the `generic_associated_types_extended` feature is active, then we ignore any
                 // obligations references lifetimes from any universe greater than or equal to the
@@ -1180,7 +1180,7 @@
                                             selcx.tcx(),
                                             selcx.tcx().require_lang_item(
                                                 LangItem::Sized,
-                                                Some(obligation.cause.span()),
+                                                Some(obligation.cause.span),
                                             ),
                                             [self_ty],
                                         ),
@@ -1600,7 +1600,7 @@
                 // exist. Instead, `Pointee<Metadata = ()>` should be a supertrait of `Sized`.
                 let sized_predicate = ty::TraitRef::new(
                     tcx,
-                    tcx.require_lang_item(LangItem::Sized, Some(obligation.cause.span())),
+                    tcx.require_lang_item(LangItem::Sized, Some(obligation.cause.span)),
                     [self_ty],
                 );
                 obligations.push(obligation.with(tcx, sized_predicate));
diff --git a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs
index 7601729..bb44645 100644
--- a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs
@@ -90,7 +90,7 @@
             assert!(!self.intercrate);
             let c_pred =
                 self.canonicalize_query(param_env.and(obligation.predicate), &mut _orig_values);
-            self.tcx.at(obligation.cause.span()).evaluate_obligation(c_pred)
+            self.tcx.at(obligation.cause.span).evaluate_obligation(c_pred)
         }
     }
 
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs
index dfd0cab..c6e41e5 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs
@@ -96,6 +96,7 @@
                 // FIXME(const_generics): Make sure that `<'a, 'b, const N: &'a &'b u32>` is sound
                 // if we ever support that
                 ty::PredicateKind::Clause(ty::ClauseKind::Trait(..))
+                | ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(..))
                 | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..))
                 | ty::PredicateKind::Subtype(..)
                 | ty::PredicateKind::Coerce(..)
@@ -200,6 +201,7 @@
                 // FIXME(const_generics): Make sure that `<'a, 'b, const N: &'a &'b u32>` is sound
                 // if we ever support that
                 ty::PredicateKind::Clause(ty::ClauseKind::Trait(..))
+                | ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(..))
                 | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..))
                 | ty::PredicateKind::Subtype(..)
                 | ty::PredicateKind::Coerce(..)
diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
index ac38c9e..e027586 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -244,7 +244,6 @@
             .param_env
             .caller_bounds()
             .iter()
-            .filter(|p| !p.references_error())
             .filter_map(|p| p.as_trait_clause())
             // Micro-optimization: filter out predicates relating to different traits.
             .filter(|p| p.def_id() == stack.obligation.predicate.def_id())
@@ -394,7 +393,7 @@
         let self_ty = obligation.self_ty().skip_binder();
         match *self_ty.kind() {
             ty::Closure(def_id, _) => {
-                let is_const = self.tcx().is_const_fn_raw(def_id);
+                let is_const = self.tcx().is_const_fn(def_id);
                 debug!(?kind, ?obligation, "assemble_unboxed_candidates");
                 match self.infcx.closure_kind(self_ty) {
                     Some(closure_kind) => {
@@ -414,7 +413,7 @@
             }
             ty::CoroutineClosure(def_id, args) => {
                 let args = args.as_coroutine_closure();
-                let is_const = self.tcx().is_const_fn_raw(def_id);
+                let is_const = self.tcx().is_const_fn(def_id);
                 if let Some(closure_kind) = self.infcx.closure_kind(self_ty)
                     // Ambiguity if upvars haven't been constrained yet
                     && !args.tupled_upvars_ty().is_ty_var()
@@ -547,7 +546,7 @@
                 }
             }
             // Provide an impl for suitable functions, rejecting `#[target_feature]` functions (RFC 2396).
-            ty::FnDef(def_id, _args) => {
+            ty::FnDef(def_id, _) => {
                 let tcx = self.tcx();
                 if tcx.fn_sig(def_id).skip_binder().is_fn_trait_compatible()
                     && tcx.codegen_fn_attrs(def_id).target_features.is_empty()
@@ -876,7 +875,7 @@
                         }
 
                         if let Some(principal) = data.principal() {
-                            if !self.infcx.tcx.features().dyn_compatible_for_dispatch {
+                            if !self.infcx.tcx.features().dyn_compatible_for_dispatch() {
                                 principal.with_self_ty(self.tcx(), self_ty)
                             } else if self.tcx().is_dyn_compatible(principal.def_id()) {
                                 principal.with_self_ty(self.tcx(), self_ty)
@@ -936,7 +935,7 @@
         }
 
         let tcx = self.tcx();
-        if tcx.features().trait_upcasting {
+        if tcx.features().trait_upcasting() {
             return None;
         }
 
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index 9a49fd7..e7d3004 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -402,7 +402,7 @@
 
         let mut assume = predicate.trait_ref.args.const_at(2);
         // FIXME(min_generic_const_exprs): We should shallowly normalize this.
-        if self.tcx().features().generic_const_exprs {
+        if self.tcx().features().generic_const_exprs() {
             assume = assume.normalize_internal(self.tcx(), obligation.param_env);
         }
         let Some(assume) =
@@ -626,7 +626,7 @@
         for assoc_type in assoc_types {
             let defs: &ty::Generics = tcx.generics_of(assoc_type);
 
-            if !defs.own_params.is_empty() && !tcx.features().generic_associated_types_extended {
+            if !defs.own_params.is_empty() && !tcx.features().generic_associated_types_extended() {
                 tcx.dcx().span_delayed_bug(
                     obligation.cause.span,
                     "GATs in trait object shouldn't have been considered",
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 4757430..ec4114f 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -645,6 +645,13 @@
                     self.evaluate_trait_predicate_recursively(previous_stack, obligation)
                 }
 
+                ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(..)) => {
+                    // FIXME(effects): It should be relatively straightforward to implement
+                    // old trait solver support for `HostEffect` bounds; or at least basic
+                    // support for them.
+                    todo!()
+                }
+
                 ty::PredicateKind::Subtype(p) => {
                     let p = bound_predicate.rebind(p);
                     // Does this code ever run?
@@ -865,7 +872,7 @@
                 ty::PredicateKind::ConstEquate(c1, c2) => {
                     let tcx = self.tcx();
                     assert!(
-                        tcx.features().generic_const_exprs,
+                        tcx.features().generic_const_exprs(),
                         "`ConstEquate` without a feature gate: {c1:?} {c2:?}",
                     );
 
@@ -1821,8 +1828,7 @@
             |cand: ty::PolyTraitPredicate<'tcx>| cand.is_global() && !cand.has_bound_vars();
 
         // (*) Prefer `BuiltinCandidate { has_nested: false }`, `PointeeCandidate`,
-        // `DiscriminantKindCandidate`, `ConstDestructCandidate`
-        // to anything else.
+        // or `DiscriminantKindCandidate` to anything else.
         //
         // This is a fix for #53123 and prevents winnowing from accidentally extending the
         // lifetime of a variable.
@@ -2195,7 +2201,7 @@
                 match self.tcx().coroutine_movability(coroutine_def_id) {
                     hir::Movability::Static => None,
                     hir::Movability::Movable => {
-                        if self.tcx().features().coroutine_clone {
+                        if self.tcx().features().coroutine_clone() {
                             let resolved_upvars =
                                 self.infcx.shallow_resolve(args.as_coroutine().tupled_upvars_ty());
                             let resolved_witness =
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
index b82a343..0e45f7a 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
@@ -136,7 +136,7 @@
 }
 
 pub(super) fn specialization_enabled_in(tcx: TyCtxt<'_>, _: LocalCrate) -> bool {
-    tcx.features().specialization || tcx.features().min_specialization
+    tcx.features().specialization() || tcx.features().min_specialization()
 }
 
 /// Is `impl1` a specialization of `impl2`?
diff --git a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs
index f8d98eb..23b5f62 100644
--- a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs
@@ -82,7 +82,7 @@
             }
 
             Ok(self.infcx.resolve_vars_if_possible(new_infer_ct))
-        } else if self.infcx.tcx.features().generic_const_exprs {
+        } else if self.infcx.tcx.features().generic_const_exprs() {
             Ok(ct.normalize_internal(self.infcx.tcx, self.param_env))
         } else {
             Ok(self.normalize(ct).into_value_registering_obligations(self.infcx, fulfill_cx))
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index 07e68e5..437343b 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -170,6 +170,10 @@
         ty::ClauseKind::Trait(t) => {
             wf.compute_trait_pred(t, Elaborate::None);
         }
+        ty::ClauseKind::HostEffect(..) => {
+            // Technically the well-formedness of this predicate is implied by
+            // the corresponding trait predicate it should've been generated beside.
+        }
         ty::ClauseKind::RegionOutlives(..) => {}
         ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty, _reg)) => {
             wf.compute(ty.into());
@@ -836,7 +840,7 @@
                 // obligations that don't refer to Self and
                 // checking those
 
-                let defer_to_coercion = tcx.features().dyn_compatible_for_dispatch;
+                let defer_to_coercion = tcx.features().dyn_compatible_for_dispatch();
 
                 if !defer_to_coercion {
                     if let Some(principal) = data.principal_def_id() {
@@ -1021,6 +1025,7 @@
                     }
                 }
                 ty::ClauseKind::Trait(_)
+                | ty::ClauseKind::HostEffect(..)
                 | ty::ClauseKind::RegionOutlives(_)
                 | ty::ClauseKind::Projection(_)
                 | ty::ClauseKind::ConstArgHasType(_, _)
diff --git a/compiler/rustc_traits/src/normalize_erasing_regions.rs b/compiler/rustc_traits/src/normalize_erasing_regions.rs
index f01a12b..3e2794f 100644
--- a/compiler/rustc_traits/src/normalize_erasing_regions.rs
+++ b/compiler/rustc_traits/src/normalize_erasing_regions.rs
@@ -55,6 +55,7 @@
         | ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(..)) => false,
         ty::PredicateKind::Clause(ty::ClauseKind::Trait(..))
         | ty::PredicateKind::Clause(ty::ClauseKind::Projection(..))
+        | ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(..))
         | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..))
         | ty::PredicateKind::NormalizesTo(..)
         | ty::PredicateKind::AliasRelate(..)
diff --git a/compiler/rustc_transmute/Cargo.toml b/compiler/rustc_transmute/Cargo.toml
index 4732e96..6a98be1 100644
--- a/compiler/rustc_transmute/Cargo.toml
+++ b/compiler/rustc_transmute/Cargo.toml
@@ -5,6 +5,7 @@
 
 [dependencies]
 # tidy-alphabetical-start
+rustc_abi = { path = "../rustc_abi", optional = true }
 rustc_ast_ir = { path = "../rustc_ast_ir", optional = true }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_hir = { path = "../rustc_hir", optional = true }
@@ -12,19 +13,18 @@
 rustc_macros = { path = "../rustc_macros", optional = true }
 rustc_middle = { path = "../rustc_middle", optional = true }
 rustc_span = { path = "../rustc_span", optional = true }
-rustc_target = { path = "../rustc_target", optional = true }
 tracing = "0.1"
 # tidy-alphabetical-end
 
 [features]
 rustc = [
+    "dep:rustc_abi",
+    "dep:rustc_ast_ir",
     "dep:rustc_hir",
     "dep:rustc_infer",
     "dep:rustc_macros",
     "dep:rustc_middle",
     "dep:rustc_span",
-    "dep:rustc_target",
-    "dep:rustc_ast_ir",
 ]
 
 [dev-dependencies]
diff --git a/compiler/rustc_transmute/src/layout/mod.rs b/compiler/rustc_transmute/src/layout/mod.rs
index a5c47c4..c4c01a8 100644
--- a/compiler/rustc_transmute/src/layout/mod.rs
+++ b/compiler/rustc_transmute/src/layout/mod.rs
@@ -62,10 +62,10 @@
 pub mod rustc {
     use std::fmt::{self, Write};
 
+    use rustc_abi::Layout;
     use rustc_middle::mir::Mutability;
     use rustc_middle::ty::layout::{HasTyCtxt, LayoutCx, LayoutError};
     use rustc_middle::ty::{self, Ty};
-    use rustc_target::abi::Layout;
 
     /// A reference in the layout.
     #[derive(Debug, Hash, Eq, PartialEq, Clone, Copy)]
diff --git a/compiler/rustc_transmute/src/layout/tree.rs b/compiler/rustc_transmute/src/layout/tree.rs
index 17eddbf..94ca4c1 100644
--- a/compiler/rustc_transmute/src/layout/tree.rs
+++ b/compiler/rustc_transmute/src/layout/tree.rs
@@ -171,12 +171,12 @@
 
 #[cfg(feature = "rustc")]
 pub(crate) mod rustc {
+    use rustc_abi::{
+        FieldIdx, FieldsShape, Layout, Size, TagEncoding, TyAndLayout, VariantIdx, Variants,
+    };
     use rustc_middle::ty::layout::{HasTyCtxt, LayoutCx, LayoutError};
     use rustc_middle::ty::{self, AdtDef, AdtKind, List, ScalarInt, Ty, TyCtxt, TypeVisitableExt};
     use rustc_span::ErrorGuaranteed;
-    use rustc_target::abi::{
-        FieldIdx, FieldsShape, Layout, Size, TagEncoding, TyAndLayout, VariantIdx, Variants,
-    };
 
     use super::Tree;
     use crate::layout::rustc::{Def, Ref, layout_of};
@@ -206,7 +206,7 @@
 
     impl<'tcx> Tree<Def<'tcx>, Ref<'tcx>> {
         pub(crate) fn from_ty(ty: Ty<'tcx>, cx: LayoutCx<'tcx>) -> Result<Self, Err> {
-            use rustc_target::abi::HasDataLayout;
+            use rustc_abi::HasDataLayout;
             let layout = layout_of(cx, ty)?;
 
             if let Err(e) = ty.error_reported() {
@@ -446,7 +446,7 @@
 
         /// Constructs a `Tree` representing the value of a enum tag.
         fn from_tag(tag: ScalarInt, tcx: TyCtxt<'tcx>) -> Self {
-            use rustc_target::abi::Endian;
+            use rustc_abi::Endian;
             let size = tag.size();
             let bits = tag.to_bits(size);
             let bytes: [u8; 16];
diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs
index 1369120..48149a0 100644
--- a/compiler/rustc_ty_utils/src/abi.rs
+++ b/compiler/rustc_ty_utils/src/abi.rs
@@ -1,8 +1,7 @@
 use std::iter;
 
-use rustc_abi::Float::*;
-use rustc_abi::Primitive::{Float, Pointer};
-use rustc_abi::{Abi, AddressSpace, PointerKind, Scalar, Size};
+use rustc_abi::Primitive::Pointer;
+use rustc_abi::{Abi, PointerKind, Scalar, Size};
 use rustc_hir as hir;
 use rustc_hir::lang_items::LangItem;
 use rustc_middle::bug;
@@ -14,8 +13,7 @@
 use rustc_session::config::OptLevel;
 use rustc_span::def_id::DefId;
 use rustc_target::abi::call::{
-    ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, Conv, FnAbi, PassMode, Reg, RegKind,
-    RiscvInterruptKind,
+    ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, Conv, FnAbi, PassMode, RiscvInterruptKind,
 };
 use rustc_target::spec::abi::Abi as SpecAbi;
 use tracing::debug;
@@ -679,6 +677,8 @@
     let tcx = cx.tcx();
 
     if abi == SpecAbi::Rust || abi == SpecAbi::RustCall || abi == SpecAbi::RustIntrinsic {
+        fn_abi.adjust_for_rust_abi(cx, abi);
+
         // Look up the deduced parameter attributes for this function, if we have its def ID and
         // we're optimizing in non-incremental mode. We'll tag its parameters with those attributes
         // as appropriate.
@@ -689,131 +689,9 @@
                 &[]
             };
 
-        let fixup = |arg: &mut ArgAbi<'tcx, Ty<'tcx>>, arg_idx: Option<usize>| {
+        for (arg_idx, arg) in fn_abi.args.iter_mut().enumerate() {
             if arg.is_ignore() {
-                return;
-            }
-
-            // Avoid returning floats in x87 registers on x86 as loading and storing from x87
-            // registers will quiet signalling NaNs.
-            if tcx.sess.target.arch == "x86"
-                && arg_idx.is_none()
-                // Intrinsics themselves are not actual "real" functions, so theres no need to
-                // change their ABIs.
-                && abi != SpecAbi::RustIntrinsic
-            {
-                match arg.layout.abi {
-                    // Handle similar to the way arguments with an `Abi::Aggregate` abi are handled
-                    // below, by returning arguments up to the size of a pointer (32 bits on x86)
-                    // cast to an appropriately sized integer.
-                    Abi::Scalar(s) if s.primitive() == Float(F32) => {
-                        // Same size as a pointer, return in a register.
-                        arg.cast_to(Reg::i32());
-                        return;
-                    }
-                    Abi::Scalar(s) if s.primitive() == Float(F64) => {
-                        // Larger than a pointer, return indirectly.
-                        arg.make_indirect();
-                        return;
-                    }
-                    Abi::ScalarPair(s1, s2)
-                        if matches!(s1.primitive(), Float(F32 | F64))
-                            || matches!(s2.primitive(), Float(F32 | F64)) =>
-                    {
-                        // Larger than a pointer, return indirectly.
-                        arg.make_indirect();
-                        return;
-                    }
-                    _ => {}
-                };
-            }
-
-            if arg_idx.is_none() && arg.layout.size > Pointer(AddressSpace::DATA).size(cx) * 2 {
-                // Return values larger than 2 registers using a return area
-                // pointer. LLVM and Cranelift disagree about how to return
-                // values that don't fit in the registers designated for return
-                // values. LLVM will force the entire return value to be passed
-                // by return area pointer, while Cranelift will look at each IR level
-                // return value independently and decide to pass it in a
-                // register or not, which would result in the return value
-                // being passed partially in registers and partially through a
-                // return area pointer.
-                //
-                // While Cranelift may need to be fixed as the LLVM behavior is
-                // generally more correct with respect to the surface language,
-                // forcing this behavior in rustc itself makes it easier for
-                // other backends to conform to the Rust ABI and for the C ABI
-                // rustc already handles this behavior anyway.
-                //
-                // In addition LLVM's decision to pass the return value in
-                // registers or using a return area pointer depends on how
-                // exactly the return type is lowered to an LLVM IR type. For
-                // example `Option<u128>` can be lowered as `{ i128, i128 }`
-                // in which case the x86_64 backend would use a return area
-                // pointer, or it could be passed as `{ i32, i128 }` in which
-                // case the x86_64 backend would pass it in registers by taking
-                // advantage of an LLVM ABI extension that allows using 3
-                // registers for the x86_64 sysv call conv rather than the
-                // officially specified 2 registers.
-                //
-                // FIXME: Technically we should look at the amount of available
-                // return registers rather than guessing that there are 2
-                // registers for return values. In practice only a couple of
-                // architectures have less than 2 return registers. None of
-                // which supported by Cranelift.
-                //
-                // NOTE: This adjustment is only necessary for the Rust ABI as
-                // for other ABI's the calling convention implementations in
-                // rustc_target already ensure any return value which doesn't
-                // fit in the available amount of return registers is passed in
-                // the right way for the current target.
-                arg.make_indirect();
-                return;
-            }
-
-            match arg.layout.abi {
-                Abi::Aggregate { .. } => {}
-
-                // This is a fun case! The gist of what this is doing is
-                // that we want callers and callees to always agree on the
-                // ABI of how they pass SIMD arguments. If we were to *not*
-                // make these arguments indirect then they'd be immediates
-                // in LLVM, which means that they'd used whatever the
-                // appropriate ABI is for the callee and the caller. That
-                // means, for example, if the caller doesn't have AVX
-                // enabled but the callee does, then passing an AVX argument
-                // across this boundary would cause corrupt data to show up.
-                //
-                // This problem is fixed by unconditionally passing SIMD
-                // arguments through memory between callers and callees
-                // which should get them all to agree on ABI regardless of
-                // target feature sets. Some more information about this
-                // issue can be found in #44367.
-                //
-                // Note that the intrinsic ABI is exempt here as
-                // that's how we connect up to LLVM and it's unstable
-                // anyway, we control all calls to it in libstd.
-                Abi::Vector { .. }
-                    if abi != SpecAbi::RustIntrinsic && tcx.sess.target.simd_types_indirect =>
-                {
-                    arg.make_indirect();
-                    return;
-                }
-
-                _ => return,
-            }
-            // Compute `Aggregate` ABI.
-
-            let is_indirect_not_on_stack =
-                matches!(arg.mode, PassMode::Indirect { on_stack: false, .. });
-            assert!(is_indirect_not_on_stack, "{:?}", arg);
-
-            let size = arg.layout.size;
-            if !arg.layout.is_unsized() && size <= Pointer(AddressSpace::DATA).size(cx) {
-                // We want to pass small aggregates as immediates, but using
-                // an LLVM aggregate type for this leads to bad optimizations,
-                // so we pick an appropriately sized integer type instead.
-                arg.cast_to(Reg { kind: RegKind::Integer, size });
+                continue;
             }
 
             // If we deduced that this parameter was read-only, add that to the attribute list now.
@@ -821,9 +699,7 @@
             // The `readonly` parameter only applies to pointers, so we can only do this if the
             // argument was passed indirectly. (If the argument is passed directly, it's an SSA
             // value, so it's implicitly immutable.)
-            if let (Some(arg_idx), &mut PassMode::Indirect { ref mut attrs, .. }) =
-                (arg_idx, &mut arg.mode)
-            {
+            if let &mut PassMode::Indirect { ref mut attrs, .. } = &mut arg.mode {
                 // The `deduced_param_attrs` list could be empty if this is a type of function
                 // we can't deduce any parameters for, so make sure the argument index is in
                 // bounds.
@@ -834,11 +710,6 @@
                     }
                 }
             }
-        };
-
-        fixup(&mut fn_abi.ret, None);
-        for (arg_idx, arg) in fn_abi.args.iter_mut().enumerate() {
-            fixup(arg, Some(arg_idx));
         }
     } else {
         fn_abi
diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs
index a057caa..16fd282 100644
--- a/compiler/rustc_ty_utils/src/assoc.rs
+++ b/compiler/rustc_ty_utils/src/assoc.rs
@@ -4,9 +4,8 @@
 use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId};
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_middle::query::Providers;
-use rustc_middle::ty::{self, ImplTraitInTraitData, Ty, TyCtxt};
+use rustc_middle::ty::{self, ImplTraitInTraitData, TyCtxt};
 use rustc_middle::{bug, span_bug};
-use rustc_span::sym;
 use rustc_span::symbol::kw;
 
 pub(crate) fn provide(providers: &mut Providers) {
@@ -15,7 +14,6 @@
         associated_item_def_ids,
         associated_items,
         associated_types_for_impl_traits_in_associated_fn,
-        associated_type_for_effects,
         associated_type_for_impl_trait_in_trait,
         impl_item_implementor_ids,
         ..*providers
@@ -46,8 +44,7 @@
                                 )
                             })
                             .copied(),
-                    )
-                    .chain(tcx.associated_type_for_effects(def_id)),
+                    ),
             )
         }
         hir::ItemKind::Impl(impl_) => {
@@ -73,8 +70,7 @@
                                 )
                             })
                             .copied()
-                    }))
-                    .chain(tcx.associated_type_for_effects(def_id)),
+                    })),
             )
         }
         _ => span_bug!(item.span, "associated_item_def_ids: not impl or trait"),
@@ -171,134 +167,6 @@
     }
 }
 
-/// Given an `def_id` of a trait or a trait impl:
-///
-/// If `def_id` is a trait that has `#[const_trait]`, then it synthesizes
-/// a new def id corresponding to a new associated type for the effects.
-///
-/// If `def_id` is an impl, then synthesize the associated type according
-/// to the constness of the impl.
-fn associated_type_for_effects(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<DefId> {
-    // don't synthesize the associated type even if the user has written `const_trait`
-    // if the effects feature is disabled.
-    if !tcx.features().effects {
-        return None;
-    }
-    let (feed, parent_did) = match tcx.def_kind(def_id) {
-        DefKind::Trait => {
-            let trait_def_id = def_id;
-            let attr = tcx.get_attr(def_id, sym::const_trait)?;
-
-            let span = attr.span;
-            let trait_assoc_ty = tcx.at(span).create_def(trait_def_id, kw::Empty, DefKind::AssocTy);
-
-            let local_def_id = trait_assoc_ty.def_id();
-            let def_id = local_def_id.to_def_id();
-
-            // Copy span of the attribute.
-            trait_assoc_ty.def_ident_span(Some(span));
-
-            trait_assoc_ty.associated_item(ty::AssocItem {
-                name: kw::Empty,
-                kind: ty::AssocKind::Type,
-                def_id,
-                trait_item_def_id: None,
-                container: ty::TraitContainer,
-                fn_has_self_parameter: false,
-                opt_rpitit_info: None,
-                is_effects_desugaring: true,
-            });
-
-            // No default type
-            trait_assoc_ty.defaultness(hir::Defaultness::Default { has_value: false });
-
-            trait_assoc_ty.is_type_alias_impl_trait(false);
-
-            (trait_assoc_ty, trait_def_id)
-        }
-        DefKind::Impl { .. } => {
-            let impl_def_id = def_id;
-            let trait_id = tcx.trait_id_of_impl(def_id.to_def_id())?;
-
-            // first get the DefId of the assoc type on the trait, if there is not,
-            // then we don't need to generate it on the impl.
-            let trait_assoc_id = tcx.associated_type_for_effects(trait_id)?;
-
-            // FIXME(effects): span
-            let span = tcx.def_ident_span(def_id).unwrap();
-
-            let impl_assoc_ty = tcx.at(span).create_def(def_id, kw::Empty, DefKind::AssocTy);
-
-            let local_def_id = impl_assoc_ty.def_id();
-            let def_id = local_def_id.to_def_id();
-
-            impl_assoc_ty.def_ident_span(Some(span));
-
-            impl_assoc_ty.associated_item(ty::AssocItem {
-                name: kw::Empty,
-                kind: ty::AssocKind::Type,
-                def_id,
-                trait_item_def_id: Some(trait_assoc_id),
-                container: ty::ImplContainer,
-                fn_has_self_parameter: false,
-                opt_rpitit_info: None,
-                is_effects_desugaring: true,
-            });
-
-            // no default value.
-            impl_assoc_ty.defaultness(hir::Defaultness::Final);
-
-            // set the type of the associated type! If this is a const impl,
-            // we set to Maybe, otherwise we set to `Runtime`.
-            let type_def_id = if tcx.is_const_trait_impl_raw(impl_def_id.to_def_id()) {
-                tcx.require_lang_item(hir::LangItem::EffectsMaybe, Some(span))
-            } else {
-                tcx.require_lang_item(hir::LangItem::EffectsRuntime, Some(span))
-            };
-            // FIXME(effects): make impls use `Min` for their effect types
-            impl_assoc_ty.type_of(ty::EarlyBinder::bind(Ty::new_adt(
-                tcx,
-                tcx.adt_def(type_def_id),
-                ty::GenericArgs::empty(),
-            )));
-
-            (impl_assoc_ty, impl_def_id)
-        }
-        def_kind => bug!(
-            "associated_type_for_effects: {:?} should be Trait or Impl but is {:?}",
-            def_id,
-            def_kind
-        ),
-    };
-
-    feed.feed_hir();
-
-    // visibility is public.
-    feed.visibility(ty::Visibility::Public);
-
-    // Copy generics_of of the trait/impl, making the trait/impl as parent.
-    feed.generics_of({
-        let parent_generics = tcx.generics_of(parent_did);
-        let parent_count = parent_generics.parent_count + parent_generics.own_params.len();
-
-        ty::Generics {
-            parent: Some(parent_did.to_def_id()),
-            parent_count,
-            own_params: vec![],
-            param_def_id_to_index: parent_generics.param_def_id_to_index.clone(),
-            has_self: false,
-            has_late_bound_regions: None,
-            host_effect_index: parent_generics.host_effect_index,
-        }
-    });
-    feed.explicit_item_super_predicates(ty::EarlyBinder::bind(&[]));
-
-    // There are no inferred outlives for the synthesized associated type.
-    feed.inferred_outlives_of(&[]);
-
-    Some(feed.def_id().to_def_id())
-}
-
 /// Given an `fn_def_id` of a trait or a trait implementation:
 ///
 /// if `fn_def_id` is a function defined inside a trait, then it synthesizes
@@ -494,7 +362,6 @@
             param_def_id_to_index,
             has_self: false,
             has_late_bound_regions: trait_assoc_generics.has_late_bound_regions,
-            host_effect_index: parent_generics.host_effect_index,
         }
     });
 
diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs
index 391985c..4b770d9 100644
--- a/compiler/rustc_ty_utils/src/consts.rs
+++ b/compiler/rustc_ty_utils/src/consts.rs
@@ -406,7 +406,7 @@
     tcx: TyCtxt<'tcx>,
     def: LocalDefId,
 ) -> Result<Option<ty::EarlyBinder<'tcx, ty::Const<'tcx>>>, ErrorGuaranteed> {
-    if !tcx.features().generic_const_exprs {
+    if !tcx.features().generic_const_exprs() {
         return Ok(None);
     }
 
diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs
index e755e90..94b80e2 100644
--- a/compiler/rustc_ty_utils/src/layout.rs
+++ b/compiler/rustc_ty_utils/src/layout.rs
@@ -6,7 +6,7 @@
 use rustc_abi::Primitive::{self, Float, Int, Pointer};
 use rustc_abi::{
     Abi, AbiAndPrefAlign, AddressSpace, Align, FieldsShape, HasDataLayout, LayoutCalculatorError,
-    LayoutS, Niche, ReprOptions, Scalar, Size, StructKind, TagEncoding, Variants, WrappingRange,
+    LayoutData, Niche, ReprOptions, Scalar, Size, StructKind, TagEncoding, Variants, WrappingRange,
 };
 use rustc_index::bit_set::BitSet;
 use rustc_index::{IndexSlice, IndexVec};
@@ -131,7 +131,7 @@
     fields: &IndexSlice<FieldIdx, TyAndLayout<'tcx>>,
     repr: &ReprOptions,
     kind: StructKind,
-) -> Result<LayoutS<FieldIdx, VariantIdx>, &'tcx LayoutError<'tcx>> {
+) -> Result<LayoutData<FieldIdx, VariantIdx>, &'tcx LayoutError<'tcx>> {
     let pack = repr.pack;
     if pack.is_some() && repr.align.is_some() {
         cx.tcx().dcx().bug("struct cannot be packed and aligned");
@@ -159,7 +159,7 @@
         assert!(size.bits() <= 128);
         Scalar::Initialized { value, valid_range: WrappingRange::full(size) }
     };
-    let scalar = |value: Primitive| tcx.mk_layout(LayoutS::scalar(cx, scalar_unit(value)));
+    let scalar = |value: Primitive| tcx.mk_layout(LayoutData::scalar(cx, scalar_unit(value)));
 
     let univariant =
         |fields: &IndexSlice<FieldIdx, TyAndLayout<'tcx>>, repr: &ReprOptions, kind| {
@@ -170,7 +170,7 @@
     Ok(match *ty.kind() {
         ty::Pat(ty, pat) => {
             let layout = cx.layout_of(ty)?.layout;
-            let mut layout = LayoutS::clone(&layout.0);
+            let mut layout = LayoutData::clone(&layout.0);
             match *pat {
                 ty::PatternKind::Range { start, end, include_end } => {
                     if let Abi::Scalar(scalar) | Abi::ScalarPair(scalar, _) = &mut layout.abi {
@@ -206,11 +206,11 @@
         }
 
         // Basic scalars.
-        ty::Bool => tcx.mk_layout(LayoutS::scalar(cx, Scalar::Initialized {
+        ty::Bool => tcx.mk_layout(LayoutData::scalar(cx, Scalar::Initialized {
             value: Int(I8, false),
             valid_range: WrappingRange { start: 0, end: 1 },
         })),
-        ty::Char => tcx.mk_layout(LayoutS::scalar(cx, Scalar::Initialized {
+        ty::Char => tcx.mk_layout(LayoutData::scalar(cx, Scalar::Initialized {
             value: Int(I32, false),
             valid_range: WrappingRange { start: 0, end: 0x10FFFF },
         })),
@@ -220,7 +220,7 @@
         ty::FnPtr(..) => {
             let mut ptr = scalar_unit(Pointer(dl.instruction_address_space));
             ptr.valid_range_mut().start = 1;
-            tcx.mk_layout(LayoutS::scalar(cx, ptr))
+            tcx.mk_layout(LayoutData::scalar(cx, ptr))
         }
 
         // The never type.
@@ -235,7 +235,7 @@
 
             let pointee = tcx.normalize_erasing_regions(param_env, pointee);
             if pointee.is_sized(tcx, param_env) {
-                return Ok(tcx.mk_layout(LayoutS::scalar(cx, data_ptr)));
+                return Ok(tcx.mk_layout(LayoutData::scalar(cx, data_ptr)));
             }
 
             let metadata = if let Some(metadata_def_id) = tcx.lang_items().metadata_type()
@@ -272,7 +272,7 @@
                 let metadata_layout = cx.layout_of(metadata_ty)?;
                 // If the metadata is a 1-zst, then the pointer is thin.
                 if metadata_layout.is_1zst() {
-                    return Ok(tcx.mk_layout(LayoutS::scalar(cx, data_ptr)));
+                    return Ok(tcx.mk_layout(LayoutData::scalar(cx, data_ptr)));
                 }
 
                 let Abi::Scalar(metadata) = metadata_layout.abi else {
@@ -285,7 +285,7 @@
 
                 match unsized_part.kind() {
                     ty::Foreign(..) => {
-                        return Ok(tcx.mk_layout(LayoutS::scalar(cx, data_ptr)));
+                        return Ok(tcx.mk_layout(LayoutData::scalar(cx, data_ptr)));
                     }
                     ty::Slice(_) | ty::Str => scalar_unit(Int(dl.ptr_sized_integer(), false)),
                     ty::Dynamic(..) => {
@@ -337,7 +337,7 @@
 
             let largest_niche = if count != 0 { element.largest_niche } else { None };
 
-            tcx.mk_layout(LayoutS {
+            tcx.mk_layout(LayoutData {
                 variants: Variants::Single { index: FIRST_VARIANT },
                 fields: FieldsShape::Array { stride: element.size, count },
                 abi,
@@ -350,7 +350,7 @@
         }
         ty::Slice(element) => {
             let element = cx.layout_of(element)?;
-            tcx.mk_layout(LayoutS {
+            tcx.mk_layout(LayoutData {
                 variants: Variants::Single { index: FIRST_VARIANT },
                 fields: FieldsShape::Array { stride: element.size, count: 0 },
                 abi: Abi::Aggregate { sized: false },
@@ -361,7 +361,7 @@
                 unadjusted_abi_align: element.align.abi,
             })
         }
-        ty::Str => tcx.mk_layout(LayoutS {
+        ty::Str => tcx.mk_layout(LayoutData {
             variants: Variants::Single { index: FIRST_VARIANT },
             fields: FieldsShape::Array { stride: Size::from_bytes(1), count: 0 },
             abi: Abi::Aggregate { sized: false },
@@ -532,7 +532,7 @@
                 FieldsShape::Array { stride: e_ly.size, count: e_len }
             };
 
-            tcx.mk_layout(LayoutS {
+            tcx.mk_layout(LayoutData {
                 variants: Variants::Single { index: FIRST_VARIANT },
                 fields,
                 abi,
@@ -835,7 +835,7 @@
     };
     let tag_layout = TyAndLayout {
         ty: discr_int.to_ty(tcx, /* signed = */ false),
-        layout: tcx.mk_layout(LayoutS::scalar(cx, tag)),
+        layout: tcx.mk_layout(LayoutData::scalar(cx, tag)),
     };
 
     let promoted_layouts = ineligible_locals.iter().map(|local| {
@@ -991,7 +991,7 @@
         Abi::Aggregate { sized: true }
     };
 
-    let layout = tcx.mk_layout(LayoutS {
+    let layout = tcx.mk_layout(LayoutData {
         variants: Variants::Multiple {
             tag,
             tag_encoding: TagEncoding::Direct,
diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs
index 28a81b1..aa49999 100644
--- a/compiler/rustc_ty_utils/src/ty.rs
+++ b/compiler/rustc_ty_utils/src/ty.rs
@@ -150,6 +150,16 @@
         });
     }
 
+    // We extend the param-env of our item with the const conditions of the item,
+    // since we're allowed to assume `~const` bounds hold within the item itself.
+    if tcx.is_conditionally_const(def_id) {
+        predicates.extend(
+            tcx.const_conditions(def_id).instantiate_identity(tcx).into_iter().map(
+                |(trait_ref, _)| trait_ref.to_host_effect_clause(tcx, ty::HostPolarity::Maybe),
+            ),
+        );
+    }
+
     let local_did = def_id.as_local();
 
     let unnormalized_env =
diff --git a/compiler/rustc_type_ir/src/binder.rs b/compiler/rustc_type_ir/src/binder.rs
index f20beb7..c06a578 100644
--- a/compiler/rustc_type_ir/src/binder.rs
+++ b/compiler/rustc_type_ir/src/binder.rs
@@ -496,8 +496,8 @@
 
     /// Similar to [`instantiate_identity`](EarlyBinder::instantiate_identity),
     /// but on an iterator of values that deref to a `TypeFoldable`.
-    pub fn iter_identity_copied(self) -> impl Iterator<Item = <Iter::Item as Deref>::Target> {
-        self.value.into_iter().map(|v| *v)
+    pub fn iter_identity_copied(self) -> IterIdentityCopied<Iter> {
+        IterIdentityCopied { it: self.value.into_iter() }
     }
 }
 
@@ -546,6 +546,44 @@
 {
 }
 
+pub struct IterIdentityCopied<Iter: IntoIterator> {
+    it: Iter::IntoIter,
+}
+
+impl<Iter: IntoIterator> Iterator for IterIdentityCopied<Iter>
+where
+    Iter::Item: Deref,
+    <Iter::Item as Deref>::Target: Copy,
+{
+    type Item = <Iter::Item as Deref>::Target;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        self.it.next().map(|i| *i)
+    }
+
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        self.it.size_hint()
+    }
+}
+
+impl<Iter: IntoIterator> DoubleEndedIterator for IterIdentityCopied<Iter>
+where
+    Iter::IntoIter: DoubleEndedIterator,
+    Iter::Item: Deref,
+    <Iter::Item as Deref>::Target: Copy,
+{
+    fn next_back(&mut self) -> Option<Self::Item> {
+        self.it.next_back().map(|i| *i)
+    }
+}
+
+impl<Iter: IntoIterator> ExactSizeIterator for IterIdentityCopied<Iter>
+where
+    Iter::IntoIter: ExactSizeIterator,
+    Iter::Item: Deref,
+    <Iter::Item as Deref>::Target: Copy,
+{
+}
 pub struct EarlyBinderIter<I, T> {
     t: T,
     _tcx: PhantomData<I>,
diff --git a/compiler/rustc_type_ir/src/canonical.rs b/compiler/rustc_type_ir/src/canonical.rs
index 07cb8b0..3fb7d87 100644
--- a/compiler/rustc_type_ir/src/canonical.rs
+++ b/compiler/rustc_type_ir/src/canonical.rs
@@ -108,7 +108,6 @@
             CanonicalVarKind::PlaceholderRegion(..) => false,
             CanonicalVarKind::Const(_) => true,
             CanonicalVarKind::PlaceholderConst(_) => false,
-            CanonicalVarKind::Effect => true,
         }
     }
 
@@ -118,17 +117,15 @@
             CanonicalVarKind::Ty(_)
             | CanonicalVarKind::PlaceholderTy(_)
             | CanonicalVarKind::Const(_)
-            | CanonicalVarKind::PlaceholderConst(_)
-            | CanonicalVarKind::Effect => false,
+            | CanonicalVarKind::PlaceholderConst(_) => false,
         }
     }
 
     pub fn expect_placeholder_index(self) -> usize {
         match self.kind {
-            CanonicalVarKind::Ty(_)
-            | CanonicalVarKind::Region(_)
-            | CanonicalVarKind::Const(_)
-            | CanonicalVarKind::Effect => panic!("expected placeholder: {self:?}"),
+            CanonicalVarKind::Ty(_) | CanonicalVarKind::Region(_) | CanonicalVarKind::Const(_) => {
+                panic!("expected placeholder: {self:?}")
+            }
 
             CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.var().as_usize(),
             CanonicalVarKind::PlaceholderTy(placeholder) => placeholder.var().as_usize(),
@@ -161,9 +158,6 @@
     /// Some kind of const inference variable.
     Const(UniverseIndex),
 
-    /// Effect variable `'?E`.
-    Effect,
-
     /// A "placeholder" that represents "any const".
     PlaceholderConst(I::PlaceholderConst),
 }
@@ -180,7 +174,6 @@
             CanonicalVarKind::Ty(CanonicalTyVarKind::Float | CanonicalTyVarKind::Int) => {
                 UniverseIndex::ROOT
             }
-            CanonicalVarKind::Effect => UniverseIndex::ROOT,
         }
     }
 
@@ -205,8 +198,7 @@
             CanonicalVarKind::PlaceholderConst(placeholder) => {
                 CanonicalVarKind::PlaceholderConst(placeholder.with_updated_universe(ui))
             }
-            CanonicalVarKind::Ty(CanonicalTyVarKind::Int | CanonicalTyVarKind::Float)
-            | CanonicalVarKind::Effect => {
+            CanonicalVarKind::Ty(CanonicalTyVarKind::Int | CanonicalTyVarKind::Float) => {
                 assert_eq!(ui, UniverseIndex::ROOT);
                 self
             }
@@ -311,10 +303,6 @@
                             Region::new_anon_bound(cx, ty::INNERMOST, ty::BoundVar::from_usize(i))
                                 .into()
                         }
-                        CanonicalVarKind::Effect => {
-                            Const::new_anon_bound(cx, ty::INNERMOST, ty::BoundVar::from_usize(i))
-                                .into()
-                        }
                         CanonicalVarKind::Const(_) | CanonicalVarKind::PlaceholderConst(_) => {
                             Const::new_anon_bound(cx, ty::INNERMOST, ty::BoundVar::from_usize(i))
                                 .into()
diff --git a/compiler/rustc_type_ir/src/const_kind.rs b/compiler/rustc_type_ir/src/const_kind.rs
index 7a8c612..03dfe54 100644
--- a/compiler/rustc_type_ir/src/const_kind.rs
+++ b/compiler/rustc_type_ir/src/const_kind.rs
@@ -84,32 +84,12 @@
     pub struct ConstVid {}
 }
 
-rustc_index::newtype_index! {
-    /// An **effect** **v**ariable **ID**.
-    ///
-    /// Handling effect infer variables happens separately from const infer variables
-    /// because we do not want to reuse any of the const infer machinery. If we try to
-    /// relate an effect variable with a normal one, we would ICE, which can catch bugs
-    /// where we are not correctly using the effect var for an effect param. Fallback
-    /// is also implemented on top of having separate effect and normal const variables.
-    #[encodable]
-    #[orderable]
-    #[debug_format = "?{}e"]
-    #[gate_rustc_only]
-    pub struct EffectVid {}
-}
-
 /// An inference variable for a const, for use in const generics.
 #[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)]
 #[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable))]
 pub enum InferConst {
     /// Infer the value of the const.
     Var(ConstVid),
-    /// Infer the value of the effect.
-    ///
-    /// For why this is separate from the `Var` variant above, see the
-    /// documentation on `EffectVid`.
-    EffectVar(EffectVid),
     /// A fresh const variable. See `infer::freshen` for more details.
     Fresh(u32),
 }
@@ -118,7 +98,6 @@
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self {
             InferConst::Var(var) => write!(f, "{var:?}"),
-            InferConst::EffectVar(var) => write!(f, "{var:?}"),
             InferConst::Fresh(var) => write!(f, "Fresh({var:?})"),
         }
     }
@@ -128,7 +107,7 @@
 impl<CTX> HashStable<CTX> for InferConst {
     fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
         match self {
-            InferConst::Var(_) | InferConst::EffectVar(_) => {
+            InferConst::Var(_) => {
                 panic!("const variables should not be hashed: {self:?}")
             }
             InferConst::Fresh(i) => i.hash_stable(hcx, hasher),
diff --git a/compiler/rustc_type_ir/src/effects.rs b/compiler/rustc_type_ir/src/effects.rs
deleted file mode 100644
index ab43533..0000000
--- a/compiler/rustc_type_ir/src/effects.rs
+++ /dev/null
@@ -1,59 +0,0 @@
-use crate::Interner;
-use crate::inherent::*;
-use crate::lang_items::TraitSolverLangItem::{EffectsMaybe, EffectsNoRuntime, EffectsRuntime};
-
-#[derive(Clone, Copy, PartialEq, Eq)]
-pub enum EffectKind {
-    Maybe,
-    Runtime,
-    NoRuntime,
-}
-
-impl EffectKind {
-    pub fn try_from_def_id<I: Interner>(cx: I, def_id: I::DefId) -> Option<EffectKind> {
-        if cx.is_lang_item(def_id, EffectsMaybe) {
-            Some(EffectKind::Maybe)
-        } else if cx.is_lang_item(def_id, EffectsRuntime) {
-            Some(EffectKind::Runtime)
-        } else if cx.is_lang_item(def_id, EffectsNoRuntime) {
-            Some(EffectKind::NoRuntime)
-        } else {
-            None
-        }
-    }
-
-    pub fn to_def_id<I: Interner>(self, cx: I) -> I::DefId {
-        let lang_item = match self {
-            EffectKind::Maybe => EffectsMaybe,
-            EffectKind::NoRuntime => EffectsNoRuntime,
-            EffectKind::Runtime => EffectsRuntime,
-        };
-
-        cx.require_lang_item(lang_item)
-    }
-
-    pub fn try_from_ty<I: Interner>(cx: I, ty: I::Ty) -> Option<EffectKind> {
-        if let crate::Adt(def, _) = ty.kind() {
-            Self::try_from_def_id(cx, def.def_id())
-        } else {
-            None
-        }
-    }
-
-    pub fn to_ty<I: Interner>(self, cx: I) -> I::Ty {
-        I::Ty::new_adt(cx, cx.adt_def(self.to_def_id(cx)), Default::default())
-    }
-
-    /// Returns an intersection between two effect kinds. If one effect kind
-    /// is more permissive than the other (e.g. `Maybe` vs `Runtime`), this
-    /// returns the less permissive effect kind (`Runtime`).
-    pub fn intersection(a: Self, b: Self) -> Option<Self> {
-        use EffectKind::*;
-        match (a, b) {
-            (Maybe, x) | (x, Maybe) => Some(x),
-            (Runtime, Runtime) => Some(Runtime),
-            (NoRuntime, NoRuntime) => Some(NoRuntime),
-            (Runtime, NoRuntime) | (NoRuntime, Runtime) => None,
-        }
-    }
-}
diff --git a/compiler/rustc_type_ir/src/elaborate.rs b/compiler/rustc_type_ir/src/elaborate.rs
index dac45ff..72d392e 100644
--- a/compiler/rustc_type_ir/src/elaborate.rs
+++ b/compiler/rustc_type_ir/src/elaborate.rs
@@ -4,7 +4,6 @@
 
 use crate::data_structures::HashSet;
 use crate::inherent::*;
-use crate::lang_items::TraitSolverLangItem;
 use crate::outlives::{Component, push_outlives_components};
 use crate::{self as ty, Interner, Upcast as _};
 
@@ -130,70 +129,6 @@
                     return;
                 }
 
-                // HACK(effects): The following code is required to get implied bounds for effects associated
-                // types to work with super traits.
-                //
-                // Suppose `data` is a trait predicate with the form `<T as Tr>::Fx: EffectsCompat<somebool>`
-                // and we know that `trait Tr: ~const SuperTr`, we need to elaborate this predicate into
-                // `<T as SuperTr>::Fx: EffectsCompat<somebool>`.
-                //
-                // Since the semantics for elaborating bounds about effects is equivalent to elaborating
-                // bounds about super traits (elaborate `T: Tr` into `T: SuperTr`), we place effects elaboration
-                // next to super trait elaboration.
-                if cx.is_lang_item(data.def_id(), TraitSolverLangItem::EffectsCompat)
-                    && matches!(self.mode, Filter::All)
-                {
-                    // first, ensure that the predicate we've got looks like a `<T as Tr>::Fx: EffectsCompat<somebool>`.
-                    if let ty::Alias(ty::AliasTyKind::Projection, alias_ty) = data.self_ty().kind()
-                    {
-                        // look for effects-level bounds that look like `<Self as Tr>::Fx: TyCompat<<Self as SuperTr>::Fx>`
-                        // on the trait, which is proof to us that `Tr: ~const SuperTr`. We're looking for bounds on the
-                        // associated trait, so we use `explicit_implied_predicates_of` since it gives us more than just
-                        // `Self: SuperTr` bounds.
-                        let bounds = cx.explicit_implied_predicates_of(cx.parent(alias_ty.def_id));
-
-                        // instantiate the implied bounds, so we get `<T as Tr>::Fx` and not `<Self as Tr>::Fx`.
-                        let elaborated = bounds.iter_instantiated(cx, alias_ty.args).filter_map(
-                            |(clause, _)| {
-                                let ty::ClauseKind::Trait(tycompat_bound) =
-                                    clause.kind().skip_binder()
-                                else {
-                                    return None;
-                                };
-                                if !cx.is_lang_item(
-                                    tycompat_bound.def_id(),
-                                    TraitSolverLangItem::EffectsTyCompat,
-                                ) {
-                                    return None;
-                                }
-
-                                // extract `<T as SuperTr>::Fx` from the `TyCompat` bound.
-                                let supertrait_effects_ty =
-                                    tycompat_bound.trait_ref.args.type_at(1);
-                                let ty::Alias(ty::AliasTyKind::Projection, supertrait_alias_ty) =
-                                    supertrait_effects_ty.kind()
-                                else {
-                                    return None;
-                                };
-
-                                // The self types (`T`) must be equal for `<T as Tr>::Fx` and `<T as SuperTr>::Fx`.
-                                if supertrait_alias_ty.self_ty() != alias_ty.self_ty() {
-                                    return None;
-                                };
-
-                                // replace the self type in the original bound `<T as Tr>::Fx: EffectsCompat<somebool>`
-                                // to the effects type of the super trait. (`<T as SuperTr>::Fx`)
-                                let elaborated_bound = data.with_self_ty(cx, supertrait_effects_ty);
-                                Some(
-                                    elaboratable
-                                        .child(bound_clause.rebind(elaborated_bound).upcast(cx)),
-                                )
-                            },
-                        );
-                        self.extend_deduped(elaborated);
-                    }
-                }
-
                 let map_to_child_clause =
                     |(index, (clause, span)): (usize, (I::Clause, I::Span))| {
                         elaboratable.child_with_derived_cause(
@@ -220,6 +155,16 @@
                     ),
                 };
             }
+            // `T: ~const Trait` implies `T: ~const Supertrait`.
+            ty::ClauseKind::HostEffect(data) => self.extend_deduped(
+                cx.implied_const_bounds(data.def_id()).iter_identity().map(|trait_ref| {
+                    elaboratable.child(
+                        trait_ref
+                            .to_host_effect_clause(cx, data.host)
+                            .instantiate_supertrait(cx, bound_clause.rebind(data.trait_ref)),
+                    )
+                }),
+            ),
             ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty_max, r_min)) => {
                 // We know that `T: 'a` for some type `T`. We can
                 // often elaborate this. For example, if we know that
diff --git a/compiler/rustc_type_ir/src/error.rs b/compiler/rustc_type_ir/src/error.rs
index 8a6d37b..cdff77f 100644
--- a/compiler/rustc_type_ir/src/error.rs
+++ b/compiler/rustc_type_ir/src/error.rs
@@ -27,10 +27,9 @@
 #[cfg_attr(feature = "nightly", rustc_pass_by_value)]
 pub enum TypeError<I: Interner> {
     Mismatch,
-    ConstnessMismatch(ExpectedFound<ty::BoundConstness>),
-    PolarityMismatch(ExpectedFound<ty::PredicatePolarity>),
-    SafetyMismatch(ExpectedFound<I::Safety>),
-    AbiMismatch(ExpectedFound<I::Abi>),
+    PolarityMismatch(#[type_visitable(ignore)] ExpectedFound<ty::PredicatePolarity>),
+    SafetyMismatch(#[type_visitable(ignore)] ExpectedFound<I::Safety>),
+    AbiMismatch(#[type_visitable(ignore)] ExpectedFound<I::Abi>),
     Mutability,
     ArgumentMutability(usize),
     TupleSize(ExpectedFound<usize>),
@@ -73,9 +72,9 @@
     pub fn must_include_note(self) -> bool {
         use self::TypeError::*;
         match self {
-            CyclicTy(_) | CyclicConst(_) | SafetyMismatch(_) | ConstnessMismatch(_)
-            | PolarityMismatch(_) | Mismatch | AbiMismatch(_) | FixedArraySize(_)
-            | ArgumentSorts(..) | Sorts(_) | VariadicMismatch(_) | TargetFeatureCast(_) => false,
+            CyclicTy(_) | CyclicConst(_) | SafetyMismatch(_) | PolarityMismatch(_) | Mismatch
+            | AbiMismatch(_) | FixedArraySize(_) | ArgumentSorts(..) | Sorts(_)
+            | VariadicMismatch(_) | TargetFeatureCast(_) => false,
 
             Mutability
             | ArgumentMutability(_)
diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs
index b9f5cde..7c6a3c6 100644
--- a/compiler/rustc_type_ir/src/infer_ctxt.rs
+++ b/compiler/rustc_type_ir/src/infer_ctxt.rs
@@ -38,10 +38,6 @@
         &self,
         vid: ty::ConstVid,
     ) -> <Self::Interner as Interner>::Const;
-    fn opportunistic_resolve_effect_var(
-        &self,
-        vid: ty::EffectVid,
-    ) -> <Self::Interner as Interner>::Const;
     fn opportunistic_resolve_lt_var(
         &self,
         vid: ty::RegionVid,
@@ -71,7 +67,6 @@
     fn equate_int_vids_raw(&self, a: ty::IntVid, b: ty::IntVid);
     fn equate_float_vids_raw(&self, a: ty::FloatVid, b: ty::FloatVid);
     fn equate_const_vids_raw(&self, a: ty::ConstVid, b: ty::ConstVid);
-    fn equate_effect_vids_raw(&self, a: ty::EffectVid, b: ty::EffectVid);
 
     fn instantiate_ty_var_raw<R: PredicateEmittingRelation<Self>>(
         &self,
@@ -83,11 +78,6 @@
     ) -> RelateResult<Self::Interner, ()>;
     fn instantiate_int_var_raw(&self, vid: ty::IntVid, value: ty::IntVarValue);
     fn instantiate_float_var_raw(&self, vid: ty::FloatVid, value: ty::FloatVarValue);
-    fn instantiate_effect_var_raw(
-        &self,
-        vid: ty::EffectVid,
-        value: <Self::Interner as Interner>::Const,
-    );
     fn instantiate_const_var_raw<R: PredicateEmittingRelation<Self>>(
         &self,
         relation: &mut R,
diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs
index f7875bb..5af1aa2 100644
--- a/compiler/rustc_type_ir/src/inherent.rs
+++ b/compiler/rustc_type_ir/src/inherent.rs
@@ -208,14 +208,14 @@
     fn output(self) -> I::Ty;
 }
 
-pub trait Abi<I: Interner<Abi = Self>>: Copy + Debug + Hash + Eq + Relate<I> {
+pub trait Abi<I: Interner<Abi = Self>>: Copy + Debug + Hash + Eq {
     fn rust() -> Self;
 
     /// Whether this ABI is `extern "Rust"`.
     fn is_rust(self) -> bool;
 }
 
-pub trait Safety<I: Interner<Safety = Self>>: Copy + Debug + Hash + Eq + Relate<I> {
+pub trait Safety<I: Interner<Safety = Self>>: Copy + Debug + Hash + Eq {
     fn safe() -> Self;
 
     fn is_safe(self) -> bool;
@@ -468,6 +468,14 @@
             .transpose()
     }
 
+    fn as_host_effect_clause(self) -> Option<ty::Binder<I, ty::HostEffectPredicate<I>>> {
+        self.kind()
+            .map_bound(
+                |clause| if let ty::ClauseKind::HostEffect(t) = clause { Some(t) } else { None },
+            )
+            .transpose()
+    }
+
     fn as_projection_clause(self) -> Option<ty::Binder<I, ty::ProjectionPredicate<I>>> {
         self.kind()
             .map_bound(
diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs
index f06017d..6a8113b 100644
--- a/compiler/rustc_type_ir/src/interner.rs
+++ b/compiler/rustc_type_ir/src/interner.rs
@@ -15,9 +15,7 @@
     CanonicalInput, ExternalConstraintsData, PredefinedOpaquesData, QueryResult, SolverMode,
 };
 use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable};
-use crate::{
-    search_graph, {self as ty},
-};
+use crate::{self as ty, search_graph};
 
 pub trait Interner:
     Sized
@@ -26,6 +24,7 @@
     + IrPrint<ty::AliasTerm<Self>>
     + IrPrint<ty::TraitRef<Self>>
     + IrPrint<ty::TraitPredicate<Self>>
+    + IrPrint<ty::HostEffectPredicate<Self>>
     + IrPrint<ty::ExistentialTraitRef<Self>>
     + IrPrint<ty::ExistentialProjection<Self>>
     + IrPrint<ty::ProjectionPredicate<Self>>
@@ -173,6 +172,10 @@
 
     fn debug_assert_args_compatible(self, def_id: Self::DefId, args: Self::GenericArgs);
 
+    /// Assert that the args from an `ExistentialTraitRef` or `ExistentialProjection`
+    /// are compatible with the `DefId`.
+    fn debug_assert_existential_args_compatible(self, def_id: Self::DefId, args: Self::GenericArgs);
+
     fn mk_type_list_from_iter<I, T>(self, args: I) -> T::Output
     where
         I: Iterator<Item = T>,
@@ -226,6 +229,16 @@
         def_id: Self::DefId,
     ) -> ty::EarlyBinder<Self, impl IntoIterator<Item = (Self::Clause, Self::Span)>>;
 
+    fn is_const_impl(self, def_id: Self::DefId) -> bool;
+    fn const_conditions(
+        self,
+        def_id: Self::DefId,
+    ) -> ty::EarlyBinder<Self, impl IntoIterator<Item = ty::Binder<Self, ty::TraitRef<Self>>>>;
+    fn implied_const_bounds(
+        self,
+        def_id: Self::DefId,
+    ) -> ty::EarlyBinder<Self, impl IntoIterator<Item = ty::Binder<Self, ty::TraitRef<Self>>>>;
+
     fn has_target_features(self, def_id: Self::DefId) -> bool;
 
     fn require_lang_item(self, lang_item: TraitSolverLangItem) -> Self::DefId;
diff --git a/compiler/rustc_type_ir/src/ir_print.rs b/compiler/rustc_type_ir/src/ir_print.rs
index d57d081..0c71f3a 100644
--- a/compiler/rustc_type_ir/src/ir_print.rs
+++ b/compiler/rustc_type_ir/src/ir_print.rs
@@ -2,8 +2,8 @@
 
 use crate::{
     AliasTerm, AliasTy, Binder, CoercePredicate, ExistentialProjection, ExistentialTraitRef, FnSig,
-    Interner, NormalizesTo, OutlivesPredicate, ProjectionPredicate, SubtypePredicate,
-    TraitPredicate, TraitRef,
+    HostEffectPredicate, Interner, NormalizesTo, OutlivesPredicate, ProjectionPredicate,
+    SubtypePredicate, TraitPredicate, TraitRef,
 };
 
 pub trait IrPrint<T> {
@@ -53,6 +53,7 @@
     NormalizesTo,
     SubtypePredicate,
     CoercePredicate,
+    HostEffectPredicate,
     AliasTy,
     AliasTerm,
     FnSig,
diff --git a/compiler/rustc_type_ir/src/lang_items.rs b/compiler/rustc_type_ir/src/lang_items.rs
index c680c84..d6ca22a 100644
--- a/compiler/rustc_type_ir/src/lang_items.rs
+++ b/compiler/rustc_type_ir/src/lang_items.rs
@@ -20,13 +20,6 @@
     Destruct,
     DiscriminantKind,
     DynMetadata,
-    EffectsCompat,
-    EffectsIntersection,
-    EffectsIntersectionOutput,
-    EffectsMaybe,
-    EffectsNoRuntime,
-    EffectsRuntime,
-    EffectsTyCompat,
     Fn,
     FnMut,
     FnOnce,
diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs
index 9e6d1f4..e7ca241 100644
--- a/compiler/rustc_type_ir/src/lib.rs
+++ b/compiler/rustc_type_ir/src/lib.rs
@@ -43,7 +43,6 @@
 mod binder;
 mod canonical;
 mod const_kind;
-mod effects;
 mod flags;
 mod generic_arg;
 mod infer_ctxt;
@@ -67,7 +66,6 @@
 #[cfg(feature = "nightly")]
 pub use codec::*;
 pub use const_kind::*;
-pub use effects::*;
 pub use flags::*;
 pub use generic_arg::*;
 pub use infer_ctxt::*;
diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs
index b613505..c316455 100644
--- a/compiler/rustc_type_ir/src/predicate.rs
+++ b/compiler/rustc_type_ir/src/predicate.rs
@@ -111,6 +111,13 @@
     pub fn def_id(&self) -> I::DefId {
         self.skip_binder().def_id
     }
+
+    pub fn to_host_effect_clause(self, cx: I, host: HostPolarity) -> I::Clause {
+        self.map_bound(|trait_ref| {
+            ty::ClauseKind::HostEffect(HostEffectPredicate { trait_ref, host })
+        })
+        .upcast(cx)
+    }
 }
 
 #[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)]
@@ -289,9 +296,26 @@
 pub struct ExistentialTraitRef<I: Interner> {
     pub def_id: I::DefId,
     pub args: I::GenericArgs,
+    /// This field exists to prevent the creation of `ExistentialTraitRef` without
+    /// calling [`ExistentialTraitRef::new_from_args`].
+    _use_existential_trait_ref_new_instead: (),
 }
 
 impl<I: Interner> ExistentialTraitRef<I> {
+    pub fn new_from_args(interner: I, trait_def_id: I::DefId, args: I::GenericArgs) -> Self {
+        interner.debug_assert_existential_args_compatible(trait_def_id, args);
+        Self { def_id: trait_def_id, args, _use_existential_trait_ref_new_instead: () }
+    }
+
+    pub fn new(
+        interner: I,
+        trait_def_id: I::DefId,
+        args: impl IntoIterator<Item: Into<I::GenericArg>>,
+    ) -> Self {
+        let args = interner.mk_args_from_iter(args.into_iter().map(Into::into));
+        Self::new_from_args(interner, trait_def_id, args)
+    }
+
     pub fn erase_self_ty(interner: I, trait_ref: TraitRef<I>) -> ExistentialTraitRef<I> {
         // Assert there is a Self.
         trait_ref.args.type_at(0);
@@ -299,6 +323,7 @@
         ExistentialTraitRef {
             def_id: trait_ref.def_id,
             args: interner.mk_args(&trait_ref.args.as_slice()[1..]),
+            _use_existential_trait_ref_new_instead: (),
         }
     }
 
@@ -336,9 +361,33 @@
     pub def_id: I::DefId,
     pub args: I::GenericArgs,
     pub term: I::Term,
+
+    /// This field exists to prevent the creation of `ExistentialProjection`
+    /// without using [`ExistentialProjection::new_from_args`].
+    use_existential_projection_new_instead: (),
 }
 
 impl<I: Interner> ExistentialProjection<I> {
+    pub fn new_from_args(
+        interner: I,
+        def_id: I::DefId,
+        args: I::GenericArgs,
+        term: I::Term,
+    ) -> ExistentialProjection<I> {
+        interner.debug_assert_existential_args_compatible(def_id, args);
+        Self { def_id, args, term, use_existential_projection_new_instead: () }
+    }
+
+    pub fn new(
+        interner: I,
+        def_id: I::DefId,
+        args: impl IntoIterator<Item: Into<I::GenericArg>>,
+        term: I::Term,
+    ) -> ExistentialProjection<I> {
+        let args = interner.mk_args_from_iter(args.into_iter().map(Into::into));
+        Self::new_from_args(interner, def_id, args, term)
+    }
+
     /// Extracts the underlying existential trait reference from this projection.
     /// For example, if this is a projection of `exists T. <T as Iterator>::Item == X`,
     /// then this function would return an `exists T. T: Iterator` existential trait
@@ -347,7 +396,7 @@
         let def_id = interner.parent(self.def_id);
         let args_count = interner.generics_of(def_id).count() - 1;
         let args = interner.mk_args(&self.args.as_slice()[..args_count]);
-        ExistentialTraitRef { def_id, args }
+        ExistentialTraitRef { def_id, args, _use_existential_trait_ref_new_instead: () }
     }
 
     pub fn with_self_ty(&self, interner: I, self_ty: I::Ty) -> ProjectionPredicate<I> {
@@ -372,6 +421,7 @@
             def_id: projection_predicate.projection_term.def_id,
             args: interner.mk_args(&projection_predicate.projection_term.args.as_slice()[1..]),
             term: projection_predicate.term,
+            use_existential_projection_new_instead: (),
         }
     }
 }
@@ -702,6 +752,64 @@
     }
 }
 
+#[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)]
+#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
+#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))]
+pub struct HostEffectPredicate<I: Interner> {
+    pub trait_ref: ty::TraitRef<I>,
+    pub host: HostPolarity,
+}
+
+impl<I: Interner> HostEffectPredicate<I> {
+    pub fn self_ty(self) -> I::Ty {
+        self.trait_ref.self_ty()
+    }
+
+    pub fn with_self_ty(self, interner: I, self_ty: I::Ty) -> Self {
+        Self { trait_ref: self.trait_ref.with_self_ty(interner, self_ty), ..self }
+    }
+
+    pub fn def_id(self) -> I::DefId {
+        self.trait_ref.def_id
+    }
+}
+
+impl<I: Interner> ty::Binder<I, HostEffectPredicate<I>> {
+    pub fn def_id(self) -> I::DefId {
+        // Ok to skip binder since trait `DefId` does not care about regions.
+        self.skip_binder().def_id()
+    }
+
+    pub fn self_ty(self) -> ty::Binder<I, I::Ty> {
+        self.map_bound(|trait_ref| trait_ref.self_ty())
+    }
+
+    #[inline]
+    pub fn host(self) -> HostPolarity {
+        self.skip_binder().host
+    }
+}
+
+#[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)]
+#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
+#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))]
+pub enum HostPolarity {
+    /// May be called in const environments if the callee is const.
+    Maybe,
+    /// Always allowed to be called in const environments.
+    Const,
+}
+
+impl HostPolarity {
+    pub fn satisfies(self, goal: HostPolarity) -> bool {
+        match (self, goal) {
+            (HostPolarity::Const, HostPolarity::Const | HostPolarity::Maybe) => true,
+            (HostPolarity::Maybe, HostPolarity::Maybe) => true,
+            (HostPolarity::Maybe, HostPolarity::Const) => false,
+        }
+    }
+}
+
 /// Encodes that `a` must be a subtype of `b`. The `a_is_expected` flag indicates
 /// whether the `a` type is the type that we should label as "expected" when
 /// presenting user diagnostics.
diff --git a/compiler/rustc_type_ir/src/predicate_kind.rs b/compiler/rustc_type_ir/src/predicate_kind.rs
index 46202db..21f4456 100644
--- a/compiler/rustc_type_ir/src/predicate_kind.rs
+++ b/compiler/rustc_type_ir/src/predicate_kind.rs
@@ -37,6 +37,12 @@
 
     /// Constant initializer must evaluate successfully.
     ConstEvaluatable(I::Const),
+
+    /// Enforces the constness of the predicate we're calling. Like a projection
+    /// goal from a where clause, it's always going to be paired with a
+    /// corresponding trait clause; this just enforces the *constness* of that
+    /// implementation.
+    HostEffect(ty::HostEffectPredicate<I>),
 }
 
 #[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)]
@@ -110,6 +116,7 @@
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self {
             ClauseKind::ConstArgHasType(ct, ty) => write!(f, "ConstArgHasType({ct:?}, {ty:?})"),
+            ClauseKind::HostEffect(data) => data.fmt(f),
             ClauseKind::Trait(a) => a.fmt(f),
             ClauseKind::RegionOutlives(pair) => pair.fmt(f),
             ClauseKind::TypeOutlives(pair) => pair.fmt(f),
diff --git a/compiler/rustc_type_ir/src/relate.rs b/compiler/rustc_type_ir/src/relate.rs
index e1f3e49..ad17911 100644
--- a/compiler/rustc_type_ir/src/relate.rs
+++ b/compiler/rustc_type_ir/src/relate.rs
@@ -174,12 +174,17 @@
                 ExpectedFound::new(true, a, b)
             }));
         }
-        let safety = relation.relate(a.safety, b.safety)?;
-        let abi = relation.relate(a.abi, b.abi)?;
+
+        if a.safety != b.safety {
+            return Err(TypeError::SafetyMismatch(ExpectedFound::new(true, a.safety, b.safety)));
+        }
+
+        if a.abi != b.abi {
+            return Err(TypeError::AbiMismatch(ExpectedFound::new(true, a.abi, b.abi)));
+        };
 
         let a_inputs = a.inputs();
         let b_inputs = b.inputs();
-
         if a_inputs.len() != b_inputs.len() {
             return Err(TypeError::ArgCount);
         }
@@ -212,26 +217,12 @@
         Ok(ty::FnSig {
             inputs_and_output: cx.mk_type_list_from_iter(inputs_and_output)?,
             c_variadic: a.c_variadic,
-            safety,
-            abi,
+            safety: a.safety,
+            abi: a.abi,
         })
     }
 }
 
-impl<I: Interner> Relate<I> for ty::BoundConstness {
-    fn relate<R: TypeRelation<I>>(
-        _relation: &mut R,
-        a: ty::BoundConstness,
-        b: ty::BoundConstness,
-    ) -> RelateResult<I, ty::BoundConstness> {
-        if a != b {
-            Err(TypeError::ConstnessMismatch(ExpectedFound::new(true, a, b)))
-        } else {
-            Ok(a)
-        }
-    }
-}
-
 impl<I: Interner> Relate<I> for ty::AliasTy<I> {
     fn relate<R: TypeRelation<I>>(
         relation: &mut R,
@@ -333,7 +324,7 @@
                 a.args,
                 b.args,
             )?;
-            Ok(ty::ExistentialProjection { def_id: a.def_id, args, term })
+            Ok(ty::ExistentialProjection::new_from_args(relation.cx(), a.def_id, args, term))
         }
     }
 }
@@ -373,7 +364,7 @@
             }))
         } else {
             let args = relate_args_invariantly(relation, a.args, b.args)?;
-            Ok(ty::ExistentialTraitRef { def_id: a.def_id, args })
+            Ok(ty::ExistentialTraitRef::new_from_args(relation.cx(), a.def_id, args))
         }
     }
 }
@@ -659,29 +650,18 @@
     }
 }
 
-impl<I: Interner> Relate<I> for ty::PredicatePolarity {
-    fn relate<R: TypeRelation<I>>(
-        _relation: &mut R,
-        a: ty::PredicatePolarity,
-        b: ty::PredicatePolarity,
-    ) -> RelateResult<I, ty::PredicatePolarity> {
-        if a != b {
-            Err(TypeError::PolarityMismatch(ExpectedFound::new(true, a, b)))
-        } else {
-            Ok(a)
-        }
-    }
-}
-
 impl<I: Interner> Relate<I> for ty::TraitPredicate<I> {
     fn relate<R: TypeRelation<I>>(
         relation: &mut R,
         a: ty::TraitPredicate<I>,
         b: ty::TraitPredicate<I>,
     ) -> RelateResult<I, ty::TraitPredicate<I>> {
-        Ok(ty::TraitPredicate {
-            trait_ref: relation.relate(a.trait_ref, b.trait_ref)?,
-            polarity: relation.relate(a.polarity, b.polarity)?,
-        })
+        let trait_ref = relation.relate(a.trait_ref, b.trait_ref)?;
+        if a.polarity != b.polarity {
+            return Err(TypeError::PolarityMismatch(ExpectedFound::new(
+                true, a.polarity, b.polarity,
+            )));
+        }
+        Ok(ty::TraitPredicate { trait_ref, polarity: a.polarity })
     }
 }
diff --git a/compiler/rustc_type_ir/src/relate/combine.rs b/compiler/rustc_type_ir/src/relate/combine.rs
index 60a9538..17a3912 100644
--- a/compiler/rustc_type_ir/src/relate/combine.rs
+++ b/compiler/rustc_type_ir/src/relate/combine.rs
@@ -179,23 +179,9 @@
             Ok(a)
         }
 
-        (
-            ty::ConstKind::Infer(ty::InferConst::EffectVar(a_vid)),
-            ty::ConstKind::Infer(ty::InferConst::EffectVar(b_vid)),
-        ) => {
-            infcx.equate_effect_vids_raw(a_vid, b_vid);
-            Ok(a)
-        }
-
         // All other cases of inference with other variables are errors.
-        (
-            ty::ConstKind::Infer(ty::InferConst::Var(_) | ty::InferConst::EffectVar(_)),
-            ty::ConstKind::Infer(_),
-        )
-        | (
-            ty::ConstKind::Infer(_),
-            ty::ConstKind::Infer(ty::InferConst::Var(_) | ty::InferConst::EffectVar(_)),
-        ) => {
+        (ty::ConstKind::Infer(ty::InferConst::Var(_)), ty::ConstKind::Infer(_))
+        | (ty::ConstKind::Infer(_), ty::ConstKind::Infer(ty::InferConst::Var(_))) => {
             panic!(
                 "tried to combine ConstKind::Infer/ConstKind::Infer(InferConst::Var): {a:?} and {b:?}"
             )
@@ -211,16 +197,6 @@
             Ok(a)
         }
 
-        (ty::ConstKind::Infer(ty::InferConst::EffectVar(vid)), _) => {
-            infcx.instantiate_effect_var_raw(vid, b);
-            Ok(b)
-        }
-
-        (_, ty::ConstKind::Infer(ty::InferConst::EffectVar(vid))) => {
-            infcx.instantiate_effect_var_raw(vid, a);
-            Ok(a)
-        }
-
         (ty::ConstKind::Unevaluated(..), _) | (_, ty::ConstKind::Unevaluated(..))
             if infcx.cx().features().generic_const_exprs() || infcx.next_trait_solver() =>
         {
diff --git a/compiler/rustc_type_ir/src/solve/inspect.rs b/compiler/rustc_type_ir/src/solve/inspect.rs
index 138ba8b..d0e618d 100644
--- a/compiler/rustc_type_ir/src/solve/inspect.rs
+++ b/compiler/rustc_type_ir/src/solve/inspect.rs
@@ -23,9 +23,7 @@
 use derive_where::derive_where;
 use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic};
 
-use crate::solve::{
-    CandidateSource, CanonicalInput, Certainty, Goal, GoalSource, QueryInput, QueryResult,
-};
+use crate::solve::{CandidateSource, CanonicalInput, Certainty, Goal, GoalSource, QueryResult};
 use crate::{Canonical, CanonicalVarValues, Interner};
 
 /// Some `data` together with information about how they relate to the input
@@ -69,15 +67,10 @@
 #[derive_where(PartialEq, Eq, Hash, Debug; I: Interner)]
 pub enum CanonicalGoalEvaluationKind<I: Interner> {
     Overflow,
-    Evaluation { final_revision: CanonicalGoalEvaluationStep<I> },
-}
-
-#[derive_where(PartialEq, Eq, Hash, Debug; I: Interner)]
-pub struct CanonicalGoalEvaluationStep<I: Interner> {
-    pub instantiated_goal: QueryInput<I, I::Predicate>,
-
-    /// The actual evaluation of the goal, always `ProbeKind::Root`.
-    pub evaluation: Probe<I>,
+    Evaluation {
+        /// This is always `ProbeKind::Root`.
+        final_revision: Probe<I>,
+    },
 }
 
 /// A self-contained computation during trait solving. This either
diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs
index b7f6ef4..499e6d3 100644
--- a/compiler/rustc_type_ir/src/ty_kind.rs
+++ b/compiler/rustc_type_ir/src/ty_kind.rs
@@ -861,7 +861,11 @@
 pub struct FnSig<I: Interner> {
     pub inputs_and_output: I::Tys,
     pub c_variadic: bool,
+    #[type_visitable(ignore)]
+    #[type_foldable(identity)]
     pub safety: I::Safety,
+    #[type_visitable(ignore)]
+    #[type_foldable(identity)]
     pub abi: I::Abi,
 }
 
diff --git a/compiler/rustc_type_ir/src/ty_kind/closure.rs b/compiler/rustc_type_ir/src/ty_kind/closure.rs
index 09a43b1..10b164e 100644
--- a/compiler/rustc_type_ir/src/ty_kind/closure.rs
+++ b/compiler/rustc_type_ir/src/ty_kind/closure.rs
@@ -372,8 +372,12 @@
     /// Always false
     pub c_variadic: bool,
     /// Always `Normal` (safe)
+    #[type_visitable(ignore)]
+    #[type_foldable(identity)]
     pub safety: I::Safety,
     /// Always `RustCall`
+    #[type_visitable(ignore)]
+    #[type_foldable(identity)]
     pub abi: I::Abi,
 }
 
diff --git a/compiler/rustc_type_ir_macros/src/lib.rs b/compiler/rustc_type_ir_macros/src/lib.rs
index 1a0a247..aaf69e2 100644
--- a/compiler/rustc_type_ir_macros/src/lib.rs
+++ b/compiler/rustc_type_ir_macros/src/lib.rs
@@ -1,18 +1,73 @@
-use quote::quote;
-use syn::parse_quote;
+use quote::{ToTokens, quote};
 use syn::visit_mut::VisitMut;
+use syn::{Attribute, parse_quote};
 use synstructure::decl_derive;
 
 decl_derive!(
-    [TypeFoldable_Generic] => type_foldable_derive
+    [TypeVisitable_Generic, attributes(type_visitable)] => type_visitable_derive
 );
 decl_derive!(
-    [TypeVisitable_Generic] => type_visitable_derive
+    [TypeFoldable_Generic, attributes(type_foldable)] => type_foldable_derive
 );
 decl_derive!(
     [Lift_Generic] => lift_derive
 );
 
+fn has_ignore_attr(attrs: &[Attribute], name: &'static str, meta: &'static str) -> bool {
+    let mut ignored = false;
+    attrs.iter().for_each(|attr| {
+        if !attr.path().is_ident(name) {
+            return;
+        }
+        let _ = attr.parse_nested_meta(|nested| {
+            if nested.path.is_ident(meta) {
+                ignored = true;
+            }
+            Ok(())
+        });
+    });
+
+    ignored
+}
+
+fn type_visitable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
+    if let syn::Data::Union(_) = s.ast().data {
+        panic!("cannot derive on union")
+    }
+
+    if !s.ast().generics.type_params().any(|ty| ty.ident == "I") {
+        s.add_impl_generic(parse_quote! { I });
+    }
+
+    s.filter(|bi| !has_ignore_attr(&bi.ast().attrs, "type_visitable", "ignore"));
+
+    s.add_where_predicate(parse_quote! { I: Interner });
+    s.add_bounds(synstructure::AddBounds::Fields);
+    let body_visit = s.each(|bind| {
+        quote! {
+            match ::rustc_ast_ir::visit::VisitorResult::branch(
+                ::rustc_type_ir::visit::TypeVisitable::visit_with(#bind, __visitor)
+            ) {
+                ::core::ops::ControlFlow::Continue(()) => {},
+                ::core::ops::ControlFlow::Break(r) => {
+                    return ::rustc_ast_ir::visit::VisitorResult::from_residual(r);
+                },
+            }
+        }
+    });
+    s.bind_with(|_| synstructure::BindStyle::Move);
+
+    s.bound_impl(quote!(::rustc_type_ir::visit::TypeVisitable<I>), quote! {
+        fn visit_with<__V: ::rustc_type_ir::visit::TypeVisitor<I>>(
+            &self,
+            __visitor: &mut __V
+        ) -> __V::Result {
+            match *self { #body_visit }
+            <__V::Result as ::rustc_ast_ir::visit::VisitorResult>::output()
+        }
+    })
+}
+
 fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
     if let syn::Data::Union(_) = s.ast().data {
         panic!("cannot derive on union")
@@ -29,12 +84,23 @@
         let bindings = vi.bindings();
         vi.construct(|_, index| {
             let bind = &bindings[index];
-            quote! {
-                ::rustc_type_ir::fold::TypeFoldable::try_fold_with(#bind, __folder)?
+
+            // retain value of fields with #[type_foldable(identity)]
+            if has_ignore_attr(&bind.ast().attrs, "type_foldable", "identity") {
+                bind.to_token_stream()
+            } else {
+                quote! {
+                    ::rustc_type_ir::fold::TypeFoldable::try_fold_with(#bind, __folder)?
+                }
             }
         })
     });
 
+    // We filter fields which get ignored and don't require them to implement
+    // `TypeFoldable`. We do so after generating `body_fold` as we still need
+    // to generate code for them.
+    s.filter(|bi| !has_ignore_attr(&bi.ast().attrs, "type_foldable", "identity"));
+    s.add_bounds(synstructure::AddBounds::Fields);
     s.bound_impl(quote!(::rustc_type_ir::fold::TypeFoldable<I>), quote! {
         fn try_fold_with<__F: ::rustc_type_ir::fold::FallibleTypeFolder<I>>(
             self,
@@ -113,39 +179,3 @@
 
     ty
 }
-
-fn type_visitable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
-    if let syn::Data::Union(_) = s.ast().data {
-        panic!("cannot derive on union")
-    }
-
-    if !s.ast().generics.type_params().any(|ty| ty.ident == "I") {
-        s.add_impl_generic(parse_quote! { I });
-    }
-
-    s.add_where_predicate(parse_quote! { I: Interner });
-    s.add_bounds(synstructure::AddBounds::Fields);
-    let body_visit = s.each(|bind| {
-        quote! {
-            match ::rustc_ast_ir::visit::VisitorResult::branch(
-                ::rustc_type_ir::visit::TypeVisitable::visit_with(#bind, __visitor)
-            ) {
-                ::core::ops::ControlFlow::Continue(()) => {},
-                ::core::ops::ControlFlow::Break(r) => {
-                    return ::rustc_ast_ir::visit::VisitorResult::from_residual(r);
-                },
-            }
-        }
-    });
-    s.bind_with(|_| synstructure::BindStyle::Move);
-
-    s.bound_impl(quote!(::rustc_type_ir::visit::TypeVisitable<I>), quote! {
-        fn visit_with<__V: ::rustc_type_ir::visit::TypeVisitor<I>>(
-            &self,
-            __visitor: &mut __V
-        ) -> __V::Result {
-            match *self { #body_visit }
-            <__V::Result as ::rustc_ast_ir::visit::VisitorResult>::output()
-        }
-    })
-}
diff --git a/compiler/stable_mir/README.md b/compiler/stable_mir/README.md
index 31dee95..ab2546e 100644
--- a/compiler/stable_mir/README.md
+++ b/compiler/stable_mir/README.md
@@ -1,93 +1,33 @@
-This crate is regularly synced with its mirror in the rustc repo at `compiler/rustc_smir`.
+This crate is currently developed in-tree together with the compiler.
 
-We use `git subtree` for this to preserve commits and allow the rustc repo to
-edit these crates without having to touch this repo. This keeps the crates compiling
-while allowing us to independently work on them here. The effort of keeping them in
-sync is pushed entirely onto us, without affecting rustc workflows negatively.
-This may change in the future, but changes to policy should only be done via a
-compiler team MCP.
+Our goal is to start publishing `stable_mir` into crates.io.
+Until then, users will use this as any other rustc crate, by installing
+the rustup component `rustc-dev`, and declaring `stable-mir` as an external crate.
 
-## Instructions for working on this crate locally
-
-Since the crate is the same in the rustc repo and here, the dependencies on rustc_* crates
-will only either work here or there, but never in both places at the same time. Thus we use
-optional dependencies on the rustc_* crates, requiring local development to use
-
-```
-cargo build --no-default-features -Zavoid-dev-deps
-```
-
-in order to compile successfully.
-
-## Instructions for syncing
-
-### Updating this repository
-
-In the rustc repo, execute
-
-```
-git subtree push --prefix=compiler/rustc_smir url_to_your_fork_of_project_stable_mir some_feature_branch
-```
-
-and then open a PR of your `some_feature_branch` against https://github.com/rust-lang/project-stable-mir
-
-### Updating the rustc library
-
-First we need to bump our stack limit, as the rustc repo otherwise quickly hits that:
-
-```
-ulimit -s 60000
-```
-
-#### Maximum function recursion depth (1000) reached
-
-Then we need to disable `dash` as the default shell for sh scripts, as otherwise we run into a
-hard limit of a recursion depth of 1000:
-
-```
-sudo dpkg-reconfigure dash
-```
-
-and then select `No` to disable dash.
-
-
-#### Patching your `git worktree`
-
-The regular git worktree does not scale to repos of the size of the rustc repo.
-So download the `git-subtree.sh` from https://github.com/gitgitgadget/git/pull/493/files and run
-
-```
-sudo cp --backup /path/to/patched/git-subtree.sh /usr/lib/git-core/git-subtree
-sudo chmod --reference=/usr/lib/git-core/git-subtree~ /usr/lib/git-core/git-subtree
-sudo chown --reference=/usr/lib/git-core/git-subtree~ /usr/lib/git-core/git-subtree
-```
-
-#### Actually doing a sync
-
-In the rustc repo, execute
-
-```
-git subtree pull --prefix=compiler/rustc_smir https://github.com/rust-lang/project-stable-mir smir
-```
-
-Note: only ever sync to rustc from the project-stable-mir's `smir` branch. Do not sync with your own forks.
-
-Then open a PR against rustc just like a regular PR.
+See the StableMIR ["Getting Started"](https://rust-lang.github.io/project-stable-mir/getting-started.html)
+guide for more information.
 
 ## Stable MIR Design
 
-The stable-mir will follow a similar approach to proc-macro2. It’s
-implementation will eventually be broken down into two main crates:
+The stable-mir will follow a similar approach to proc-macro2. Its
+implementation is split between two main crates:
 
 - `stable_mir`: Public crate, to be published on crates.io, which will contain
-the stable data structure as well as proxy APIs to make calls to the
-compiler.
-- `rustc_smir`: The compiler crate that will translate from internal MIR to
-SMIR. This crate will also implement APIs that will be invoked by
-stable-mir to query the compiler for more information.
+the stable data structure as well as calls to `rustc_smir` APIs. The
+translation between stable and internal constructs will also be done in this crate,
+however, this is currently implemented in the `rustc_smir` crate.[^translation].
+- `rustc_smir`: This crate implements the public APIs to the compiler.
+It is responsible for gathering all the information requested, and providing
+the data in its unstable form.
 
-This will help tools to communicate with the rust compiler via stable APIs. Tools will depend on
-`stable_mir` crate, which will invoke the compiler using APIs defined in `rustc_smir`. I.e.:
+[^translation]: This is currently implemented in the `rustc_smir` crate,
+but we are working to change that.
+
+I.e.,
+tools will depend on `stable_mir` crate,
+which will invoke the compiler using APIs defined in `rustc_smir`.
+
+I.e.:
 
 ```
     ┌──────────────────────────────────┐           ┌──────────────────────────────────┐
@@ -104,9 +44,3 @@
 
 More details can be found here:
 https://hackmd.io/XhnYHKKuR6-LChhobvlT-g?view
-
-For now, the code for these two crates are in separate modules of this crate.
-The modules have the same name for simplicity. We also have a third module,
-`rustc_internal` which will expose APIs and definitions that allow users to
-gather information from internal MIR constructs that haven't been exposed in
-the `stable_mir` module.
diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs
index 9e6fbc8..8db1258 100644
--- a/compiler/stable_mir/src/ty.rs
+++ b/compiler/stable_mir/src/ty.rs
@@ -1393,7 +1393,6 @@
     pub param_def_id_to_index: Vec<(GenericDef, u32)>,
     pub has_self: bool,
     pub has_late_bound_regions: Option<Span>,
-    pub host_effect_index: Option<usize>,
 }
 
 #[derive(Clone, Debug, Eq, PartialEq, Serialize)]
diff --git a/config.example.toml b/config.example.toml
index 168ac35..d5b904e 100644
--- a/config.example.toml
+++ b/config.example.toml
@@ -84,6 +84,9 @@
 # Wheter to build Enzyme as AutoDiff backend.
 #enzyme = false
 
+# Whether to build LLVM with support for it's gpu offload runtime.
+#offload = false
+
 # Indicates whether ccache is used when building LLVM. Set to `true` to use the first `ccache` in
 # PATH, or set an absolute path to use a specific version.
 #ccache = false
@@ -419,6 +422,9 @@
 # passed to cargo invocations.
 #jobs = 0
 
+# What custom diff tool to use for displaying compiletest tests.
+#compiletest-diff-tool = <none>
+
 # =============================================================================
 # General install configuration options
 # =============================================================================
diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs
index 3e79141..bc35465 100644
--- a/library/alloc/src/boxed.rs
+++ b/library/alloc/src/boxed.rs
@@ -196,7 +196,7 @@
 use core::mem::{self, SizedTypeProperties};
 use core::ops::{
     AsyncFn, AsyncFnMut, AsyncFnOnce, CoerceUnsized, Coroutine, CoroutineState, Deref, DerefMut,
-    DerefPure, DispatchFromDyn, Receiver,
+    DerefPure, DispatchFromDyn, LegacyReceiver,
 };
 use core::pin::{Pin, PinCoerceUnsized};
 use core::ptr::{self, NonNull, Unique};
@@ -2378,8 +2378,8 @@
 #[unstable(feature = "deref_pure_trait", issue = "87121")]
 unsafe impl<T: ?Sized, A: Allocator> DerefPure for Box<T, A> {}
 
-#[unstable(feature = "receiver_trait", issue = "none")]
-impl<T: ?Sized, A: Allocator> Receiver for Box<T, A> {}
+#[unstable(feature = "legacy_receiver_trait", issue = "none")]
+impl<T: ?Sized, A: Allocator> LegacyReceiver for Box<T, A> {}
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<I: Iterator + ?Sized, A: Allocator> Iterator for Box<I, A> {
diff --git a/library/alloc/src/collections/binary_heap/tests.rs b/library/alloc/src/collections/binary_heap/tests.rs
index c183187..ad0a020 100644
--- a/library/alloc/src/collections/binary_heap/tests.rs
+++ b/library/alloc/src/collections/binary_heap/tests.rs
@@ -350,7 +350,7 @@
         mem::forget(it);
     }))
     .unwrap();
-    // Behaviour after leaking is explicitly unspecified and order is arbitrary,
+    // Behavior after leaking is explicitly unspecified and order is arbitrary,
     // so it's fine if these start failing, but probably worth knowing.
     assert!(q.is_empty());
     assert_eq!(a.dropped() + b.dropped() + c.dropped(), 1);
@@ -377,7 +377,7 @@
         mem::forget(it);
     }))
     .unwrap();
-    // Behaviour after leaking is explicitly unspecified,
+    // Behavior after leaking is explicitly unspecified,
     // so it's fine if these start failing, but probably worth knowing.
     assert_eq!(q.len(), 2);
     assert_eq!(a.dropped(), 0);
diff --git a/library/alloc/src/collections/btree/append.rs b/library/alloc/src/collections/btree/append.rs
index 4737293..d137d27 100644
--- a/library/alloc/src/collections/btree/append.rs
+++ b/library/alloc/src/collections/btree/append.rs
@@ -79,7 +79,7 @@
                 }
                 open_node.push(key, value, right_tree);
 
-                // Go down to the right-most leaf again.
+                // Go down to the rightmost leaf again.
                 cur_node = open_node.forget_type().last_leaf_edge().into_node();
             }
 
diff --git a/library/alloc/src/collections/btree/fix.rs b/library/alloc/src/collections/btree/fix.rs
index 95fb52b..09edea3 100644
--- a/library/alloc/src/collections/btree/fix.rs
+++ b/library/alloc/src/collections/btree/fix.rs
@@ -102,7 +102,7 @@
     pub fn fix_right_border_of_plentiful(&mut self) {
         let mut cur_node = self.borrow_mut();
         while let Internal(internal) = cur_node.force() {
-            // Check if right-most child is underfull.
+            // Check if rightmost child is underfull.
             let mut last_kv = internal.last_kv().consider_for_balancing();
             debug_assert!(last_kv.left_child_len() >= MIN_LEN * 2);
             let right_child_len = last_kv.right_child_len();
diff --git a/library/alloc/src/collections/btree/map/tests.rs b/library/alloc/src/collections/btree/map/tests.rs
index d0e4137..db16d82 100644
--- a/library/alloc/src/collections/btree/map/tests.rs
+++ b/library/alloc/src/collections/btree/map/tests.rs
@@ -1216,7 +1216,7 @@
         {
             let mut it = map.extract_if(|dummy, _| dummy.query(true));
             catch_unwind(AssertUnwindSafe(|| while it.next().is_some() {})).unwrap_err();
-            // Iterator behaviour after a panic is explicitly unspecified,
+            // Iterator behavior after a panic is explicitly unspecified,
             // so this is just the current implementation:
             let result = catch_unwind(AssertUnwindSafe(|| it.next()));
             assert!(matches!(result, Ok(None)));
diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs
index 5c513d3..2a853ef 100644
--- a/library/alloc/src/collections/btree/node.rs
+++ b/library/alloc/src/collections/btree/node.rs
@@ -1521,7 +1521,7 @@
                     right_node.val_area_mut(..count - 1),
                 );
 
-                // Move the left-most stolen pair to the parent.
+                // Move the leftmost stolen pair to the parent.
                 let k = left_node.key_area_mut(new_left_len).assume_init_read();
                 let v = left_node.val_area_mut(new_left_len).assume_init_read();
                 let (k, v) = self.parent.replace_kv(k, v);
@@ -1570,7 +1570,7 @@
 
             // Move leaf data.
             {
-                // Move the right-most stolen pair to the parent.
+                // Move the rightmost stolen pair to the parent.
                 let k = right_node.key_area_mut(count - 1).assume_init_read();
                 let v = right_node.val_area_mut(count - 1).assume_init_read();
                 let (k, v) = self.parent.replace_kv(k, v);
diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs
index 50a5f3c..dd9dfa3 100644
--- a/library/alloc/src/lib.rs
+++ b/library/alloc/src/lib.rs
@@ -129,6 +129,7 @@
 #![feature(iter_advance_by)]
 #![feature(iter_next_chunk)]
 #![feature(layout_for_ptr)]
+#![feature(legacy_receiver_trait)]
 #![feature(local_waker)]
 #![feature(maybe_uninit_slice)]
 #![feature(maybe_uninit_uninit_array_transpose)]
@@ -138,7 +139,6 @@
 #![feature(ptr_internals)]
 #![feature(ptr_metadata)]
 #![feature(ptr_sub_ptr)]
-#![feature(receiver_trait)]
 #![feature(set_ptr_value)]
 #![feature(sized_type_properties)]
 #![feature(slice_from_ptr_range)]
diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec.rs
index 45de061..85a9120 100644
--- a/library/alloc/src/raw_vec.rs
+++ b/library/alloc/src/raw_vec.rs
@@ -103,7 +103,7 @@
     /// `RawVec` with capacity `usize::MAX`. Useful for implementing
     /// delayed allocation.
     #[must_use]
-    #[rustc_const_stable(feature = "raw_vec_internals_const", since = "1.81")]
+    #[cfg_attr(bootstrap, rustc_const_stable(feature = "raw_vec_internals_const", since = "1.81"))]
     pub const fn new() -> Self {
         Self::new_in(Global)
     }
@@ -179,7 +179,7 @@
     /// Like `new`, but parameterized over the choice of allocator for
     /// the returned `RawVec`.
     #[inline]
-    #[rustc_const_stable(feature = "raw_vec_internals_const", since = "1.81")]
+    #[cfg_attr(bootstrap, rustc_const_stable(feature = "raw_vec_internals_const", since = "1.81"))]
     pub const fn new_in(alloc: A) -> Self {
         Self { inner: RawVecInner::new_in(alloc, align_of::<T>()), _marker: PhantomData }
     }
@@ -409,7 +409,7 @@
 
 impl<A: Allocator> RawVecInner<A> {
     #[inline]
-    #[rustc_const_stable(feature = "raw_vec_internals_const", since = "1.81")]
+    #[cfg_attr(bootstrap, rustc_const_stable(feature = "raw_vec_internals_const", since = "1.81"))]
     const fn new_in(alloc: A, align: usize) -> Self {
         let ptr = unsafe { core::mem::transmute(align) };
         // `cap: 0` means "unallocated". zero-sized types are ignored.
diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs
index e98ae7c..9fdd51c 100644
--- a/library/alloc/src/rc.rs
+++ b/library/alloc/src/rc.rs
@@ -252,7 +252,7 @@
 use core::iter;
 use core::marker::{PhantomData, Unsize};
 use core::mem::{self, ManuallyDrop, align_of_val_raw};
-use core::ops::{CoerceUnsized, Deref, DerefMut, DerefPure, DispatchFromDyn, Receiver};
+use core::ops::{CoerceUnsized, Deref, DerefMut, DerefPure, DispatchFromDyn, LegacyReceiver};
 use core::panic::{RefUnwindSafe, UnwindSafe};
 #[cfg(not(no_global_oom_handling))]
 use core::pin::Pin;
@@ -2222,8 +2222,8 @@
 #[unstable(feature = "deref_pure_trait", issue = "87121")]
 unsafe impl<T: ?Sized, A: Allocator> DerefPure for Rc<T, A> {}
 
-#[unstable(feature = "receiver_trait", issue = "none")]
-impl<T: ?Sized> Receiver for Rc<T> {}
+#[unstable(feature = "legacy_receiver_trait", issue = "none")]
+impl<T: ?Sized> LegacyReceiver for Rc<T> {}
 
 #[stable(feature = "rust1", since = "1.0.0")]
 unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for Rc<T, A> {
@@ -2312,7 +2312,16 @@
     /// ```
     #[inline]
     fn default() -> Rc<T> {
-        Rc::new(Default::default())
+        unsafe {
+            Self::from_inner(
+                Box::leak(Box::write(Box::new_uninit(), RcInner {
+                    strong: Cell::new(1),
+                    weak: Cell::new(1),
+                    value: T::default(),
+                }))
+                .into(),
+            )
+        }
     }
 }
 
@@ -3066,7 +3075,7 @@
     ///
     /// drop(strong);
     /// // But not any more. We can do weak.as_ptr(), but accessing the pointer would lead to
-    /// // undefined behaviour.
+    /// // undefined behavior.
     /// // assert_eq!("hello", unsafe { &*weak.as_ptr() });
     /// ```
     ///
diff --git a/library/alloc/src/str.rs b/library/alloc/src/str.rs
index 52ceb8b..26c1ba2 100644
--- a/library/alloc/src/str.rs
+++ b/library/alloc/src/str.rs
@@ -269,8 +269,7 @@
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn replace<P: Pattern>(&self, from: P, to: &str) -> String {
-        // Fast path for ASCII to ASCII case.
-
+        // Fast path for replacing a single ASCII character with another.
         if let Some(from_byte) = match from.as_utf8_pattern() {
             Some(Utf8Pattern::StringPattern([from_byte])) => Some(*from_byte),
             Some(Utf8Pattern::CharPattern(c)) => c.as_ascii().map(|ascii_char| ascii_char.to_u8()),
@@ -280,8 +279,13 @@
                 return unsafe { replace_ascii(self.as_bytes(), from_byte, *to_byte) };
             }
         }
-
-        let mut result = String::new();
+        // Set result capacity to self.len() when from.len() <= to.len()
+        let default_capacity = match from.as_utf8_pattern() {
+            Some(Utf8Pattern::StringPattern(s)) if s.len() <= to.len() => self.len(),
+            Some(Utf8Pattern::CharPattern(c)) if c.len_utf8() <= to.len() => self.len(),
+            _ => 0,
+        };
+        let mut result = String::with_capacity(default_capacity);
         let mut last_end = 0;
         for (start, part) in self.match_indices(from) {
             result.push_str(unsafe { self.get_unchecked(last_end..start) });
diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs
index acbc325..15a1b0f 100644
--- a/library/alloc/src/sync.rs
+++ b/library/alloc/src/sync.rs
@@ -18,7 +18,7 @@
 use core::iter;
 use core::marker::{PhantomData, Unsize};
 use core::mem::{self, ManuallyDrop, align_of_val_raw};
-use core::ops::{CoerceUnsized, Deref, DerefPure, DispatchFromDyn, Receiver};
+use core::ops::{CoerceUnsized, Deref, DerefPure, DispatchFromDyn, LegacyReceiver};
 use core::panic::{RefUnwindSafe, UnwindSafe};
 use core::pin::{Pin, PinCoerceUnsized};
 use core::ptr::{self, NonNull};
@@ -804,7 +804,7 @@
             // observe a non-zero strong count. Therefore we need at least "Release" ordering
             // in order to synchronize with the `compare_exchange_weak` in `Weak::upgrade`.
             //
-            // "Acquire" ordering is not required. When considering the possible behaviours
+            // "Acquire" ordering is not required. When considering the possible behaviors
             // of `data_fn` we only need to look at what it could do with a reference to a
             // non-upgradeable `Weak`:
             // - It can *clone* the `Weak`, increasing the weak reference count.
@@ -2189,8 +2189,8 @@
 #[unstable(feature = "deref_pure_trait", issue = "87121")]
 unsafe impl<T: ?Sized, A: Allocator> DerefPure for Arc<T, A> {}
 
-#[unstable(feature = "receiver_trait", issue = "none")]
-impl<T: ?Sized> Receiver for Arc<T> {}
+#[unstable(feature = "legacy_receiver_trait", issue = "none")]
+impl<T: ?Sized> LegacyReceiver for Arc<T> {}
 
 #[cfg(not(no_global_oom_handling))]
 impl<T: ?Sized + CloneToUninit, A: Allocator + Clone> Arc<T, A> {
@@ -2788,7 +2788,7 @@
     ///
     /// drop(strong);
     /// // But not any more. We can do weak.as_ptr(), but accessing the pointer would lead to
-    /// // undefined behaviour.
+    /// // undefined behavior.
     /// // assert_eq!("hello", unsafe { &*weak.as_ptr() });
     /// ```
     ///
@@ -3447,13 +3447,16 @@
     /// assert_eq!(*x, 0);
     /// ```
     fn default() -> Arc<T> {
-        let x = Box::into_raw(Box::write(Box::new_uninit(), ArcInner {
-            strong: atomic::AtomicUsize::new(1),
-            weak: atomic::AtomicUsize::new(1),
-            data: T::default(),
-        }));
-        // SAFETY: `Box::into_raw` consumes the `Box` and never returns null
-        unsafe { Self::from_inner(NonNull::new_unchecked(x)) }
+        unsafe {
+            Self::from_inner(
+                Box::leak(Box::write(Box::new_uninit(), ArcInner {
+                    strong: atomic::AtomicUsize::new(1),
+                    weak: atomic::AtomicUsize::new(1),
+                    data: T::default(),
+                }))
+                .into(),
+            )
+        }
     }
 }
 
diff --git a/library/alloc/src/vec/is_zero.rs b/library/alloc/src/vec/is_zero.rs
index bcc5bf4..ba57d94 100644
--- a/library/alloc/src/vec/is_zero.rs
+++ b/library/alloc/src/vec/is_zero.rs
@@ -172,7 +172,7 @@
             fn is_zero(&self) -> bool {
                 // SAFETY: This is *not* a stable layout guarantee, but
                 // inside `core` we're allowed to rely on the current rustc
-                // behaviour that options of bools will be one byte with
+                // behavior that options of bools will be one byte with
                 // no padding, so long as they're nested less than 254 deep.
                 let raw: u8 = unsafe { core::mem::transmute(*self) };
                 raw == 0
diff --git a/library/alloc/tests/boxed.rs b/library/alloc/tests/boxed.rs
index bfc31a6..544f60d 100644
--- a/library/alloc/tests/boxed.rs
+++ b/library/alloc/tests/boxed.rs
@@ -4,6 +4,7 @@
 use core::ptr::NonNull;
 
 #[test]
+#[cfg_attr(not(bootstrap), expect(dangling_pointers_from_temporaries))]
 fn uninitialized_zero_size_box() {
     assert_eq!(
         &*Box::<()>::new_uninit() as *const _,
diff --git a/library/core/benches/lib.rs b/library/core/benches/lib.rs
index 3f1c58b..32d15c3 100644
--- a/library/core/benches/lib.rs
+++ b/library/core/benches/lib.rs
@@ -8,7 +8,6 @@
 #![feature(iter_array_chunks)]
 #![feature(iter_next_chunk)]
 #![feature(iter_advance_by)]
-#![feature(isqrt)]
 
 extern crate test;
 
diff --git a/library/core/src/alloc/global.rs b/library/core/src/alloc/global.rs
index 68f00d0..8f48af2 100644
--- a/library/core/src/alloc/global.rs
+++ b/library/core/src/alloc/global.rs
@@ -173,7 +173,7 @@
     /// # Safety
     ///
     /// The caller has to ensure that `layout` has non-zero size. Like `alloc`
-    /// zero sized `layout` can result in undefined behaviour.
+    /// zero sized `layout` can result in undefined behavior.
     /// However the allocated block of memory is guaranteed to be initialized.
     ///
     /// # Errors
@@ -234,7 +234,7 @@
     ///   does not overflow `isize` (i.e., the rounded value must be less than or
     ///   equal to `isize::MAX`).
     ///
-    /// If these are not followed, undefined behaviour can result.
+    /// If these are not followed, undefined behavior can result.
     ///
     /// (Extension subtraits might provide more specific bounds on
     /// behavior, e.g., guarantee a sentinel address or a null pointer
diff --git a/library/core/src/alloc/layout.rs b/library/core/src/alloc/layout.rs
index fca32b9..95cf942 100644
--- a/library/core/src/alloc/layout.rs
+++ b/library/core/src/alloc/layout.rs
@@ -66,7 +66,6 @@
     #[stable(feature = "alloc_layout", since = "1.28.0")]
     #[rustc_const_stable(feature = "const_alloc_layout_size_align", since = "1.50.0")]
     #[inline]
-    #[rustc_allow_const_fn_unstable(ptr_alignment_type)]
     pub const fn from_size_align(size: usize, align: usize) -> Result<Self, LayoutError> {
         if Layout::is_size_align_valid(size, align) {
             // SAFETY: Layout::is_size_align_valid checks the preconditions for this call.
@@ -127,7 +126,6 @@
     #[rustc_const_stable(feature = "const_alloc_layout_unchecked", since = "1.36.0")]
     #[must_use]
     #[inline]
-    #[rustc_allow_const_fn_unstable(ptr_alignment_type)]
     pub const unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Self {
         assert_unsafe_precondition!(
             check_library_ub,
@@ -159,7 +157,7 @@
     #[must_use = "this returns the minimum alignment, \
                   without modifying the layout"]
     #[inline]
-    #[rustc_allow_const_fn_unstable(ptr_alignment_type)]
+    #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(ptr_alignment_type))]
     pub const fn align(&self) -> usize {
         self.align.as_usize()
     }
diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs
index e1fa432..7e6c042 100644
--- a/library/core/src/cell.rs
+++ b/library/core/src/cell.rs
@@ -304,6 +304,7 @@
 /// ```
 ///
 /// See the [module-level documentation](self) for more.
+#[cfg_attr(not(test), rustc_diagnostic_item = "Cell")]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[repr(transparent)]
 #[rustc_pub_transparent]
@@ -1221,7 +1222,7 @@
     /// Unlike `RefCell::borrow`, this method is unsafe because it does not
     /// return a `Ref`, thus leaving the borrow flag untouched. Mutably
     /// borrowing the `RefCell` while the reference returned by this method
-    /// is alive is undefined behaviour.
+    /// is alive is undefined behavior.
     ///
     /// # Examples
     ///
@@ -2287,6 +2288,7 @@
 
     /// Unwraps the value, consuming the cell.
     #[inline]
+    #[rustc_const_unstable(feature = "sync_unsafe_cell", issue = "95439")]
     pub const fn into_inner(self) -> T {
         self.value.into_inner()
     }
diff --git a/library/core/src/cell/lazy.rs b/library/core/src/cell/lazy.rs
index d323fbe..5ac3351 100644
--- a/library/core/src/cell/lazy.rs
+++ b/library/core/src/cell/lazy.rs
@@ -79,6 +79,7 @@
     /// assert_eq!(LazyCell::into_inner(lazy).ok(), Some("HELLO, WORLD!".to_string()));
     /// ```
     #[unstable(feature = "lazy_cell_into_inner", issue = "125623")]
+    #[rustc_const_unstable(feature = "lazy_cell_into_inner", issue = "125623")]
     pub const fn into_inner(this: Self) -> Result<T, F> {
         match this.state.into_inner() {
             State::Init(data) => Ok(data),
diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs
index 30c0fff..206bbf5 100644
--- a/library/core/src/char/methods.rs
+++ b/library/core/src/char/methods.rs
@@ -320,8 +320,9 @@
     /// '1'.is_digit(37);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_const_unstable(feature = "const_char_is_digit", issue = "132241")]
     #[inline]
-    pub fn is_digit(self, radix: u32) -> bool {
+    pub const fn is_digit(self, radix: u32) -> bool {
         self.to_digit(radix).is_some()
     }
 
@@ -1770,7 +1771,7 @@
 /// Panics if the buffer is not large enough.
 /// A buffer of length four is large enough to encode any `char`.
 #[unstable(feature = "char_internals", reason = "exposed only for libstd", issue = "none")]
-#[rustc_const_stable(feature = "const_char_encode_utf8", since = "1.83.0")]
+#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_char_encode_utf8", since = "1.83.0"))]
 #[doc(hidden)]
 #[inline]
 #[rustc_allow_const_fn_unstable(const_eval_select)]
diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs
index 4377b49..5a3b936 100644
--- a/library/core/src/cmp.rs
+++ b/library/core/src/cmp.rs
@@ -380,7 +380,7 @@
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
 #[stable(feature = "rust1", since = "1.0.0")]
 // This is a lang item only so that `BinOp::Cmp` in MIR can return it.
-// It has no special behaviour, but does require that the three variants
+// It has no special behavior, but does require that the three variants
 // `Less`/`Equal`/`Greater` remain `-1_i8`/`0_i8`/`+1_i8` respectively.
 #[lang = "Ordering"]
 #[repr(i8)]
diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs
index 15b00b9..93dd351 100644
--- a/library/core/src/ffi/c_str.rs
+++ b/library/core/src/ffi/c_str.rs
@@ -137,11 +137,11 @@
 
 // FIXME: const stability attributes should not be required here, I think
 impl FromBytesWithNulError {
-    #[rustc_const_stable(feature = "const_cstr_methods", since = "1.72.0")]
+    #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_cstr_methods", since = "1.72.0"))]
     const fn interior_nul(pos: usize) -> FromBytesWithNulError {
         FromBytesWithNulError { kind: FromBytesWithNulErrorKind::InteriorNul(pos) }
     }
-    #[rustc_const_stable(feature = "const_cstr_methods", since = "1.72.0")]
+    #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_cstr_methods", since = "1.72.0"))]
     const fn not_nul_terminated() -> FromBytesWithNulError {
         FromBytesWithNulError { kind: FromBytesWithNulErrorKind::NotNulTerminated }
     }
@@ -464,7 +464,9 @@
     /// behavior when `ptr` is used inside the `unsafe` block:
     ///
     /// ```no_run
-    /// # #![allow(unused_must_use)] #![allow(temporary_cstring_as_ptr)]
+    /// # #![allow(unused_must_use)]
+    /// # #![cfg_attr(bootstrap, expect(temporary_cstring_as_ptr))]
+    /// # #![cfg_attr(not(bootstrap), expect(dangling_pointers_from_temporaries))]
     /// use std::ffi::CString;
     ///
     /// // Do not do this:
@@ -730,7 +732,7 @@
 /// located within `isize::MAX` from `ptr`.
 #[inline]
 #[unstable(feature = "cstr_internals", issue = "none")]
-#[rustc_const_stable(feature = "const_cstr_from_ptr", since = "1.81.0")]
+#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_cstr_from_ptr", since = "1.81.0"))]
 #[rustc_allow_const_fn_unstable(const_eval_select)]
 const unsafe fn strlen(ptr: *const c_char) -> usize {
     const fn strlen_ct(s: *const c_char) -> usize {
diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs
index 4cbcfb0..f3b5423 100644
--- a/library/core/src/fmt/mod.rs
+++ b/library/core/src/fmt/mod.rs
@@ -333,7 +333,10 @@
 #[unstable(feature = "fmt_internals", issue = "none")]
 impl<'a> Arguments<'a> {
     #[inline]
-    #[rustc_const_unstable(feature = "const_fmt_arguments_new", issue = "none")]
+    #[cfg_attr(
+        bootstrap,
+        rustc_const_unstable(feature = "const_fmt_arguments_new", issue = "none")
+    )]
     pub const fn new_const<const N: usize>(pieces: &'a [&'static str; N]) -> Self {
         const { assert!(N <= 1) };
         Arguments { pieces, fmt: None, args: &[] }
@@ -438,6 +441,7 @@
     #[rustc_const_unstable(feature = "const_arguments_as_str", issue = "103900")]
     #[must_use]
     #[inline]
+    #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
     pub const fn as_str(&self) -> Option<&'static str> {
         match (self.pieces, self.args) {
             ([], []) => Some(""),
diff --git a/library/core/src/fmt/rt.rs b/library/core/src/fmt/rt.rs
index eee4a9e..af6f0da 100644
--- a/library/core/src/fmt/rt.rs
+++ b/library/core/src/fmt/rt.rs
@@ -94,11 +94,11 @@
 }
 
 #[rustc_diagnostic_item = "ArgumentMethods"]
-impl<'a> Argument<'a> {
+impl Argument<'_> {
     #[inline(always)]
-    fn new<'b, T>(x: &'b T, f: fn(&T, &mut Formatter<'_>) -> Result) -> Argument<'b> {
+    fn new<'a, T>(x: &'a T, f: fn(&T, &mut Formatter<'_>) -> Result) -> Argument<'a> {
         Argument {
-            // INVARIANT: this creates an `ArgumentType<'b>` from a `&'b T` and
+            // INVARIANT: this creates an `ArgumentType<'a>` from a `&'a T` and
             // a `fn(&T, ...)`, so the invariant is maintained.
             ty: ArgumentType::Placeholder {
                 value: NonNull::from(x).cast(),
@@ -110,43 +110,43 @@
     }
 
     #[inline(always)]
-    pub fn new_display<'b, T: Display>(x: &'b T) -> Argument<'b> {
+    pub fn new_display<T: Display>(x: &T) -> Argument<'_> {
         Self::new(x, Display::fmt)
     }
     #[inline(always)]
-    pub fn new_debug<'b, T: Debug>(x: &'b T) -> Argument<'b> {
+    pub fn new_debug<T: Debug>(x: &T) -> Argument<'_> {
         Self::new(x, Debug::fmt)
     }
     #[inline(always)]
-    pub fn new_debug_noop<'b, T: Debug>(x: &'b T) -> Argument<'b> {
+    pub fn new_debug_noop<T: Debug>(x: &T) -> Argument<'_> {
         Self::new(x, |_, _| Ok(()))
     }
     #[inline(always)]
-    pub fn new_octal<'b, T: Octal>(x: &'b T) -> Argument<'b> {
+    pub fn new_octal<T: Octal>(x: &T) -> Argument<'_> {
         Self::new(x, Octal::fmt)
     }
     #[inline(always)]
-    pub fn new_lower_hex<'b, T: LowerHex>(x: &'b T) -> Argument<'b> {
+    pub fn new_lower_hex<T: LowerHex>(x: &T) -> Argument<'_> {
         Self::new(x, LowerHex::fmt)
     }
     #[inline(always)]
-    pub fn new_upper_hex<'b, T: UpperHex>(x: &'b T) -> Argument<'b> {
+    pub fn new_upper_hex<T: UpperHex>(x: &T) -> Argument<'_> {
         Self::new(x, UpperHex::fmt)
     }
     #[inline(always)]
-    pub fn new_pointer<'b, T: Pointer>(x: &'b T) -> Argument<'b> {
+    pub fn new_pointer<T: Pointer>(x: &T) -> Argument<'_> {
         Self::new(x, Pointer::fmt)
     }
     #[inline(always)]
-    pub fn new_binary<'b, T: Binary>(x: &'b T) -> Argument<'b> {
+    pub fn new_binary<T: Binary>(x: &T) -> Argument<'_> {
         Self::new(x, Binary::fmt)
     }
     #[inline(always)]
-    pub fn new_lower_exp<'b, T: LowerExp>(x: &'b T) -> Argument<'b> {
+    pub fn new_lower_exp<T: LowerExp>(x: &T) -> Argument<'_> {
         Self::new(x, LowerExp::fmt)
     }
     #[inline(always)]
-    pub fn new_upper_exp<'b, T: UpperExp>(x: &'b T) -> Argument<'b> {
+    pub fn new_upper_exp<T: UpperExp>(x: &T) -> Argument<'_> {
         Self::new(x, UpperExp::fmt)
     }
     #[inline(always)]
diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs
index a69f0af..78df51f 100644
--- a/library/core/src/hint.rs
+++ b/library/core/src/hint.rs
@@ -506,7 +506,7 @@
 ///   # }
 ///   ```
 #[unstable(feature = "hint_must_use", issue = "94745")]
-#[rustc_const_unstable(feature = "hint_must_use", issue = "94745")]
+#[cfg_attr(bootstrap, rustc_const_unstable(feature = "hint_must_use", issue = "94745"))]
 #[must_use] // <-- :)
 #[inline(always)]
 pub const fn must_use<T>(value: T) -> T {
diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs
index 97e7276..fc09da7 100644
--- a/library/core/src/intrinsics.rs
+++ b/library/core/src/intrinsics.rs
@@ -14,9 +14,10 @@
 //! `#[rustc_const_unstable(feature = "const_such_and_such", issue = "01234")]` to the intrinsic declaration.
 //!
 //! If an intrinsic is supposed to be used from a `const fn` with a `rustc_const_stable` attribute,
-//! the intrinsic's attribute must be `rustc_const_stable`, too. Such a change should not be done
-//! without T-lang consultation, because it bakes a feature into the language that cannot be
-//! replicated in user code without compiler support.
+//! `#[rustc_const_stable_indirect]` needs to be added to the intrinsic (`#[rustc_const_unstable]`
+//! can be removed then). Such a change should not be done without T-lang consultation, because it
+//! may bake a feature into the language that cannot be replicated in user code without compiler
+//! support.
 //!
 //! # Volatiles
 //!
@@ -930,7 +931,7 @@
     /// on most platforms.
     /// On Unix, the
     /// process will probably terminate with a signal like `SIGABRT`, `SIGILL`, `SIGTRAP`, `SIGSEGV` or
-    /// `SIGBUS`.  The precise behaviour is not guaranteed and not stable.
+    /// `SIGBUS`.  The precise behavior is not guaranteed and not stable.
     #[rustc_safe_intrinsic]
     #[rustc_nounwind]
     pub fn abort() -> !;
@@ -943,7 +944,11 @@
     /// reach code marked with this function.
     ///
     /// The stabilized version of this intrinsic is [`core::hint::unreachable_unchecked`].
-    #[rustc_const_stable(feature = "const_unreachable_unchecked", since = "1.57.0")]
+    #[cfg_attr(
+        bootstrap,
+        rustc_const_stable(feature = "const_unreachable_unchecked", since = "1.57.0")
+    )]
+    #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
     #[rustc_nounwind]
     pub fn unreachable() -> !;
 }
@@ -958,7 +963,8 @@
 /// own, or if it does not enable any significant optimizations.
 ///
 /// The stabilized version of this intrinsic is [`core::hint::assert_unchecked`].
-#[rustc_const_stable(feature = "const_assume", since = "1.77.0")]
+#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_assume", since = "1.77.0"))]
+#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
 #[rustc_nounwind]
 #[unstable(feature = "core_intrinsics", issue = "none")]
 #[rustc_intrinsic]
@@ -980,7 +986,11 @@
 /// any safety invariants.
 ///
 /// This intrinsic does not have a stable counterpart.
-#[rustc_const_unstable(feature = "const_likely", issue = "none")]
+#[cfg_attr(
+    bootstrap,
+    rustc_const_stable(feature = "const_likely", since = "CURRENT_RUSTC_VERSION")
+)]
+#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
 #[unstable(feature = "core_intrinsics", issue = "none")]
 #[rustc_intrinsic]
 #[rustc_nounwind]
@@ -1000,7 +1010,11 @@
 /// any safety invariants.
 ///
 /// This intrinsic does not have a stable counterpart.
-#[rustc_const_unstable(feature = "const_likely", issue = "none")]
+#[cfg_attr(
+    bootstrap,
+    rustc_const_stable(feature = "const_likely", since = "CURRENT_RUSTC_VERSION")
+)]
+#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
 #[unstable(feature = "core_intrinsics", issue = "none")]
 #[rustc_intrinsic]
 #[rustc_nounwind]
@@ -1041,7 +1055,8 @@
     /// This will statically either panic, or do nothing.
     ///
     /// This intrinsic does not have a stable counterpart.
-    #[rustc_const_stable(feature = "const_assert_type", since = "1.59.0")]
+    #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_assert_type", since = "1.59.0"))]
+    #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
     #[rustc_safe_intrinsic]
     #[rustc_nounwind]
     pub fn assert_inhabited<T>();
@@ -1050,7 +1065,8 @@
     /// zero-initialization: This will statically either panic, or do nothing.
     ///
     /// This intrinsic does not have a stable counterpart.
-    #[rustc_const_stable(feature = "const_assert_type2", since = "1.75.0")]
+    #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_assert_type2", since = "1.75.0"))]
+    #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
     #[rustc_safe_intrinsic]
     #[rustc_nounwind]
     pub fn assert_zero_valid<T>();
@@ -1058,7 +1074,8 @@
     /// A guard for `std::mem::uninitialized`. This will statically either panic, or do nothing.
     ///
     /// This intrinsic does not have a stable counterpart.
-    #[rustc_const_stable(feature = "const_assert_type2", since = "1.75.0")]
+    #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_assert_type2", since = "1.75.0"))]
+    #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
     #[rustc_safe_intrinsic]
     #[rustc_nounwind]
     pub fn assert_mem_uninitialized_valid<T>();
@@ -1071,7 +1088,8 @@
     /// any safety invariants.
     ///
     /// Consider using [`core::panic::Location::caller`] instead.
-    #[rustc_const_stable(feature = "const_caller_location", since = "1.79.0")]
+    #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_caller_location", since = "1.79.0"))]
+    #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
     #[rustc_safe_intrinsic]
     #[rustc_nounwind]
     pub fn caller_location() -> &'static crate::panic::Location<'static>;
@@ -1085,7 +1103,8 @@
     /// it does not require an `unsafe` block.
     /// Therefore, implementations must not require the user to uphold
     /// any safety invariants.
-    #[rustc_const_stable(feature = "const_intrinsic_forget", since = "1.83.0")]
+    #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_intrinsic_forget", since = "1.83.0"))]
+    #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
     #[rustc_safe_intrinsic]
     #[rustc_nounwind]
     pub fn forget<T: ?Sized>(_: T);
@@ -1384,14 +1403,15 @@
 
     /// Like [`transmute`], but even less checked at compile-time: rather than
     /// giving an error for `size_of::<Src>() != size_of::<Dst>()`, it's
-    /// **Undefined Behaviour** at runtime.
+    /// **Undefined Behavior** at runtime.
     ///
     /// Prefer normal `transmute` where possible, for the extra checking, since
     /// both do exactly the same thing at runtime, if they both compile.
     ///
     /// This is not expected to ever be exposed directly to users, rather it
     /// may eventually be exposed through some more-constrained API.
-    #[rustc_const_stable(feature = "const_transmute", since = "1.56.0")]
+    #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_transmute", since = "1.56.0"))]
+    #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
     #[rustc_nounwind]
     pub fn transmute_unchecked<Src, Dst>(src: Src) -> Dst;
 
@@ -1408,7 +1428,8 @@
     /// any safety invariants.
     ///
     /// The stabilized version of this intrinsic is [`mem::needs_drop`](crate::mem::needs_drop).
-    #[rustc_const_stable(feature = "const_needs_drop", since = "1.40.0")]
+    #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_needs_drop", since = "1.40.0"))]
+    #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
     #[rustc_safe_intrinsic]
     #[rustc_nounwind]
     pub fn needs_drop<T: ?Sized>() -> bool;
@@ -1430,7 +1451,8 @@
     ///
     /// The stabilized version of this intrinsic is [`pointer::offset`].
     #[must_use = "returns a new pointer rather than modifying its argument"]
-    #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")]
+    #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0"))]
+    #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
     #[rustc_nounwind]
     pub fn offset<Ptr, Delta>(dst: Ptr, offset: Delta) -> Ptr;
 
@@ -1448,7 +1470,8 @@
     ///
     /// The stabilized version of this intrinsic is [`pointer::wrapping_offset`].
     #[must_use = "returns a new pointer rather than modifying its argument"]
-    #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")]
+    #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0"))]
+    #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
     #[rustc_nounwind]
     pub fn arith_offset<T>(dst: *const T, offset: isize) -> *const T;
 
@@ -2131,7 +2154,8 @@
     /// The stabilized versions of this intrinsic are available on the integer
     /// primitives via the `count_ones` method. For example,
     /// [`u32::count_ones`]
-    #[rustc_const_stable(feature = "const_ctpop", since = "1.40.0")]
+    #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ctpop", since = "1.40.0"))]
+    #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
     #[rustc_safe_intrinsic]
     #[rustc_nounwind]
     pub fn ctpop<T: Copy>(x: T) -> u32;
@@ -2172,7 +2196,8 @@
     /// let num_leading = ctlz(x);
     /// assert_eq!(num_leading, 16);
     /// ```
-    #[rustc_const_stable(feature = "const_ctlz", since = "1.40.0")]
+    #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ctlz", since = "1.40.0"))]
+    #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
     #[rustc_safe_intrinsic]
     #[rustc_nounwind]
     pub fn ctlz<T: Copy>(x: T) -> u32;
@@ -2194,7 +2219,8 @@
     /// let num_leading = unsafe { ctlz_nonzero(x) };
     /// assert_eq!(num_leading, 3);
     /// ```
-    #[rustc_const_stable(feature = "constctlz", since = "1.50.0")]
+    #[cfg_attr(bootstrap, rustc_const_stable(feature = "constctlz", since = "1.50.0"))]
+    #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
     #[rustc_nounwind]
     pub fn ctlz_nonzero<T: Copy>(x: T) -> u32;
 
@@ -2234,7 +2260,8 @@
     /// let num_trailing = cttz(x);
     /// assert_eq!(num_trailing, 16);
     /// ```
-    #[rustc_const_stable(feature = "const_cttz", since = "1.40.0")]
+    #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_cttz", since = "1.40.0"))]
+    #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
     #[rustc_safe_intrinsic]
     #[rustc_nounwind]
     pub fn cttz<T: Copy>(x: T) -> u32;
@@ -2256,7 +2283,8 @@
     /// let num_trailing = unsafe { cttz_nonzero(x) };
     /// assert_eq!(num_trailing, 3);
     /// ```
-    #[rustc_const_stable(feature = "const_cttz_nonzero", since = "1.53.0")]
+    #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_cttz_nonzero", since = "1.53.0"))]
+    #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
     #[rustc_nounwind]
     pub fn cttz_nonzero<T: Copy>(x: T) -> u32;
 
@@ -2270,7 +2298,8 @@
     /// The stabilized versions of this intrinsic are available on the integer
     /// primitives via the `swap_bytes` method. For example,
     /// [`u32::swap_bytes`]
-    #[rustc_const_stable(feature = "const_bswap", since = "1.40.0")]
+    #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_bswap", since = "1.40.0"))]
+    #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
     #[rustc_safe_intrinsic]
     #[rustc_nounwind]
     pub fn bswap<T: Copy>(x: T) -> T;
@@ -2285,7 +2314,8 @@
     /// The stabilized versions of this intrinsic are available on the integer
     /// primitives via the `reverse_bits` method. For example,
     /// [`u32::reverse_bits`]
-    #[rustc_const_stable(feature = "const_bitreverse", since = "1.40.0")]
+    #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_bitreverse", since = "1.40.0"))]
+    #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
     #[rustc_safe_intrinsic]
     #[rustc_nounwind]
     pub fn bitreverse<T: Copy>(x: T) -> T;
@@ -2311,7 +2341,8 @@
     /// The stabilized versions of this intrinsic are available on the integer
     /// primitives via the `overflowing_add` method. For example,
     /// [`u32::overflowing_add`]
-    #[rustc_const_stable(feature = "const_int_overflow", since = "1.40.0")]
+    #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_overflow", since = "1.40.0"))]
+    #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
     #[rustc_safe_intrinsic]
     #[rustc_nounwind]
     pub fn add_with_overflow<T: Copy>(x: T, y: T) -> (T, bool);
@@ -2326,7 +2357,8 @@
     /// The stabilized versions of this intrinsic are available on the integer
     /// primitives via the `overflowing_sub` method. For example,
     /// [`u32::overflowing_sub`]
-    #[rustc_const_stable(feature = "const_int_overflow", since = "1.40.0")]
+    #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_overflow", since = "1.40.0"))]
+    #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
     #[rustc_safe_intrinsic]
     #[rustc_nounwind]
     pub fn sub_with_overflow<T: Copy>(x: T, y: T) -> (T, bool);
@@ -2341,7 +2373,8 @@
     /// The stabilized versions of this intrinsic are available on the integer
     /// primitives via the `overflowing_mul` method. For example,
     /// [`u32::overflowing_mul`]
-    #[rustc_const_stable(feature = "const_int_overflow", since = "1.40.0")]
+    #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_overflow", since = "1.40.0"))]
+    #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
     #[rustc_safe_intrinsic]
     #[rustc_nounwind]
     pub fn mul_with_overflow<T: Copy>(x: T, y: T) -> (T, bool);
@@ -2360,7 +2393,11 @@
     /// Safe wrappers for this intrinsic are available on the integer
     /// primitives via the `checked_div` method. For example,
     /// [`u32::checked_div`]
-    #[rustc_const_stable(feature = "const_int_unchecked_div", since = "1.52.0")]
+    #[cfg_attr(
+        bootstrap,
+        rustc_const_stable(feature = "const_int_unchecked_div", since = "1.52.0")
+    )]
+    #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
     #[rustc_nounwind]
     pub fn unchecked_div<T: Copy>(x: T, y: T) -> T;
     /// Returns the remainder of an unchecked division, resulting in
@@ -2369,7 +2406,11 @@
     /// Safe wrappers for this intrinsic are available on the integer
     /// primitives via the `checked_rem` method. For example,
     /// [`u32::checked_rem`]
-    #[rustc_const_stable(feature = "const_int_unchecked_rem", since = "1.52.0")]
+    #[cfg_attr(
+        bootstrap,
+        rustc_const_stable(feature = "const_int_unchecked_rem", since = "1.52.0")
+    )]
+    #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
     #[rustc_nounwind]
     pub fn unchecked_rem<T: Copy>(x: T, y: T) -> T;
 
@@ -2379,7 +2420,8 @@
     /// Safe wrappers for this intrinsic are available on the integer
     /// primitives via the `checked_shl` method. For example,
     /// [`u32::checked_shl`]
-    #[rustc_const_stable(feature = "const_int_unchecked", since = "1.40.0")]
+    #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_unchecked", since = "1.40.0"))]
+    #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
     #[rustc_nounwind]
     pub fn unchecked_shl<T: Copy, U: Copy>(x: T, y: U) -> T;
     /// Performs an unchecked right shift, resulting in undefined behavior when
@@ -2388,7 +2430,8 @@
     /// Safe wrappers for this intrinsic are available on the integer
     /// primitives via the `checked_shr` method. For example,
     /// [`u32::checked_shr`]
-    #[rustc_const_stable(feature = "const_int_unchecked", since = "1.40.0")]
+    #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_unchecked", since = "1.40.0"))]
+    #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
     #[rustc_nounwind]
     pub fn unchecked_shr<T: Copy, U: Copy>(x: T, y: U) -> T;
 
@@ -2397,7 +2440,8 @@
     ///
     /// The stable counterpart of this intrinsic is `unchecked_add` on the various
     /// integer types, such as [`u16::unchecked_add`] and [`i64::unchecked_add`].
-    #[rustc_const_stable(feature = "unchecked_math", since = "1.79.0")]
+    #[cfg_attr(bootstrap, rustc_const_stable(feature = "unchecked_math", since = "1.79.0"))]
+    #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
     #[rustc_nounwind]
     pub fn unchecked_add<T: Copy>(x: T, y: T) -> T;
 
@@ -2406,7 +2450,8 @@
     ///
     /// The stable counterpart of this intrinsic is `unchecked_sub` on the various
     /// integer types, such as [`u16::unchecked_sub`] and [`i64::unchecked_sub`].
-    #[rustc_const_stable(feature = "unchecked_math", since = "1.79.0")]
+    #[cfg_attr(bootstrap, rustc_const_stable(feature = "unchecked_math", since = "1.79.0"))]
+    #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
     #[rustc_nounwind]
     pub fn unchecked_sub<T: Copy>(x: T, y: T) -> T;
 
@@ -2415,7 +2460,8 @@
     ///
     /// The stable counterpart of this intrinsic is `unchecked_mul` on the various
     /// integer types, such as [`u16::unchecked_mul`] and [`i64::unchecked_mul`].
-    #[rustc_const_stable(feature = "unchecked_math", since = "1.79.0")]
+    #[cfg_attr(bootstrap, rustc_const_stable(feature = "unchecked_math", since = "1.79.0"))]
+    #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
     #[rustc_nounwind]
     pub fn unchecked_mul<T: Copy>(x: T, y: T) -> T;
 
@@ -2429,7 +2475,8 @@
     /// The stabilized versions of this intrinsic are available on the integer
     /// primitives via the `rotate_left` method. For example,
     /// [`u32::rotate_left`]
-    #[rustc_const_stable(feature = "const_int_rotate", since = "1.40.0")]
+    #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_rotate", since = "1.40.0"))]
+    #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
     #[rustc_safe_intrinsic]
     #[rustc_nounwind]
     pub fn rotate_left<T: Copy>(x: T, shift: u32) -> T;
@@ -2444,7 +2491,8 @@
     /// The stabilized versions of this intrinsic are available on the integer
     /// primitives via the `rotate_right` method. For example,
     /// [`u32::rotate_right`]
-    #[rustc_const_stable(feature = "const_int_rotate", since = "1.40.0")]
+    #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_rotate", since = "1.40.0"))]
+    #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
     #[rustc_safe_intrinsic]
     #[rustc_nounwind]
     pub fn rotate_right<T: Copy>(x: T, shift: u32) -> T;
@@ -2459,7 +2507,8 @@
     /// The stabilized versions of this intrinsic are available on the integer
     /// primitives via the `wrapping_add` method. For example,
     /// [`u32::wrapping_add`]
-    #[rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0")]
+    #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0"))]
+    #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
     #[rustc_safe_intrinsic]
     #[rustc_nounwind]
     pub fn wrapping_add<T: Copy>(a: T, b: T) -> T;
@@ -2473,7 +2522,8 @@
     /// The stabilized versions of this intrinsic are available on the integer
     /// primitives via the `wrapping_sub` method. For example,
     /// [`u32::wrapping_sub`]
-    #[rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0")]
+    #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0"))]
+    #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
     #[rustc_safe_intrinsic]
     #[rustc_nounwind]
     pub fn wrapping_sub<T: Copy>(a: T, b: T) -> T;
@@ -2487,7 +2537,8 @@
     /// The stabilized versions of this intrinsic are available on the integer
     /// primitives via the `wrapping_mul` method. For example,
     /// [`u32::wrapping_mul`]
-    #[rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0")]
+    #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0"))]
+    #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
     #[rustc_safe_intrinsic]
     #[rustc_nounwind]
     pub fn wrapping_mul<T: Copy>(a: T, b: T) -> T;
@@ -2502,7 +2553,8 @@
     /// The stabilized versions of this intrinsic are available on the integer
     /// primitives via the `saturating_add` method. For example,
     /// [`u32::saturating_add`]
-    #[rustc_const_stable(feature = "const_int_saturating", since = "1.40.0")]
+    #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_saturating", since = "1.40.0"))]
+    #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
     #[rustc_safe_intrinsic]
     #[rustc_nounwind]
     pub fn saturating_add<T: Copy>(a: T, b: T) -> T;
@@ -2516,7 +2568,8 @@
     /// The stabilized versions of this intrinsic are available on the integer
     /// primitives via the `saturating_sub` method. For example,
     /// [`u32::saturating_sub`]
-    #[rustc_const_stable(feature = "const_int_saturating", since = "1.40.0")]
+    #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_saturating", since = "1.40.0"))]
+    #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
     #[rustc_safe_intrinsic]
     #[rustc_nounwind]
     pub fn saturating_sub<T: Copy>(a: T, b: T) -> T;
@@ -2527,7 +2580,8 @@
     /// This intrinsic can *only* be called where the pointer is a local without
     /// projections (`read_via_copy(ptr)`, not `read_via_copy(*ptr)`) so that it
     /// trivially obeys runtime-MIR rules about derefs in operands.
-    #[rustc_const_stable(feature = "const_ptr_read", since = "1.71.0")]
+    #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_read", since = "1.71.0"))]
+    #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
     #[rustc_nounwind]
     pub fn read_via_copy<T>(ptr: *const T) -> T;
 
@@ -2537,7 +2591,8 @@
     /// This intrinsic can *only* be called where the pointer is a local without
     /// projections (`write_via_move(ptr, x)`, not `write_via_move(*ptr, x)`) so
     /// that it trivially obeys runtime-MIR rules about derefs in operands.
-    #[rustc_const_stable(feature = "const_ptr_write", since = "1.83.0")]
+    #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_write", since = "1.83.0"))]
+    #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
     #[rustc_nounwind]
     pub fn write_via_move<T>(ptr: *mut T, value: T);
 
@@ -2550,7 +2605,8 @@
     /// any safety invariants.
     ///
     /// The stabilized version of this intrinsic is [`core::mem::discriminant`].
-    #[rustc_const_stable(feature = "const_discriminant", since = "1.75.0")]
+    #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_discriminant", since = "1.75.0"))]
+    #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
     #[rustc_safe_intrinsic]
     #[rustc_nounwind]
     pub fn discriminant_value<T>(v: &T) -> <T as DiscriminantKind>::Discriminant;
@@ -2584,7 +2640,8 @@
     pub fn nontemporal_store<T>(ptr: *mut T, val: T);
 
     /// See documentation of `<*const T>::offset_from` for details.
-    #[rustc_const_stable(feature = "const_ptr_offset_from", since = "1.65.0")]
+    #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_offset_from", since = "1.65.0"))]
+    #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
     #[rustc_nounwind]
     pub fn ptr_offset_from<T>(ptr: *const T, base: *const T) -> isize;
 
@@ -2850,7 +2907,8 @@
 /// assertions are enabled whenever the *user crate* has UB checks enabled. However, if the
 /// user has UB checks disabled, the checks will still get optimized out. This intrinsic is
 /// primarily used by [`ub_checks::assert_unsafe_precondition`].
-#[rustc_const_unstable(feature = "const_ub_checks", issue = "none")]
+#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_ub_checks", issue = "none"))]
+#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] // just for UB checks
 #[unstable(feature = "core_intrinsics", issue = "none")]
 #[inline(always)]
 #[rustc_intrinsic]
@@ -2935,7 +2993,8 @@
 /// The stabilized version of this intrinsic is [`core::mem::size_of`].
 #[rustc_nounwind]
 #[unstable(feature = "core_intrinsics", issue = "none")]
-#[rustc_const_stable(feature = "const_size_of", since = "1.40.0")]
+#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_size_of", since = "1.40.0"))]
+#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
 #[rustc_intrinsic]
 #[rustc_intrinsic_must_be_overridden]
 pub const fn size_of<T>() -> usize {
@@ -2952,7 +3011,8 @@
 /// The stabilized version of this intrinsic is [`core::mem::align_of`].
 #[rustc_nounwind]
 #[unstable(feature = "core_intrinsics", issue = "none")]
-#[rustc_const_stable(feature = "const_min_align_of", since = "1.40.0")]
+#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_min_align_of", since = "1.40.0"))]
+#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
 #[rustc_intrinsic]
 #[rustc_intrinsic_must_be_overridden]
 pub const fn min_align_of<T>() -> usize {
@@ -3065,7 +3125,8 @@
 /// change the possible layouts of pointers.
 #[rustc_nounwind]
 #[unstable(feature = "core_intrinsics", issue = "none")]
-#[rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0")]
+#[cfg_attr(bootstrap, rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0"))]
+#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
 #[rustc_intrinsic]
 #[rustc_intrinsic_must_be_overridden]
 pub const fn aggregate_raw_ptr<P: AggregateRawPtr<D, Metadata = M>, D, M>(_data: D, _meta: M) -> P {
@@ -3090,7 +3151,11 @@
 /// This is used to implement functions like `ptr::metadata`.
 #[rustc_nounwind]
 #[unstable(feature = "core_intrinsics", issue = "none")]
-#[rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0")]
+#[cfg_attr(
+    bootstrap,
+    cfg_attr(bootstrap, rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0"))
+)]
+#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
 #[rustc_intrinsic]
 #[rustc_intrinsic_must_be_overridden]
 pub const fn ptr_metadata<P: ptr::Pointee<Metadata = M> + ?Sized, M>(_ptr: *const P) -> M {
@@ -3197,7 +3262,15 @@
 #[rustc_diagnostic_item = "ptr_copy_nonoverlapping"]
 pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize) {
     extern "rust-intrinsic" {
-        #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0")]
+        #[cfg_attr(
+            bootstrap,
+            rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0")
+        )]
+        #[cfg_attr(
+            not(bootstrap),
+            rustc_const_unstable(feature = "core_intrinsics", issue = "none")
+        )]
+        #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
         #[rustc_nounwind]
         pub fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
     }
@@ -3301,7 +3374,15 @@
 #[rustc_diagnostic_item = "ptr_copy"]
 pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
     extern "rust-intrinsic" {
-        #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0")]
+        #[cfg_attr(
+            bootstrap,
+            rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0")
+        )]
+        #[cfg_attr(
+            not(bootstrap),
+            rustc_const_unstable(feature = "core_intrinsics", issue = "none")
+        )]
+        #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
         #[rustc_nounwind]
         fn copy<T>(src: *const T, dst: *mut T, count: usize);
     }
@@ -3382,7 +3463,8 @@
 #[rustc_diagnostic_item = "ptr_write_bytes"]
 pub const unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize) {
     extern "rust-intrinsic" {
-        #[rustc_const_stable(feature = "const_ptr_write", since = "1.83.0")]
+        #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_write", since = "1.83.0"))]
+        #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
         #[rustc_nounwind]
         fn write_bytes<T>(dst: *mut T, val: u8, count: usize);
     }
@@ -3643,6 +3725,7 @@
 
 /// Inform Miri that a given pointer definitely has a certain alignment.
 #[cfg(miri)]
+#[rustc_allow_const_fn_unstable(const_eval_select)]
 pub(crate) const fn miri_promise_symbolic_alignment(ptr: *const (), align: usize) {
     extern "Rust" {
         /// Miri-provided extern function to promise that a given pointer is properly aligned for
diff --git a/library/core/src/intrinsics/mir.rs b/library/core/src/intrinsics/mir.rs
index a2ab39c..6539964 100644
--- a/library/core/src/intrinsics/mir.rs
+++ b/library/core/src/intrinsics/mir.rs
@@ -298,7 +298,7 @@
 );
 define!(
     "mir_unwind_unreachable",
-    /// An unwind action that triggers undefined behaviour.
+    /// An unwind action that triggers undefined behavior.
     fn UnwindUnreachable() -> UnwindActionArg
 );
 define!(
diff --git a/library/core/src/iter/adapters/mod.rs b/library/core/src/iter/adapters/mod.rs
index 6d30f35..2a0ef01 100644
--- a/library/core/src/iter/adapters/mod.rs
+++ b/library/core/src/iter/adapters/mod.rs
@@ -71,7 +71,7 @@
 /// this can be useful for specializing [`FromIterator`] implementations or recovering the
 /// remaining elements after an iterator has been partially exhausted.
 ///
-/// Note that implementations do not necessarily have to provide access to the inner-most
+/// Note that implementations do not necessarily have to provide access to the innermost
 /// source of a pipeline. A stateful intermediate adapter might eagerly evaluate a part
 /// of the pipeline and expose its internal storage as source.
 ///
diff --git a/library/core/src/iter/traits/collect.rs b/library/core/src/iter/traits/collect.rs
index 86660f2..2cf2ea5 100644
--- a/library/core/src/iter/traits/collect.rs
+++ b/library/core/src/iter/traits/collect.rs
@@ -346,7 +346,6 @@
     fn into_iter(self) -> Self::IntoIter;
 }
 
-#[rustc_const_unstable(feature = "const_intoiterator_identity", issue = "90603")]
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<I: Iterator> IntoIterator for I {
     type Item = I::Item;
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 1687756..74f7905 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -107,6 +107,7 @@
 //
 // Library features:
 // tidy-alphabetical-start
+#![cfg_attr(bootstrap, feature(const_fmt_arguments_new))]
 #![feature(array_ptr_get)]
 #![feature(asm_experimental_arch)]
 #![feature(const_align_of_val)]
@@ -121,11 +122,8 @@
 #![feature(const_eval_select)]
 #![feature(const_exact_div)]
 #![feature(const_float_methods)]
-#![feature(const_fmt_arguments_new)]
 #![feature(const_hash)]
 #![feature(const_heap)]
-#![feature(const_index_range_slice_index)]
-#![feature(const_likely)]
 #![feature(const_nonnull_new)]
 #![feature(const_num_midpoint)]
 #![feature(const_option_ext)]
@@ -136,6 +134,7 @@
 #![feature(const_raw_ptr_comparison)]
 #![feature(const_size_of_val)]
 #![feature(const_size_of_val_raw)]
+#![feature(const_sockaddr_setters)]
 #![feature(const_strict_overflow_ops)]
 #![feature(const_swap)]
 #![feature(const_try)]
@@ -144,13 +143,13 @@
 #![feature(const_typed_swap)]
 #![feature(const_ub_checks)]
 #![feature(const_unicode_case_lookup)]
+#![feature(core_intrinsics)]
 #![feature(coverage_attribute)]
 #![feature(do_not_recommend)]
 #![feature(internal_impls_macro)]
 #![feature(ip)]
 #![feature(is_ascii_octdigit)]
 #![feature(is_val_statically_known)]
-#![feature(isqrt)]
 #![feature(lazy_get)]
 #![feature(link_cfg)]
 #![feature(non_null_from_ref)]
@@ -159,6 +158,7 @@
 #![feature(ptr_alignment_type)]
 #![feature(ptr_metadata)]
 #![feature(set_ptr_value)]
+#![feature(slice_as_chunks)]
 #![feature(slice_ptr_get)]
 #![feature(str_internals)]
 #![feature(str_split_inclusive_remainder)]
diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs
index aed6be4..1c5c58d 100644
--- a/library/core/src/marker.rs
+++ b/library/core/src/marker.rs
@@ -1063,53 +1063,10 @@
 }
 
 /// Derive macro generating impls of traits related to smart pointers.
-#[rustc_builtin_macro(SmartPointer, attributes(pointee))]
+#[rustc_builtin_macro(CoercePointee, attributes(pointee))]
 #[allow_internal_unstable(dispatch_from_dyn, coerce_unsized, unsize)]
-#[unstable(feature = "derive_smart_pointer", issue = "123430")]
-pub macro SmartPointer($item:item) {
+#[unstable(feature = "derive_coerce_pointee", issue = "123430")]
+#[cfg(not(bootstrap))]
+pub macro CoercePointee($item:item) {
     /* compiler built-in */
 }
-
-// Support traits and types for the desugaring of const traits and
-// `~const` bounds. Not supposed to be used by anything other than
-// the compiler.
-#[doc(hidden)]
-#[unstable(
-    feature = "effect_types",
-    issue = "none",
-    reason = "internal module for implementing effects"
-)]
-#[allow(missing_debug_implementations)] // these unit structs don't need `Debug` impls.
-pub mod effects {
-    #[lang = "EffectsNoRuntime"]
-    pub struct NoRuntime;
-    #[lang = "EffectsMaybe"]
-    pub struct Maybe;
-    #[lang = "EffectsRuntime"]
-    pub struct Runtime;
-
-    #[lang = "EffectsCompat"]
-    pub trait Compat<#[rustc_runtime] const RUNTIME: bool> {}
-
-    impl Compat<false> for NoRuntime {}
-    impl Compat<true> for Runtime {}
-    impl<#[rustc_runtime] const RUNTIME: bool> Compat<RUNTIME> for Maybe {}
-
-    #[lang = "EffectsTyCompat"]
-    #[marker]
-    pub trait TyCompat<T: ?Sized> {}
-
-    impl<T: ?Sized> TyCompat<T> for T {}
-    impl<T: ?Sized> TyCompat<Maybe> for T {}
-
-    #[lang = "EffectsIntersection"]
-    pub trait Intersection {
-        #[lang = "EffectsIntersectionOutput"]
-        type Output: ?Sized;
-    }
-
-    // FIXME(effects): remove this after next trait solver lands
-    impl Intersection for () {
-        type Output = Maybe;
-    }
-}
diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs
index ea73cfc..b4252ef 100644
--- a/library/core/src/mem/maybe_uninit.rs
+++ b/library/core/src/mem/maybe_uninit.rs
@@ -723,7 +723,7 @@
     /// this does not constitute a stable guarantee), because the only
     /// requirement the compiler knows about it is that the data pointer must be
     /// non-null. Dropping such a `Vec<T>` however will cause undefined
-    /// behaviour.
+    /// behavior.
     ///
     /// [`assume_init`]: MaybeUninit::assume_init
     /// [`Vec<T>`]: ../../std/vec/struct.Vec.html
diff --git a/library/core/src/net/ip_addr.rs b/library/core/src/net/ip_addr.rs
index d3360c1..0d1f4a9 100644
--- a/library/core/src/net/ip_addr.rs
+++ b/library/core/src/net/ip_addr.rs
@@ -373,6 +373,7 @@
     /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0x2, 0, 0, 0, 0, 0, 0)).is_benchmarking(), true);
     /// ```
     #[unstable(feature = "ip", issue = "27709")]
+    #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")]
     #[must_use]
     #[inline]
     pub const fn is_benchmarking(&self) -> bool {
diff --git a/library/core/src/net/socket_addr.rs b/library/core/src/net/socket_addr.rs
index 4e33917..9204797 100644
--- a/library/core/src/net/socket_addr.rs
+++ b/library/core/src/net/socket_addr.rs
@@ -49,6 +49,15 @@
 /// [IETF RFC 793]: https://tools.ietf.org/html/rfc793
 /// [`IPv4` address]: Ipv4Addr
 ///
+/// # Textual representation
+///
+/// `SocketAddrV4` provides a [`FromStr`](crate::str::FromStr) implementation.
+/// It accepts an IPv4 address in its [textual representation], followed by a
+/// single `:`, followed by the port encoded as a decimal integer.  Other
+/// formats are not accepted.
+///
+/// [textual representation]: Ipv4Addr#textual-representation
+///
 /// # Examples
 ///
 /// ```
@@ -82,6 +91,32 @@
 /// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3
 /// [`IPv6` address]: Ipv6Addr
 ///
+/// # Textual representation
+///
+/// `SocketAddrV6` provides a [`FromStr`](crate::str::FromStr) implementation,
+/// based on the bracketed format recommended by [IETF RFC 5952],
+/// with scope identifiers based on those specified in [IETF RFC 4007].
+///
+/// It accepts addresses consisting of the following elements, in order:
+///   - A left square bracket (`[`)
+///   - The [textual representation] of an IPv6 address
+///   - _Optionally_, a percent sign (`%`) followed by the scope identifier
+///     encoded as a decimal integer
+///   - A right square bracket (`]`)
+///   - A colon (`:`)
+///   - The port, encoded as a decimal integer.
+///
+/// For example, the string `[2001:db8::413]:443` represents a `SocketAddrV6`
+/// with the address `2001:db8::413` and port `443`.  The string
+/// `[2001:db8::413%612]:443` represents the same address and port, with a
+/// scope identifier of `612`.
+///
+/// Other formats are not accepted.
+///
+/// [IETF RFC 5952]: https://tools.ietf.org/html/rfc5952#section-6
+/// [IETF RFC 4007]: https://tools.ietf.org/html/rfc4007#section-11
+/// [textual representation]: Ipv6Addr#textual-representation
+///
 /// # Examples
 ///
 /// ```
@@ -92,6 +127,10 @@
 /// assert_eq!("[2001:db8::1]:8080".parse(), Ok(socket));
 /// assert_eq!(socket.ip(), &Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1));
 /// assert_eq!(socket.port(), 8080);
+///
+/// let mut with_scope = socket.clone();
+/// with_scope.set_scope_id(3);
+/// assert_eq!("[2001:db8::1%3]:8080".parse(), Ok(with_scope));
 /// ```
 #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -159,9 +198,10 @@
     /// socket.set_ip(IpAddr::V4(Ipv4Addr::new(10, 10, 0, 1)));
     /// assert_eq!(socket.ip(), IpAddr::V4(Ipv4Addr::new(10, 10, 0, 1)));
     /// ```
-    #[stable(feature = "sockaddr_setters", since = "1.9.0")]
     #[inline]
-    pub fn set_ip(&mut self, new_ip: IpAddr) {
+    #[stable(feature = "sockaddr_setters", since = "1.9.0")]
+    #[rustc_const_unstable(feature = "const_sockaddr_setters", issue = "131714")]
+    pub const fn set_ip(&mut self, new_ip: IpAddr) {
         // `match (*self, new_ip)` would have us mutate a copy of self only to throw it away.
         match (self, new_ip) {
             (&mut SocketAddr::V4(ref mut a), IpAddr::V4(new_ip)) => a.set_ip(new_ip),
@@ -202,9 +242,10 @@
     /// socket.set_port(1025);
     /// assert_eq!(socket.port(), 1025);
     /// ```
-    #[stable(feature = "sockaddr_setters", since = "1.9.0")]
     #[inline]
-    pub fn set_port(&mut self, new_port: u16) {
+    #[stable(feature = "sockaddr_setters", since = "1.9.0")]
+    #[rustc_const_unstable(feature = "const_sockaddr_setters", issue = "131714")]
+    pub const fn set_port(&mut self, new_port: u16) {
         match *self {
             SocketAddr::V4(ref mut a) => a.set_port(new_port),
             SocketAddr::V6(ref mut a) => a.set_port(new_port),
@@ -307,9 +348,10 @@
     /// socket.set_ip(Ipv4Addr::new(192, 168, 0, 1));
     /// assert_eq!(socket.ip(), &Ipv4Addr::new(192, 168, 0, 1));
     /// ```
-    #[stable(feature = "sockaddr_setters", since = "1.9.0")]
     #[inline]
-    pub fn set_ip(&mut self, new_ip: Ipv4Addr) {
+    #[stable(feature = "sockaddr_setters", since = "1.9.0")]
+    #[rustc_const_unstable(feature = "const_sockaddr_setters", issue = "131714")]
+    pub const fn set_ip(&mut self, new_ip: Ipv4Addr) {
         self.ip = new_ip;
     }
 
@@ -342,9 +384,10 @@
     /// socket.set_port(4242);
     /// assert_eq!(socket.port(), 4242);
     /// ```
-    #[stable(feature = "sockaddr_setters", since = "1.9.0")]
     #[inline]
-    pub fn set_port(&mut self, new_port: u16) {
+    #[stable(feature = "sockaddr_setters", since = "1.9.0")]
+    #[rustc_const_unstable(feature = "const_sockaddr_setters", issue = "131714")]
+    pub const fn set_port(&mut self, new_port: u16) {
         self.port = new_port;
     }
 }
@@ -403,9 +446,10 @@
     /// socket.set_ip(Ipv6Addr::new(76, 45, 0, 0, 0, 0, 0, 0));
     /// assert_eq!(socket.ip(), &Ipv6Addr::new(76, 45, 0, 0, 0, 0, 0, 0));
     /// ```
-    #[stable(feature = "sockaddr_setters", since = "1.9.0")]
     #[inline]
-    pub fn set_ip(&mut self, new_ip: Ipv6Addr) {
+    #[stable(feature = "sockaddr_setters", since = "1.9.0")]
+    #[rustc_const_unstable(feature = "const_sockaddr_setters", issue = "131714")]
+    pub const fn set_ip(&mut self, new_ip: Ipv6Addr) {
         self.ip = new_ip;
     }
 
@@ -438,9 +482,10 @@
     /// socket.set_port(4242);
     /// assert_eq!(socket.port(), 4242);
     /// ```
-    #[stable(feature = "sockaddr_setters", since = "1.9.0")]
     #[inline]
-    pub fn set_port(&mut self, new_port: u16) {
+    #[stable(feature = "sockaddr_setters", since = "1.9.0")]
+    #[rustc_const_unstable(feature = "const_sockaddr_setters", issue = "131714")]
+    pub const fn set_port(&mut self, new_port: u16) {
         self.port = new_port;
     }
 
@@ -485,9 +530,10 @@
     /// socket.set_flowinfo(56);
     /// assert_eq!(socket.flowinfo(), 56);
     /// ```
-    #[stable(feature = "sockaddr_setters", since = "1.9.0")]
     #[inline]
-    pub fn set_flowinfo(&mut self, new_flowinfo: u32) {
+    #[stable(feature = "sockaddr_setters", since = "1.9.0")]
+    #[rustc_const_unstable(feature = "const_sockaddr_setters", issue = "131714")]
+    pub const fn set_flowinfo(&mut self, new_flowinfo: u32) {
         self.flowinfo = new_flowinfo;
     }
 
@@ -527,9 +573,10 @@
     /// socket.set_scope_id(42);
     /// assert_eq!(socket.scope_id(), 42);
     /// ```
-    #[stable(feature = "sockaddr_setters", since = "1.9.0")]
     #[inline]
-    pub fn set_scope_id(&mut self, new_scope_id: u32) {
+    #[stable(feature = "sockaddr_setters", since = "1.9.0")]
+    #[rustc_const_unstable(feature = "const_sockaddr_setters", issue = "131714")]
+    pub const fn set_scope_id(&mut self, new_scope_id: u32) {
         self.scope_id = new_scope_id;
     }
 }
diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs
index 5ab2ab5..e8161cc 100644
--- a/library/core/src/num/f128.rs
+++ b/library/core/src/num/f128.rs
@@ -288,7 +288,6 @@
     // concerns about portability, so this implementation is for
     // private use internally.
     #[inline]
-    #[rustc_const_unstable(feature = "f128", issue = "116909")]
     pub(crate) const fn abs_private(self) -> f128 {
         // SAFETY: This transmutation is fine just like in `to_bits`/`from_bits`.
         unsafe {
@@ -319,7 +318,6 @@
     #[inline]
     #[must_use]
     #[unstable(feature = "f128", issue = "116909")]
-    #[rustc_const_unstable(feature = "f128", issue = "116909")]
     pub const fn is_infinite(self) -> bool {
         (self == f128::INFINITY) | (self == f128::NEG_INFINITY)
     }
@@ -346,7 +344,6 @@
     #[inline]
     #[must_use]
     #[unstable(feature = "f128", issue = "116909")]
-    #[rustc_const_unstable(feature = "f128", issue = "116909")]
     pub const fn is_finite(self) -> bool {
         // There's no need to handle NaN separately: if self is NaN,
         // the comparison is not true, exactly as desired.
@@ -380,7 +377,6 @@
     #[inline]
     #[must_use]
     #[unstable(feature = "f128", issue = "116909")]
-    #[rustc_const_unstable(feature = "f128", issue = "116909")]
     pub const fn is_subnormal(self) -> bool {
         matches!(self.classify(), FpCategory::Subnormal)
     }
@@ -412,7 +408,6 @@
     #[inline]
     #[must_use]
     #[unstable(feature = "f128", issue = "116909")]
-    #[rustc_const_unstable(feature = "f128", issue = "116909")]
     pub const fn is_normal(self) -> bool {
         matches!(self.classify(), FpCategory::Normal)
     }
@@ -437,7 +432,6 @@
     /// ```
     #[inline]
     #[unstable(feature = "f128", issue = "116909")]
-    #[rustc_const_unstable(feature = "f128", issue = "116909")]
     pub const fn classify(self) -> FpCategory {
         let bits = self.to_bits();
         match (bits & Self::MAN_MASK, bits & Self::EXP_MASK) {
@@ -915,7 +909,6 @@
     /// ```
     #[inline]
     #[unstable(feature = "f128", issue = "116909")]
-    #[rustc_const_unstable(feature = "f128", issue = "116909")]
     #[must_use = "this returns the result of the operation, without modifying the original"]
     pub const fn to_bits(self) -> u128 {
         // SAFETY: `u128` is a plain old datatype so we can always transmute to it.
@@ -964,7 +957,6 @@
     #[inline]
     #[must_use]
     #[unstable(feature = "f128", issue = "116909")]
-    #[rustc_const_unstable(feature = "f128", issue = "116909")]
     pub const fn from_bits(v: u128) -> Self {
         // It turns out the safety issues with sNaN were overblown! Hooray!
         // SAFETY: `u128` is a plain old datatype so we can always transmute from it.
@@ -991,7 +983,6 @@
     /// ```
     #[inline]
     #[unstable(feature = "f128", issue = "116909")]
-    #[rustc_const_unstable(feature = "f128", issue = "116909")]
     #[must_use = "this returns the result of the operation, without modifying the original"]
     pub const fn to_be_bytes(self) -> [u8; 16] {
         self.to_bits().to_be_bytes()
@@ -1017,7 +1008,6 @@
     /// ```
     #[inline]
     #[unstable(feature = "f128", issue = "116909")]
-    #[rustc_const_unstable(feature = "f128", issue = "116909")]
     #[must_use = "this returns the result of the operation, without modifying the original"]
     pub const fn to_le_bytes(self) -> [u8; 16] {
         self.to_bits().to_le_bytes()
@@ -1054,7 +1044,6 @@
     /// ```
     #[inline]
     #[unstable(feature = "f128", issue = "116909")]
-    #[rustc_const_unstable(feature = "f128", issue = "116909")]
     #[must_use = "this returns the result of the operation, without modifying the original"]
     pub const fn to_ne_bytes(self) -> [u8; 16] {
         self.to_bits().to_ne_bytes()
@@ -1082,7 +1071,6 @@
     #[inline]
     #[must_use]
     #[unstable(feature = "f128", issue = "116909")]
-    #[rustc_const_unstable(feature = "f128", issue = "116909")]
     pub const fn from_be_bytes(bytes: [u8; 16]) -> Self {
         Self::from_bits(u128::from_be_bytes(bytes))
     }
@@ -1109,7 +1097,6 @@
     #[inline]
     #[must_use]
     #[unstable(feature = "f128", issue = "116909")]
-    #[rustc_const_unstable(feature = "f128", issue = "116909")]
     pub const fn from_le_bytes(bytes: [u8; 16]) -> Self {
         Self::from_bits(u128::from_le_bytes(bytes))
     }
@@ -1146,7 +1133,6 @@
     #[inline]
     #[must_use]
     #[unstable(feature = "f128", issue = "116909")]
-    #[rustc_const_unstable(feature = "f128", issue = "116909")]
     pub const fn from_ne_bytes(bytes: [u8; 16]) -> Self {
         Self::from_bits(u128::from_ne_bytes(bytes))
     }
diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs
index 60a8849..8b3f3b7 100644
--- a/library/core/src/num/f16.rs
+++ b/library/core/src/num/f16.rs
@@ -282,7 +282,6 @@
     // concerns about portability, so this implementation is for
     // private use internally.
     #[inline]
-    #[rustc_const_unstable(feature = "f16", issue = "116909")]
     pub(crate) const fn abs_private(self) -> f16 {
         // SAFETY: This transmutation is fine just like in `to_bits`/`from_bits`.
         unsafe { mem::transmute::<u16, f16>(mem::transmute::<f16, u16>(self) & !Self::SIGN_MASK) }
@@ -310,7 +309,6 @@
     #[inline]
     #[must_use]
     #[unstable(feature = "f16", issue = "116909")]
-    #[rustc_const_unstable(feature = "f16", issue = "116909")]
     pub const fn is_infinite(self) -> bool {
         (self == f16::INFINITY) | (self == f16::NEG_INFINITY)
     }
@@ -336,7 +334,6 @@
     #[inline]
     #[must_use]
     #[unstable(feature = "f16", issue = "116909")]
-    #[rustc_const_unstable(feature = "f16", issue = "116909")]
     pub const fn is_finite(self) -> bool {
         // There's no need to handle NaN separately: if self is NaN,
         // the comparison is not true, exactly as desired.
@@ -368,7 +365,6 @@
     #[inline]
     #[must_use]
     #[unstable(feature = "f16", issue = "116909")]
-    #[rustc_const_unstable(feature = "f16", issue = "116909")]
     pub const fn is_subnormal(self) -> bool {
         matches!(self.classify(), FpCategory::Subnormal)
     }
@@ -398,7 +394,6 @@
     #[inline]
     #[must_use]
     #[unstable(feature = "f16", issue = "116909")]
-    #[rustc_const_unstable(feature = "f16", issue = "116909")]
     pub const fn is_normal(self) -> bool {
         matches!(self.classify(), FpCategory::Normal)
     }
@@ -422,7 +417,6 @@
     /// ```
     #[inline]
     #[unstable(feature = "f16", issue = "116909")]
-    #[rustc_const_unstable(feature = "f16", issue = "116909")]
     pub const fn classify(self) -> FpCategory {
         let b = self.to_bits();
         match (b & Self::MAN_MASK, b & Self::EXP_MASK) {
@@ -901,7 +895,6 @@
     /// ```
     #[inline]
     #[unstable(feature = "f16", issue = "116909")]
-    #[rustc_const_unstable(feature = "f16", issue = "116909")]
     #[must_use = "this returns the result of the operation, without modifying the original"]
     pub const fn to_bits(self) -> u16 {
         // SAFETY: `u16` is a plain old datatype so we can always transmute to it.
@@ -949,7 +942,6 @@
     #[inline]
     #[must_use]
     #[unstable(feature = "f16", issue = "116909")]
-    #[rustc_const_unstable(feature = "f16", issue = "116909")]
     pub const fn from_bits(v: u16) -> Self {
         // It turns out the safety issues with sNaN were overblown! Hooray!
         // SAFETY: `u16` is a plain old datatype so we can always transmute from it.
@@ -975,7 +967,6 @@
     /// ```
     #[inline]
     #[unstable(feature = "f16", issue = "116909")]
-    #[rustc_const_unstable(feature = "f16", issue = "116909")]
     #[must_use = "this returns the result of the operation, without modifying the original"]
     pub const fn to_be_bytes(self) -> [u8; 2] {
         self.to_bits().to_be_bytes()
@@ -1000,7 +991,6 @@
     /// ```
     #[inline]
     #[unstable(feature = "f16", issue = "116909")]
-    #[rustc_const_unstable(feature = "f16", issue = "116909")]
     #[must_use = "this returns the result of the operation, without modifying the original"]
     pub const fn to_le_bytes(self) -> [u8; 2] {
         self.to_bits().to_le_bytes()
@@ -1038,7 +1028,6 @@
     /// ```
     #[inline]
     #[unstable(feature = "f16", issue = "116909")]
-    #[rustc_const_unstable(feature = "f16", issue = "116909")]
     #[must_use = "this returns the result of the operation, without modifying the original"]
     pub const fn to_ne_bytes(self) -> [u8; 2] {
         self.to_bits().to_ne_bytes()
@@ -1062,7 +1051,6 @@
     #[inline]
     #[must_use]
     #[unstable(feature = "f16", issue = "116909")]
-    #[rustc_const_unstable(feature = "f16", issue = "116909")]
     pub const fn from_be_bytes(bytes: [u8; 2]) -> Self {
         Self::from_bits(u16::from_be_bytes(bytes))
     }
@@ -1085,7 +1073,6 @@
     #[inline]
     #[must_use]
     #[unstable(feature = "f16", issue = "116909")]
-    #[rustc_const_unstable(feature = "f16", issue = "116909")]
     pub const fn from_le_bytes(bytes: [u8; 2]) -> Self {
         Self::from_bits(u16::from_le_bytes(bytes))
     }
@@ -1119,7 +1106,6 @@
     #[inline]
     #[must_use]
     #[unstable(feature = "f16", issue = "116909")]
-    #[rustc_const_unstable(feature = "f16", issue = "116909")]
     pub const fn from_ne_bytes(bytes: [u8; 2]) -> Self {
         Self::from_bits(u16::from_ne_bytes(bytes))
     }
diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs
index 7241b3f..3a9060df 100644
--- a/library/core/src/num/int_macros.rs
+++ b/library/core/src/num/int_macros.rs
@@ -449,7 +449,7 @@
         #[inline]
         pub const fn checked_add(self, rhs: Self) -> Option<Self> {
             let (a, b) = self.overflowing_add(rhs);
-            if unlikely!(b) { None } else { Some(a) }
+            if intrinsics::unlikely(b) { None } else { Some(a) }
         }
 
         /// Strict integer addition. Computes `self + rhs`, panicking
@@ -545,7 +545,7 @@
         #[inline]
         pub const fn checked_add_unsigned(self, rhs: $UnsignedT) -> Option<Self> {
             let (a, b) = self.overflowing_add_unsigned(rhs);
-            if unlikely!(b) { None } else { Some(a) }
+            if intrinsics::unlikely(b) { None } else { Some(a) }
         }
 
         /// Strict addition with an unsigned integer. Computes `self + rhs`,
@@ -601,7 +601,7 @@
         #[inline]
         pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
             let (a, b) = self.overflowing_sub(rhs);
-            if unlikely!(b) { None } else { Some(a) }
+            if intrinsics::unlikely(b) { None } else { Some(a) }
         }
 
         /// Strict integer subtraction. Computes `self - rhs`, panicking if
@@ -697,7 +697,7 @@
         #[inline]
         pub const fn checked_sub_unsigned(self, rhs: $UnsignedT) -> Option<Self> {
             let (a, b) = self.overflowing_sub_unsigned(rhs);
-            if unlikely!(b) { None } else { Some(a) }
+            if intrinsics::unlikely(b) { None } else { Some(a) }
         }
 
         /// Strict subtraction with an unsigned integer. Computes `self - rhs`,
@@ -753,7 +753,7 @@
         #[inline]
         pub const fn checked_mul(self, rhs: Self) -> Option<Self> {
             let (a, b) = self.overflowing_mul(rhs);
-            if unlikely!(b) { None } else { Some(a) }
+            if intrinsics::unlikely(b) { None } else { Some(a) }
         }
 
         /// Strict integer multiplication. Computes `self * rhs`, panicking if
@@ -849,7 +849,7 @@
                       without modifying the original"]
         #[inline]
         pub const fn checked_div(self, rhs: Self) -> Option<Self> {
-            if unlikely!(rhs == 0 || ((self == Self::MIN) && (rhs == -1))) {
+            if intrinsics::unlikely(rhs == 0 || ((self == Self::MIN) && (rhs == -1))) {
                 None
             } else {
                 // SAFETY: div by zero and by INT_MIN have been checked above
@@ -924,7 +924,7 @@
         #[inline]
         pub const fn checked_div_euclid(self, rhs: Self) -> Option<Self> {
             // Using `&` helps LLVM see that it is the same check made in division.
-            if unlikely!(rhs == 0 || ((self == Self::MIN) & (rhs == -1))) {
+            if intrinsics::unlikely(rhs == 0 || ((self == Self::MIN) & (rhs == -1))) {
                 None
             } else {
                 Some(self.div_euclid(rhs))
@@ -997,7 +997,7 @@
                       without modifying the original"]
         #[inline]
         pub const fn checked_rem(self, rhs: Self) -> Option<Self> {
-            if unlikely!(rhs == 0 || ((self == Self::MIN) && (rhs == -1))) {
+            if intrinsics::unlikely(rhs == 0 || ((self == Self::MIN) && (rhs == -1))) {
                 None
             } else {
                 // SAFETY: div by zero and by INT_MIN have been checked above
@@ -1071,7 +1071,7 @@
         #[inline]
         pub const fn checked_rem_euclid(self, rhs: Self) -> Option<Self> {
             // Using `&` helps LLVM see that it is the same check made in division.
-            if unlikely!(rhs == 0 || ((self == Self::MIN) & (rhs == -1))) {
+            if intrinsics::unlikely(rhs == 0 || ((self == Self::MIN) & (rhs == -1))) {
                 None
             } else {
                 Some(self.rem_euclid(rhs))
@@ -1142,7 +1142,7 @@
         #[inline]
         pub const fn checked_neg(self) -> Option<Self> {
             let (a, b) = self.overflowing_neg();
-            if unlikely!(b) { None } else { Some(a) }
+            if intrinsics::unlikely(b) { None } else { Some(a) }
         }
 
         /// Unchecked negation. Computes `-self`, assuming overflow cannot occur.
@@ -1629,11 +1629,10 @@
         ///
         /// Basic usage:
         /// ```
-        /// #![feature(isqrt)]
         #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".checked_isqrt(), Some(3));")]
         /// ```
-        #[unstable(feature = "isqrt", issue = "116226")]
-        #[rustc_const_unstable(feature = "isqrt", issue = "116226")]
+        #[stable(feature = "isqrt", since = "CURRENT_RUSTC_VERSION")]
+        #[rustc_const_stable(feature = "isqrt", since = "CURRENT_RUSTC_VERSION")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
@@ -2564,7 +2563,7 @@
                       without modifying the original"]
         pub const fn overflowing_div(self, rhs: Self) -> (Self, bool) {
             // Using `&` helps LLVM see that it is the same check made in division.
-            if unlikely!((self == Self::MIN) & (rhs == -1)) {
+            if intrinsics::unlikely((self == Self::MIN) & (rhs == -1)) {
                 (self, true)
             } else {
                 (self / rhs, false)
@@ -2595,7 +2594,7 @@
                       without modifying the original"]
         pub const fn overflowing_div_euclid(self, rhs: Self) -> (Self, bool) {
             // Using `&` helps LLVM see that it is the same check made in division.
-            if unlikely!((self == Self::MIN) & (rhs == -1)) {
+            if intrinsics::unlikely((self == Self::MIN) & (rhs == -1)) {
                 (self, true)
             } else {
                 (self.div_euclid(rhs), false)
@@ -2625,7 +2624,7 @@
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         pub const fn overflowing_rem(self, rhs: Self) -> (Self, bool) {
-            if unlikely!(rhs == -1) {
+            if intrinsics::unlikely(rhs == -1) {
                 (0, self == Self::MIN)
             } else {
                 (self % rhs, false)
@@ -2657,7 +2656,7 @@
         #[inline]
         #[track_caller]
         pub const fn overflowing_rem_euclid(self, rhs: Self) -> (Self, bool) {
-            if unlikely!(rhs == -1) {
+            if intrinsics::unlikely(rhs == -1) {
                 (0, self == Self::MIN)
             } else {
                 (self.rem_euclid(rhs), false)
@@ -2686,7 +2685,7 @@
                       without modifying the original"]
         #[allow(unused_attributes)]
         pub const fn overflowing_neg(self) -> (Self, bool) {
-            if unlikely!(self == Self::MIN) {
+            if intrinsics::unlikely(self == Self::MIN) {
                 (Self::MIN, true)
             } else {
                 (-self, false)
@@ -2880,11 +2879,10 @@
         ///
         /// Basic usage:
         /// ```
-        /// #![feature(isqrt)]
         #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".isqrt(), 3);")]
         /// ```
-        #[unstable(feature = "isqrt", issue = "116226")]
-        #[rustc_const_unstable(feature = "isqrt", issue = "116226")]
+        #[stable(feature = "isqrt", since = "CURRENT_RUSTC_VERSION")]
+        #[rustc_const_stable(feature = "isqrt", since = "CURRENT_RUSTC_VERSION")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
@@ -3181,44 +3179,6 @@
             }
         }
 
-        /// Calculates the middle point of `self` and `rhs`.
-        ///
-        /// `midpoint(a, b)` is `(a + b) >> 1` as if it were performed in a
-        /// sufficiently-large signed integral type. This implies that the result is
-        /// always rounded towards negative infinity and that no overflow will ever occur.
-        ///
-        /// # Examples
-        ///
-        /// ```
-        /// #![feature(num_midpoint)]
-        #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(4), 2);")]
-        #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(-1), -1);")]
-        #[doc = concat!("assert_eq!((-1", stringify!($SelfT), ").midpoint(0), -1);")]
-        /// ```
-        #[unstable(feature = "num_midpoint", issue = "110840")]
-        #[rustc_const_unstable(feature = "const_num_midpoint", issue = "110840")]
-        #[rustc_allow_const_fn_unstable(const_num_midpoint)]
-        #[must_use = "this returns the result of the operation, \
-                      without modifying the original"]
-        #[inline]
-        pub const fn midpoint(self, rhs: Self) -> Self {
-            const U: $UnsignedT = <$SelfT>::MIN.unsigned_abs();
-
-            // Map an $SelfT to an $UnsignedT
-            // ex: i8 [-128; 127] to [0; 255]
-            const fn map(a: $SelfT) -> $UnsignedT {
-                (a as $UnsignedT) ^ U
-            }
-
-            // Map an $UnsignedT to an $SelfT
-            // ex: u8 [0; 255] to [-128; 127]
-            const fn demap(a: $UnsignedT) -> $SelfT {
-                (a ^ U) as $SelfT
-            }
-
-            demap(<$UnsignedT>::midpoint(map(self), map(rhs)))
-        }
-
         /// Returns the logarithm of the number with respect to an arbitrary base,
         /// rounded down.
         ///
diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs
index 5e2f458..9a5e211 100644
--- a/library/core/src/num/mod.rs
+++ b/library/core/src/num/mod.rs
@@ -16,13 +16,6 @@
     };
 }
 
-#[allow_internal_unstable(const_likely)]
-macro_rules! unlikely {
-    ($e: expr) => {
-        intrinsics::unlikely($e)
-    };
-}
-
 // Use this when the generated code should differ between signed and unsigned types.
 macro_rules! sign_dependent_expr {
     (signed ? if signed { $signed_case:expr } if unsigned { $unsigned_case:expr } ) => {
@@ -131,6 +124,37 @@
             ((self ^ rhs) >> 1) + (self & rhs)
         }
     };
+    ($SelfT:ty, signed) => {
+        /// Calculates the middle point of `self` and `rhs`.
+        ///
+        /// `midpoint(a, b)` is `(a + b) / 2` as if it were performed in a
+        /// sufficiently-large signed integral type. This implies that the result is
+        /// always rounded towards zero and that no overflow will ever occur.
+        ///
+        /// # Examples
+        ///
+        /// ```
+        /// #![feature(num_midpoint)]
+        #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(4), 2);")]
+        #[doc = concat!("assert_eq!((-1", stringify!($SelfT), ").midpoint(2), 0);")]
+        #[doc = concat!("assert_eq!((-7", stringify!($SelfT), ").midpoint(0), -3);")]
+        #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(-7), -3);")]
+        #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(7), 3);")]
+        /// ```
+        #[unstable(feature = "num_midpoint", issue = "110840")]
+        #[rustc_const_unstable(feature = "const_num_midpoint", issue = "110840")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn midpoint(self, rhs: Self) -> Self {
+            // Use the well known branchless algorithm from Hacker's Delight to compute
+            // `(a + b) / 2` without overflowing: `((a ^ b) >> 1) + (a & b)`.
+            let t = ((self ^ rhs) >> 1) + (self & rhs);
+            // Except that it fails for integers whose sum is an odd negative number as
+            // their floor is one less than their average. So we adjust the result.
+            t + (if t < 0 { 1 } else { 0 } & (self ^ rhs))
+        }
+    };
     ($SelfT:ty, $WideT:ty, unsigned) => {
         /// Calculates the middle point of `self` and `rhs`.
         ///
@@ -154,6 +178,32 @@
             ((self as $WideT + rhs as $WideT) / 2) as $SelfT
         }
     };
+    ($SelfT:ty, $WideT:ty, signed) => {
+        /// Calculates the middle point of `self` and `rhs`.
+        ///
+        /// `midpoint(a, b)` is `(a + b) / 2` as if it were performed in a
+        /// sufficiently-large signed integral type. This implies that the result is
+        /// always rounded towards zero and that no overflow will ever occur.
+        ///
+        /// # Examples
+        ///
+        /// ```
+        /// #![feature(num_midpoint)]
+        #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(4), 2);")]
+        #[doc = concat!("assert_eq!((-1", stringify!($SelfT), ").midpoint(2), 0);")]
+        #[doc = concat!("assert_eq!((-7", stringify!($SelfT), ").midpoint(0), -3);")]
+        #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(-7), -3);")]
+        #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(7), 3);")]
+        /// ```
+        #[unstable(feature = "num_midpoint", issue = "110840")]
+        #[rustc_const_unstable(feature = "const_num_midpoint", issue = "110840")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn midpoint(self, rhs: $SelfT) -> $SelfT {
+            ((self as $WideT + rhs as $WideT) / 2) as $SelfT
+        }
+    };
 }
 
 macro_rules! widening_impl {
@@ -307,6 +357,7 @@
         from_xe_bytes_doc = "",
         bound_condition = "",
     }
+    midpoint_impl! { i8, i16, signed }
 }
 
 impl i16 {
@@ -330,6 +381,7 @@
         from_xe_bytes_doc = "",
         bound_condition = "",
     }
+    midpoint_impl! { i16, i32, signed }
 }
 
 impl i32 {
@@ -353,6 +405,7 @@
         from_xe_bytes_doc = "",
         bound_condition = "",
     }
+    midpoint_impl! { i32, i64, signed }
 }
 
 impl i64 {
@@ -376,6 +429,7 @@
         from_xe_bytes_doc = "",
         bound_condition = "",
     }
+    midpoint_impl! { i64, i128, signed }
 }
 
 impl i128 {
@@ -401,6 +455,7 @@
         from_xe_bytes_doc = "",
         bound_condition = "",
     }
+    midpoint_impl! { i128, signed }
 }
 
 #[cfg(target_pointer_width = "16")]
@@ -425,6 +480,7 @@
         from_xe_bytes_doc = usize_isize_from_xe_bytes_doc!(),
         bound_condition = " on 16-bit targets",
     }
+    midpoint_impl! { isize, i32, signed }
 }
 
 #[cfg(target_pointer_width = "32")]
@@ -449,6 +505,7 @@
         from_xe_bytes_doc = usize_isize_from_xe_bytes_doc!(),
         bound_condition = " on 32-bit targets",
     }
+    midpoint_impl! { isize, i64, signed }
 }
 
 #[cfg(target_pointer_width = "64")]
@@ -473,6 +530,7 @@
         from_xe_bytes_doc = usize_isize_from_xe_bytes_doc!(),
         bound_condition = " on 64-bit targets",
     }
+    midpoint_impl! { isize, i128, signed }
 }
 
 /// If the 6th bit is set ascii is lower case.
@@ -1397,7 +1455,7 @@
 #[doc(hidden)]
 #[inline(always)]
 #[unstable(issue = "none", feature = "std_internals")]
-#[rustc_const_stable(feature = "const_int_from_str", since = "1.82.0")]
+#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_from_str", since = "1.82.0"))]
 pub const fn can_not_overflow<T>(radix: u32, is_signed_ty: bool, digits: &[u8]) -> bool {
     radix <= 16 && digits.len() <= mem::size_of::<T>() * 2 - is_signed_ty as usize
 }
@@ -1416,6 +1474,7 @@
 #[cfg_attr(feature = "panic_immediate_abort", inline)]
 #[cold]
 #[track_caller]
+#[rustc_allow_const_fn_unstable(const_eval_select)]
 const fn from_str_radix_panic(radix: u32) {
     // The only difference between these two functions is their panic message.
     intrinsics::const_eval_select((radix,), from_str_radix_panic_ct, from_str_radix_panic_rt);
diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs
index e5c9a7e..f6e2719 100644
--- a/library/core/src/num/nonzero.rs
+++ b/library/core/src/num/nonzero.rs
@@ -355,7 +355,7 @@
     }
 
     /// Creates a non-zero without checking whether the value is non-zero.
-    /// This results in undefined behaviour if the value is zero.
+    /// This results in undefined behavior if the value is zero.
     ///
     /// # Safety
     ///
@@ -952,9 +952,9 @@
 
             /// Multiplies two non-zero integers together,
             /// assuming overflow cannot occur.
-            /// Overflow is unchecked, and it is undefined behaviour to overflow
+            /// Overflow is unchecked, and it is undefined behavior to overflow
             /// *even if the result would wrap to a non-zero value*.
-            /// The behaviour is undefined as soon as
+            /// The behavior is undefined as soon as
             #[doc = sign_dependent_expr!{
                 $signedness ?
                 if signed {
@@ -1323,9 +1323,9 @@
 
         /// Adds an unsigned integer to a non-zero value,
         /// assuming overflow cannot occur.
-        /// Overflow is unchecked, and it is undefined behaviour to overflow
+        /// Overflow is unchecked, and it is undefined behavior to overflow
         /// *even if the result would wrap to a non-zero value*.
-        /// The behaviour is undefined as soon as
+        /// The behavior is undefined as soon as
         #[doc = concat!("`self + rhs > ", stringify!($Int), "::MAX`.")]
         ///
         /// # Examples
@@ -1527,7 +1527,6 @@
         ///
         /// Basic usage:
         /// ```
-        /// #![feature(isqrt)]
         /// # use std::num::NonZero;
         /// #
         /// # fn main() { test().unwrap(); }
@@ -1539,8 +1538,8 @@
         /// # Some(())
         /// # }
         /// ```
-        #[unstable(feature = "isqrt", issue = "116226")]
-        #[rustc_const_unstable(feature = "isqrt", issue = "116226")]
+        #[stable(feature = "isqrt", since = "CURRENT_RUSTC_VERSION")]
+        #[rustc_const_stable(feature = "isqrt", since = "CURRENT_RUSTC_VERSION")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
@@ -1599,7 +1598,7 @@
 
         /// Computes the absolute value of self.
         #[doc = concat!("See [`", stringify!($Int), "::abs`]")]
-        /// for documentation on overflow behaviour.
+        /// for documentation on overflow behavior.
         ///
         /// # Example
         ///
@@ -1878,7 +1877,7 @@
         /// Negates self, overflowing if this is equal to the minimum value.
         ///
         #[doc = concat!("See [`", stringify!($Int), "::overflowing_neg`]")]
-        /// for documentation on overflow behaviour.
+        /// for documentation on overflow behavior.
         ///
         /// # Example
         ///
@@ -1943,7 +1942,7 @@
         /// of the type.
         ///
         #[doc = concat!("See [`", stringify!($Int), "::wrapping_neg`]")]
-        /// for documentation on overflow behaviour.
+        /// for documentation on overflow behavior.
         ///
         /// # Example
         ///
diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs
index d9036ab..eb4ea4b 100644
--- a/library/core/src/num/uint_macros.rs
+++ b/library/core/src/num/uint_macros.rs
@@ -491,7 +491,7 @@
             // Per <https://github.com/rust-lang/rust/pull/124114#issuecomment-2066173305>,
             // LLVM is happy to re-form the intrinsic later if useful.
 
-            if unlikely!(intrinsics::add_with_overflow(self, rhs).1) {
+            if intrinsics::unlikely(intrinsics::add_with_overflow(self, rhs).1) {
                 None
             } else {
                 // SAFETY: Just checked it doesn't overflow
@@ -593,7 +593,7 @@
         #[inline]
         pub const fn checked_add_signed(self, rhs: $SignedT) -> Option<Self> {
             let (a, b) = self.overflowing_add_signed(rhs);
-            if unlikely!(b) { None } else { Some(a) }
+            if intrinsics::unlikely(b) { None } else { Some(a) }
         }
 
         /// Strict addition with a signed integer. Computes `self + rhs`,
@@ -845,7 +845,7 @@
         #[inline]
         pub const fn checked_mul(self, rhs: Self) -> Option<Self> {
             let (a, b) = self.overflowing_mul(rhs);
-            if unlikely!(b) { None } else { Some(a) }
+            if intrinsics::unlikely(b) { None } else { Some(a) }
         }
 
         /// Strict integer multiplication. Computes `self * rhs`, panicking if
@@ -940,7 +940,7 @@
                       without modifying the original"]
         #[inline]
         pub const fn checked_div(self, rhs: Self) -> Option<Self> {
-            if unlikely!(rhs == 0) {
+            if intrinsics::unlikely(rhs == 0) {
                 None
             } else {
                 // SAFETY: div by zero has been checked above and unsigned types have no other
@@ -1001,7 +1001,7 @@
                       without modifying the original"]
         #[inline]
         pub const fn checked_div_euclid(self, rhs: Self) -> Option<Self> {
-            if unlikely!(rhs == 0) {
+            if intrinsics::unlikely(rhs == 0) {
                 None
             } else {
                 Some(self.div_euclid(rhs))
@@ -1061,7 +1061,7 @@
                       without modifying the original"]
         #[inline]
         pub const fn checked_rem(self, rhs: Self) -> Option<Self> {
-            if unlikely!(rhs == 0) {
+            if intrinsics::unlikely(rhs == 0) {
                 None
             } else {
                 // SAFETY: div by zero has been checked above and unsigned types have no other
@@ -1123,7 +1123,7 @@
                       without modifying the original"]
         #[inline]
         pub const fn checked_rem_euclid(self, rhs: Self) -> Option<Self> {
-            if unlikely!(rhs == 0) {
+            if intrinsics::unlikely(rhs == 0) {
                 None
             } else {
                 Some(self.rem_euclid(rhs))
@@ -1362,7 +1362,7 @@
         #[inline]
         pub const fn checked_neg(self) -> Option<Self> {
             let (a, b) = self.overflowing_neg();
-            if unlikely!(b) { None } else { Some(a) }
+            if intrinsics::unlikely(b) { None } else { Some(a) }
         }
 
         /// Strict negation. Computes `-self`, panicking unless `self ==
@@ -2753,11 +2753,10 @@
         ///
         /// Basic usage:
         /// ```
-        /// #![feature(isqrt)]
         #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".isqrt(), 3);")]
         /// ```
-        #[unstable(feature = "isqrt", issue = "116226")]
-        #[rustc_const_unstable(feature = "isqrt", issue = "116226")]
+        #[stable(feature = "isqrt", since = "CURRENT_RUSTC_VERSION")]
+        #[rustc_const_stable(feature = "isqrt", since = "CURRENT_RUSTC_VERSION")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
@@ -3009,7 +3008,7 @@
         // overflow cases it instead ends up returning the maximum value
         // of the type, and can return 0 for 0.
         #[inline]
-        #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
+        #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_pow", since = "1.50.0"))]
         const fn one_less_than_next_power_of_two(self) -> Self {
             if self <= 1 { return 0; }
 
@@ -3086,7 +3085,7 @@
         /// ```
         #[inline]
         #[unstable(feature = "wrapping_next_power_of_two", issue = "32463",
-                   reason = "needs decision on wrapping behaviour")]
+                   reason = "needs decision on wrapping behavior")]
         #[rustc_const_unstable(feature = "wrapping_next_power_of_two", issue = "32463")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
diff --git a/library/core/src/num/wrapping.rs b/library/core/src/num/wrapping.rs
index 1ac6d316..1156b38 100644
--- a/library/core/src/num/wrapping.rs
+++ b/library/core/src/num/wrapping.rs
@@ -1043,7 +1043,7 @@
             #[must_use = "this returns the result of the operation, \
                           without modifying the original"]
             #[unstable(feature = "wrapping_next_power_of_two", issue = "32463",
-                       reason = "needs decision on wrapping behaviour")]
+                       reason = "needs decision on wrapping behavior")]
             pub fn next_power_of_two(self) -> Self {
                 Wrapping(self.0.wrapping_next_power_of_two())
             }
diff --git a/library/core/src/ops/deref.rs b/library/core/src/ops/deref.rs
index f0d2c76..1ef9990 100644
--- a/library/core/src/ops/deref.rs
+++ b/library/core/src/ops/deref.rs
@@ -15,7 +15,7 @@
 ///
 /// Types that implement `Deref` or `DerefMut` are often called "smart
 /// pointers" and the mechanism of deref coercion has been specifically designed
-/// to facilitate the pointer-like behaviour that name suggests. Often, the
+/// to facilitate the pointer-like behavior that name suggests. Often, the
 /// purpose of a "smart pointer" type is to change the ownership semantics
 /// of a contained value (for example, [`Rc`][rc] or [`Cow`][cow]) or the
 /// storage semantics of a contained value (for example, [`Box`][box]).
@@ -42,7 +42,7 @@
 /// 1. a value of the type transparently behaves like a value of the target
 ///    type;
 /// 1. the implementation of the deref function is cheap; and
-/// 1. users of the type will not be surprised by any deref coercion behaviour.
+/// 1. users of the type will not be surprised by any deref coercion behavior.
 ///
 /// In general, deref traits **should not** be implemented if:
 ///
@@ -185,7 +185,7 @@
 ///
 /// Types that implement `DerefMut` or `Deref` are often called "smart
 /// pointers" and the mechanism of deref coercion has been specifically designed
-/// to facilitate the pointer-like behaviour that name suggests. Often, the
+/// to facilitate the pointer-like behavior that name suggests. Often, the
 /// purpose of a "smart pointer" type is to change the ownership semantics
 /// of a contained value (for example, [`Rc`][rc] or [`Cow`][cow]) or the
 /// storage semantics of a contained value (for example, [`Box`][box]).
@@ -297,15 +297,21 @@
 /// Indicates that a struct can be used as a method receiver, without the
 /// `arbitrary_self_types` feature. This is implemented by stdlib pointer types like `Box<T>`,
 /// `Rc<T>`, `&T`, and `Pin<P>`.
-#[lang = "receiver"]
-#[unstable(feature = "receiver_trait", issue = "none")]
+///
+/// This trait will shortly be removed and replaced with a more generic
+/// facility based around the current "arbitrary self types" unstable feature.
+/// That new facility will use a replacement trait called `Receiver` which is
+/// why this is now named `LegacyReceiver`.
+#[cfg_attr(bootstrap, lang = "receiver")]
+#[cfg_attr(not(bootstrap), lang = "legacy_receiver")]
+#[unstable(feature = "legacy_receiver_trait", issue = "none")]
 #[doc(hidden)]
-pub trait Receiver {
+pub trait LegacyReceiver {
     // Empty.
 }
 
-#[unstable(feature = "receiver_trait", issue = "none")]
-impl<T: ?Sized> Receiver for &T {}
+#[unstable(feature = "legacy_receiver_trait", issue = "none")]
+impl<T: ?Sized> LegacyReceiver for &T {}
 
-#[unstable(feature = "receiver_trait", issue = "none")]
-impl<T: ?Sized> Receiver for &mut T {}
+#[unstable(feature = "legacy_receiver_trait", issue = "none")]
+impl<T: ?Sized> LegacyReceiver for &mut T {}
diff --git a/library/core/src/ops/mod.rs b/library/core/src/ops/mod.rs
index 5464bf6..c9f47e5 100644
--- a/library/core/src/ops/mod.rs
+++ b/library/core/src/ops/mod.rs
@@ -168,8 +168,8 @@
 pub use self::coroutine::{Coroutine, CoroutineState};
 #[unstable(feature = "deref_pure_trait", issue = "87121")]
 pub use self::deref::DerefPure;
-#[unstable(feature = "receiver_trait", issue = "none")]
-pub use self::deref::Receiver;
+#[unstable(feature = "legacy_receiver_trait", issue = "none")]
+pub use self::deref::LegacyReceiver;
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use self::deref::{Deref, DerefMut};
 #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/library/core/src/option.rs b/library/core/src/option.rs
index 0b996c4..2aa4f17 100644
--- a/library/core/src/option.rs
+++ b/library/core/src/option.rs
@@ -150,7 +150,7 @@
 //! It is further guaranteed that, for the cases above, one can
 //! [`mem::transmute`] from all valid values of `T` to `Option<T>` and
 //! from `Some::<T>(_)` to `T` (but transmuting `None::<T>` to `T`
-//! is undefined behaviour).
+//! is undefined behavior).
 //!
 //! # Method overview
 //!
diff --git a/library/core/src/panic/panic_info.rs b/library/core/src/panic/panic_info.rs
index af2c83b..1d950eb 100644
--- a/library/core/src/panic/panic_info.rs
+++ b/library/core/src/panic/panic_info.rs
@@ -168,6 +168,7 @@
     #[rustc_const_unstable(feature = "const_arguments_as_str", issue = "103900")]
     #[must_use]
     #[inline]
+    #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
     pub const fn as_str(&self) -> Option<&'static str> {
         self.message.as_str()
     }
diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs
index 7420579..9071d67 100644
--- a/library/core/src/panicking.rs
+++ b/library/core/src/panicking.rs
@@ -50,7 +50,8 @@
 #[track_caller]
 #[lang = "panic_fmt"] // needed for const-evaluated panics
 #[rustc_do_not_const_check] // hooked by const-eval
-#[rustc_const_unstable(feature = "panic_internals", issue = "none")]
+#[cfg_attr(bootstrap, rustc_const_unstable(feature = "panic_internals", issue = "none"))]
+#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] // must follow stable const rules since it is exposed to stable
 pub const fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! {
     if cfg!(feature = "panic_immediate_abort") {
         super::intrinsics::abort()
@@ -84,7 +85,9 @@
 // and unwinds anyway, we will hit the "unwinding out of nounwind function" guard,
 // which causes a "panic in a function that cannot unwind".
 #[rustc_nounwind]
-#[rustc_const_unstable(feature = "panic_internals", issue = "none")]
+#[cfg_attr(bootstrap, rustc_const_unstable(feature = "panic_internals", issue = "none"))]
+#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] // must follow stable const rules since it is exposed to stable
+#[rustc_allow_const_fn_unstable(const_eval_select)]
 pub const fn panic_nounwind_fmt(fmt: fmt::Arguments<'_>, force_no_backtrace: bool) -> ! {
     #[inline] // this should always be inlined into `panic_nounwind_fmt`
     #[track_caller]
@@ -131,7 +134,8 @@
 #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
 #[cfg_attr(feature = "panic_immediate_abort", inline)]
 #[track_caller]
-#[rustc_const_unstable(feature = "panic_internals", issue = "none")]
+#[cfg_attr(bootstrap, rustc_const_unstable(feature = "panic_internals", issue = "none"))]
+#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] // must follow stable const rules since it is exposed to stable
 #[lang = "panic"] // used by lints and miri for panics
 pub const fn panic(expr: &'static str) -> ! {
     // Use Arguments::new_const instead of format_args!("{expr}") to potentially
@@ -169,7 +173,8 @@
                 #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
                 #[cfg_attr(feature = "panic_immediate_abort", inline)]
                 #[track_caller]
-                #[rustc_const_unstable(feature = "panic_internals", issue = "none")]
+                #[cfg_attr(bootstrap, rustc_const_unstable(feature = "panic_internals", issue = "none"))]
+                #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] // must follow stable const rules since it is exposed to stable
                 #[lang = stringify!($lang)]
                 pub const fn $lang() -> ! {
                     // Use Arguments::new_const instead of format_args!("{expr}") to potentially
@@ -216,7 +221,8 @@
 #[cfg_attr(feature = "panic_immediate_abort", inline)]
 #[lang = "panic_nounwind"] // needed by codegen for non-unwinding panics
 #[rustc_nounwind]
-#[rustc_const_unstable(feature = "panic_internals", issue = "none")]
+#[cfg_attr(bootstrap, rustc_const_unstable(feature = "panic_internals", issue = "none"))]
+#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] // must follow stable const rules since it is exposed to stable
 pub const fn panic_nounwind(expr: &'static str) -> ! {
     panic_nounwind_fmt(fmt::Arguments::new_const(&[expr]), /* force_no_backtrace */ false);
 }
@@ -232,7 +238,8 @@
 #[track_caller]
 #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
 #[cfg_attr(feature = "panic_immediate_abort", inline)]
-#[rustc_const_unstable(feature = "panic_internals", issue = "none")]
+#[cfg_attr(bootstrap, rustc_const_unstable(feature = "panic_internals", issue = "none"))]
+#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] // must follow stable const rules since it is exposed to stable
 pub const fn panic_explicit() -> ! {
     panic_display(&"explicit panic");
 }
@@ -249,7 +256,8 @@
 #[inline]
 #[track_caller]
 #[rustc_diagnostic_item = "panic_str_2015"]
-#[rustc_const_unstable(feature = "panic_internals", issue = "none")]
+#[cfg_attr(bootstrap, rustc_const_unstable(feature = "panic_internals", issue = "none"))]
+#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] // must follow stable const rules since it is exposed to stable
 pub const fn panic_str_2015(expr: &str) -> ! {
     panic_display(&expr);
 }
@@ -259,7 +267,8 @@
 #[rustc_do_not_const_check] // hooked by const-eval
 // enforce a &&str argument in const-check and hook this by const-eval
 #[rustc_const_panic_str]
-#[rustc_const_unstable(feature = "panic_internals", issue = "none")]
+#[cfg_attr(bootstrap, rustc_const_unstable(feature = "panic_internals", issue = "none"))]
+#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] // must follow stable const rules since it is exposed to stable
 pub const fn panic_display<T: fmt::Display>(x: &T) -> ! {
     panic_fmt(format_args!("{}", *x));
 }
@@ -327,8 +336,9 @@
 }
 
 /// This function is used instead of panic_fmt in const eval.
-#[lang = "const_panic_fmt"]
-#[rustc_const_unstable(feature = "panic_internals", issue = "none")]
+#[lang = "const_panic_fmt"] // needed by const-eval machine to replace calls to `panic_fmt` lang item
+#[cfg_attr(bootstrap, rustc_const_unstable(feature = "panic_internals", issue = "none"))]
+#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] // must follow stable const rules since it is exposed to stable
 pub const fn const_panic_fmt(fmt: fmt::Arguments<'_>) -> ! {
     if let Some(msg) = fmt.as_str() {
         // The panic_display function is hooked by const eval.
diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs
index 5d5733d..254b306 100644
--- a/library/core/src/pin.rs
+++ b/library/core/src/pin.rs
@@ -921,7 +921,7 @@
 #![stable(feature = "pin", since = "1.33.0")]
 
 use crate::hash::{Hash, Hasher};
-use crate::ops::{CoerceUnsized, Deref, DerefMut, DerefPure, DispatchFromDyn, Receiver};
+use crate::ops::{CoerceUnsized, Deref, DerefMut, DerefPure, DispatchFromDyn, LegacyReceiver};
 #[allow(unused_imports)]
 use crate::{
     cell::{RefCell, UnsafeCell},
@@ -1692,8 +1692,8 @@
 #[unstable(feature = "deref_pure_trait", issue = "87121")]
 unsafe impl<Ptr: DerefPure> DerefPure for Pin<Ptr> {}
 
-#[unstable(feature = "receiver_trait", issue = "none")]
-impl<Ptr: Receiver> Receiver for Pin<Ptr> {}
+#[unstable(feature = "legacy_receiver_trait", issue = "none")]
+impl<Ptr: LegacyReceiver> LegacyReceiver for Pin<Ptr> {}
 
 #[stable(feature = "pin", since = "1.33.0")]
 impl<Ptr: fmt::Debug> fmt::Debug for Pin<Ptr> {
diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs
index 95fa6c9..4a6fca5 100644
--- a/library/core/src/primitive_docs.rs
+++ b/library/core/src/primitive_docs.rs
@@ -100,7 +100,7 @@
 ///
 /// Both match arms must produce values of type [`u32`], but since `break` never produces a value
 /// at all we know it can never produce a value which isn't a [`u32`]. This illustrates another
-/// behaviour of the `!` type - expressions with type `!` will coerce into any other type.
+/// behavior of the `!` type - expressions with type `!` will coerce into any other type.
 ///
 /// [`u32`]: prim@u32
 /// [`exit`]: ../std/process/fn.exit.html
@@ -134,7 +134,7 @@
 ///
 /// Since the [`Err`] variant contains a `!`, it can never occur. If the `exhaustive_patterns`
 /// feature is present this means we can exhaustively match on [`Result<T, !>`] by just taking the
-/// [`Ok`] variant. This illustrates another behaviour of `!` - it can be used to "delete" certain
+/// [`Ok`] variant. This illustrates another behavior of `!` - it can be used to "delete" certain
 /// enum variants from generic types like `Result`.
 ///
 /// ## Infinite loops
@@ -351,7 +351,7 @@
 /// ```
 ///
 /// ```no_run
-/// // Undefined behaviour
+/// // Undefined behavior
 /// let _ = unsafe { char::from_u32_unchecked(0x110000) };
 /// ```
 ///
@@ -568,7 +568,7 @@
 /// Instead of coercing a reference to a raw pointer, you can use the macros
 /// [`ptr::addr_of!`] (for `*const T`) and [`ptr::addr_of_mut!`] (for `*mut T`).
 /// These macros allow you to create raw pointers to fields to which you cannot
-/// create a reference (without causing undefined behaviour), such as an
+/// create a reference (without causing undefined behavior), such as an
 /// unaligned field. This might be necessary if packed structs or uninitialized
 /// memory is involved.
 ///
@@ -1453,7 +1453,7 @@
 /// <code>&[bool]</code> can only point to an allocation containing the integer values `1`
 /// ([`true`](../std/keyword.true.html)) or `0` ([`false`](../std/keyword.false.html)), but
 /// creating a <code>&[bool]</code> that points to an allocation containing
-/// the value `3` causes undefined behaviour.
+/// the value `3` causes undefined behavior.
 /// In fact, <code>[Option]\<&T></code> has the same memory representation as a
 /// nullable but aligned pointer, and can be passed across FFI boundaries as such.
 ///
@@ -1612,6 +1612,9 @@
 /// pointers, make your type [`Option<fn()>`](core::option#options-and-pointers-nullable-pointers)
 /// with your required signature.
 ///
+/// Note that FFI requires additional care to ensure that the ABI for both sides of the call match.
+/// The exact requirements are not currently documented.
+///
 /// ### Safety
 ///
 /// Plain function pointers are obtained by casting either plain functions, or closures that don't
@@ -1750,8 +1753,13 @@
 /// is also used rarely. So, most likely you do not have to worry about ABI compatibility.
 ///
 /// But assuming such circumstances, what are the rules? For this section, we are only considering
-/// the ABI of direct Rust-to-Rust calls, not linking in general -- once functions are imported via
-/// `extern` blocks, there are more things to consider that we do not go into here.
+/// the ABI of direct Rust-to-Rust calls (with both definition and callsite visible to the
+/// Rust compiler), not linking in general -- once functions are imported via `extern` blocks, there
+/// are more things to consider that we do not go into here. Note that this also applies to
+/// passing/calling functions across language boundaries via function pointers.
+///
+/// **Nothing in this section should be taken as a guarantee for non-Rust-to-Rust calls, even with
+/// types from `core::ffi` or `libc`**.
 ///
 /// For two signatures to be considered *ABI-compatible*, they must use a compatible ABI string,
 /// must take the same number of arguments, the individual argument types and the return types must
diff --git a/library/core/src/ptr/alignment.rs b/library/core/src/ptr/alignment.rs
index 50706fc..2538d60 100644
--- a/library/core/src/ptr/alignment.rs
+++ b/library/core/src/ptr/alignment.rs
@@ -41,7 +41,7 @@
     /// This provides the same numerical value as [`mem::align_of`],
     /// but in an `Alignment` instead of a `usize`.
     #[unstable(feature = "ptr_alignment_type", issue = "102070")]
-    #[rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070")]
+    #[cfg_attr(bootstrap, rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070"))]
     #[inline]
     pub const fn of<T>() -> Self {
         // SAFETY: rustc ensures that type alignment is always a power of two.
@@ -53,7 +53,7 @@
     ///
     /// Note that `0` is not a power of two, nor a valid alignment.
     #[unstable(feature = "ptr_alignment_type", issue = "102070")]
-    #[rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070")]
+    #[cfg_attr(bootstrap, rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070"))]
     #[inline]
     pub const fn new(align: usize) -> Option<Self> {
         if align.is_power_of_two() {
@@ -73,7 +73,7 @@
     /// Equivalently, it must be `1 << exp` for some `exp` in `0..usize::BITS`.
     /// It must *not* be zero.
     #[unstable(feature = "ptr_alignment_type", issue = "102070")]
-    #[rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070")]
+    #[cfg_attr(bootstrap, rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070"))]
     #[inline]
     pub const unsafe fn new_unchecked(align: usize) -> Self {
         assert_unsafe_precondition!(
@@ -89,7 +89,7 @@
 
     /// Returns the alignment as a [`usize`].
     #[unstable(feature = "ptr_alignment_type", issue = "102070")]
-    #[rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070")]
+    #[cfg_attr(bootstrap, rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070"))]
     #[inline]
     pub const fn as_usize(self) -> usize {
         self.0 as usize
@@ -97,7 +97,7 @@
 
     /// Returns the alignment as a <code>[NonZero]<[usize]></code>.
     #[unstable(feature = "ptr_alignment_type", issue = "102070")]
-    #[rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070")]
+    #[cfg_attr(bootstrap, rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070"))]
     #[inline]
     pub const fn as_nonzero(self) -> NonZero<usize> {
         // SAFETY: All the discriminants are non-zero.
@@ -118,7 +118,7 @@
     /// assert_eq!(Alignment::new(1024).unwrap().log2(), 10);
     /// ```
     #[unstable(feature = "ptr_alignment_type", issue = "102070")]
-    #[rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070")]
+    #[cfg_attr(bootstrap, rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070"))]
     #[inline]
     pub const fn log2(self) -> u32 {
         self.as_nonzero().trailing_zeros()
@@ -148,7 +148,7 @@
     /// assert_ne!(one.mask(Alignment::of::<Align4>().mask()), one);
     /// ```
     #[unstable(feature = "ptr_alignment_type", issue = "102070")]
-    #[rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070")]
+    #[cfg_attr(bootstrap, rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070"))]
     #[inline]
     pub const fn mask(self) -> usize {
         // SAFETY: The alignment is always nonzero, and therefore decrementing won't overflow.
diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs
index 9ee0fb5..75d681d 100644
--- a/library/core/src/ptr/const_ptr.rs
+++ b/library/core/src/ptr/const_ptr.rs
@@ -39,6 +39,7 @@
         }
 
         #[inline]
+        #[rustc_const_unstable(feature = "const_ptr_is_null", issue = "74939")]
         const fn const_impl(ptr: *const u8) -> bool {
             match (ptr).guaranteed_eq(null_mut()) {
                 Some(res) => res,
@@ -113,7 +114,7 @@
     /// println!("{:?}", unsafe { &*bad });
     /// ```
     #[unstable(feature = "set_ptr_value", issue = "75091")]
-    #[rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0")]
+    #[cfg_attr(bootstrap, rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0"))]
     #[must_use = "returns a new pointer rather than modifying its argument"]
     #[inline]
     pub const fn with_metadata_of<U>(self, meta: *const U) -> *const U
@@ -409,6 +410,7 @@
         T: Sized,
     {
         #[inline]
+        #[rustc_allow_const_fn_unstable(const_eval_select)]
         const fn runtime_offset_nowrap(this: *const (), count: isize, size: usize) -> bool {
             #[inline]
             fn runtime(this: *const (), count: isize, size: usize) -> bool {
@@ -704,7 +706,7 @@
     /// but it provides slightly more information to the optimizer, which can
     /// sometimes allow it to optimize slightly better with some backends.
     ///
-    /// This method can be though of as recovering the `count` that was passed
+    /// This method can be thought of as recovering the `count` that was passed
     /// to [`add`](#method.add) (or, with the parameters in the other order,
     /// to [`sub`](#method.sub)).  The following are all equivalent, assuming
     /// that their safety preconditions are met:
@@ -761,6 +763,7 @@
     where
         T: Sized,
     {
+        #[rustc_allow_const_fn_unstable(const_eval_select)]
         const fn runtime_ptr_ge(this: *const (), origin: *const ()) -> bool {
             fn runtime(this: *const (), origin: *const ()) -> bool {
                 this >= origin
@@ -902,6 +905,7 @@
     {
         #[cfg(debug_assertions)]
         #[inline]
+        #[rustc_allow_const_fn_unstable(const_eval_select)]
         const fn runtime_add_nowrap(this: *const (), count: usize, size: usize) -> bool {
             #[inline]
             fn runtime(this: *const (), count: usize, size: usize) -> bool {
@@ -1010,6 +1014,7 @@
     {
         #[cfg(debug_assertions)]
         #[inline]
+        #[rustc_allow_const_fn_unstable(const_eval_select)]
         const fn runtime_sub_nowrap(this: *const (), count: usize, size: usize) -> bool {
             #[inline]
             fn runtime(this: *const (), count: usize, size: usize) -> bool {
@@ -1622,6 +1627,7 @@
         }
 
         #[inline]
+        #[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")]
         const fn const_impl(ptr: *const (), align: usize) -> bool {
             // We can't use the address of `self` in a `const fn`, so we use `align_offset` instead.
             ptr.align_offset(align) == 0
diff --git a/library/core/src/ptr/metadata.rs b/library/core/src/ptr/metadata.rs
index 09c4002..5f20cb2 100644
--- a/library/core/src/ptr/metadata.rs
+++ b/library/core/src/ptr/metadata.rs
@@ -92,7 +92,7 @@
 ///
 /// assert_eq!(std::ptr::metadata("foo"), 3_usize);
 /// ```
-#[rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0")]
+#[cfg_attr(bootstrap, rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0"))]
 #[inline]
 pub const fn metadata<T: ?Sized>(ptr: *const T) -> <T as Pointee>::Metadata {
     ptr_metadata(ptr)
@@ -106,7 +106,7 @@
 ///
 /// [`slice::from_raw_parts`]: crate::slice::from_raw_parts
 #[unstable(feature = "ptr_metadata", issue = "81513")]
-#[rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0")]
+#[cfg_attr(bootstrap, rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0"))]
 #[inline]
 pub const fn from_raw_parts<T: ?Sized>(
     data_pointer: *const impl Thin,
@@ -120,7 +120,7 @@
 ///
 /// See the documentation of [`from_raw_parts`] for more details.
 #[unstable(feature = "ptr_metadata", issue = "81513")]
-#[rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0")]
+#[cfg_attr(bootstrap, rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0"))]
 #[inline]
 pub const fn from_raw_parts_mut<T: ?Sized>(
     data_pointer: *mut impl Thin,
diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs
index f769b51..e9f5bf4 100644
--- a/library/core/src/ptr/mod.rs
+++ b/library/core/src/ptr/mod.rs
@@ -134,7 +134,7 @@
 //! # Provenance
 //!
 //! Pointers are not *simply* an "integer" or "address". For instance, it's uncontroversial
-//! to say that a Use After Free is clearly Undefined Behaviour, even if you "get lucky"
+//! to say that a Use After Free is clearly Undefined Behavior, even if you "get lucky"
 //! and the freed memory gets reallocated before your read/write (in fact this is the
 //! worst-case scenario, UAFs would be much less concerning if this didn't happen!).
 //! As another example, consider that [`wrapping_offset`] is documented to "remember"
@@ -591,8 +591,8 @@
 /// This is a [Strict Provenance][crate::ptr#strict-provenance] API.
 #[inline(always)]
 #[must_use]
-#[rustc_const_stable(feature = "stable_things_using_strict_provenance", since = "1.61.0")]
 #[stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")]
+#[rustc_const_stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")]
 pub const fn without_provenance<T>(addr: usize) -> *const T {
     // An int-to-pointer transmute currently has exactly the intended semantics: it creates a
     // pointer without provenance. Note that this is *not* a stable guarantee about transmute
@@ -602,7 +602,7 @@
     unsafe { mem::transmute(addr) }
 }
 
-/// Creates a new pointer that is dangling, but well-aligned.
+/// Creates a new pointer that is dangling, but non-null and well-aligned.
 ///
 /// This is useful for initializing types which lazily allocate, like
 /// `Vec::new` does.
@@ -613,8 +613,8 @@
 /// some other means.
 #[inline(always)]
 #[must_use]
-#[rustc_const_stable(feature = "stable_things_using_strict_provenance", since = "1.61.0")]
 #[stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")]
+#[rustc_const_stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")]
 pub const fn dangling<T>() -> *const T {
     without_provenance(mem::align_of::<T>())
 }
@@ -634,8 +634,8 @@
 /// This is a [Strict Provenance][crate::ptr#strict-provenance] API.
 #[inline(always)]
 #[must_use]
-#[rustc_const_stable(feature = "stable_things_using_strict_provenance", since = "1.61.0")]
 #[stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")]
+#[rustc_const_stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")]
 pub const fn without_provenance_mut<T>(addr: usize) -> *mut T {
     // An int-to-pointer transmute currently has exactly the intended semantics: it creates a
     // pointer without provenance. Note that this is *not* a stable guarantee about transmute
@@ -645,7 +645,7 @@
     unsafe { mem::transmute(addr) }
 }
 
-/// Creates a new pointer that is dangling, but well-aligned.
+/// Creates a new pointer that is dangling, but non-null and well-aligned.
 ///
 /// This is useful for initializing types which lazily allocate, like
 /// `Vec::new` does.
@@ -656,8 +656,8 @@
 /// some other means.
 #[inline(always)]
 #[must_use]
-#[rustc_const_stable(feature = "stable_things_using_strict_provenance", since = "1.61.0")]
 #[stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")]
+#[rustc_const_stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")]
 pub const fn dangling_mut<T>() -> *mut T {
     without_provenance_mut(mem::align_of::<T>())
 }
@@ -1125,7 +1125,7 @@
     unsafe { swap_nonoverlapping_simple_untyped(x, y, count) }
 }
 
-/// Same behaviour and safety conditions as [`swap_nonoverlapping`]
+/// Same behavior and safety conditions as [`swap_nonoverlapping`]
 ///
 /// LLVM can vectorize this (at least it can for the power-of-two-sized types
 /// `swap_nonoverlapping` tries to use) so no need to manually SIMD it.
@@ -1854,6 +1854,7 @@
 /// Any questions go to @nagisa.
 #[allow(ptr_to_integer_transmute_in_consts)]
 #[lang = "align_offset"]
+#[rustc_const_unstable(feature = "const_align_offset", issue = "90962")]
 pub(crate) const unsafe fn align_offset<T: Sized>(p: *const T, a: usize) -> usize {
     // FIXME(#75598): Direct use of these intrinsics improves codegen significantly at opt-level <=
     // 1, where the method versions of these operations are not inlined.
@@ -2107,13 +2108,39 @@
 
 /// Compares the *addresses* of the two function pointers for equality.
 ///
-/// Function pointers comparisons can have surprising results since
-/// they are never guaranteed to be unique and could vary between different
-/// code generation units. Furthermore, different functions could have the
-/// same address after being merged together.
+/// This is the same as `f == g`, but using this function makes clear that the potentially
+/// surprising semantics of function pointer comparison are involved.
 ///
-/// This is the same as `f == g` but using this function makes clear
-/// that you are aware of these potentially surprising semantics.
+/// There are **very few guarantees** about how functions are compiled and they have no intrinsic
+/// “identity”; in particular, this comparison:
+///
+/// * May return `true` unexpectedly, in cases where functions are equivalent.
+///
+///   For example, the following program is likely (but not guaranteed) to print `(true, true)`
+///   when compiled with optimization:
+///
+///   ```
+///   # #![feature(ptr_fn_addr_eq)]
+///   let f: fn(i32) -> i32 = |x| x;
+///   let g: fn(i32) -> i32 = |x| x + 0;  // different closure, different body
+///   let h: fn(u32) -> u32 = |x| x + 0;  // different signature too
+///   dbg!(std::ptr::fn_addr_eq(f, g), std::ptr::fn_addr_eq(f, h)); // not guaranteed to be equal
+///   ```
+///
+/// * May return `false` in any case.
+///
+///   This is particularly likely with generic functions but may happen with any function.
+///   (From an implementation perspective, this is possible because functions may sometimes be
+///   processed more than once by the compiler, resulting in duplicate machine code.)
+///
+/// Despite these false positives and false negatives, this comparison can still be useful.
+/// Specifically, if
+///
+/// * `T` is the same type as `U`, `T` is a [subtype] of `U`, or `U` is a [subtype] of `T`, and
+/// * `ptr::fn_addr_eq(f, g)` returns true,
+///
+/// then calling `f` and calling `g` will be equivalent.
+///
 ///
 /// # Examples
 ///
@@ -2125,6 +2152,8 @@
 /// fn b() { println!("b"); }
 /// assert!(!ptr::fn_addr_eq(a as fn(), b as fn()));
 /// ```
+///
+/// [subtype]: https://doc.rust-lang.org/reference/subtyping.html
 #[unstable(feature = "ptr_fn_addr_eq", issue = "129322")]
 #[inline(always)]
 #[must_use = "function pointer comparison produces a value"]
diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs
index 782934f..408e722 100644
--- a/library/core/src/ptr/mut_ptr.rs
+++ b/library/core/src/ptr/mut_ptr.rs
@@ -94,7 +94,7 @@
     /// // This dereference is UB. The pointer only has provenance for `x` but points to `y`.
     /// println!("{:?}", unsafe { &*bad });
     #[unstable(feature = "set_ptr_value", issue = "75091")]
-    #[rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0")]
+    #[cfg_attr(bootstrap, rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0"))]
     #[must_use = "returns a new pointer rather than modifying its argument"]
     #[inline]
     pub const fn with_metadata_of<U>(self, meta: *const U) -> *mut U
@@ -405,6 +405,7 @@
         T: Sized,
     {
         #[inline]
+        #[rustc_allow_const_fn_unstable(const_eval_select)]
         const fn runtime_offset_nowrap(this: *const (), count: isize, size: usize) -> bool {
             #[inline]
             fn runtime(this: *const (), count: isize, size: usize) -> bool {
@@ -867,7 +868,7 @@
     /// but it provides slightly more information to the optimizer, which can
     /// sometimes allow it to optimize slightly better with some backends.
     ///
-    /// This method can be though of as recovering the `count` that was passed
+    /// This method can be thought of as recovering the `count` that was passed
     /// to [`add`](#method.add) (or, with the parameters in the other order,
     /// to [`sub`](#method.sub)).  The following are all equivalent, assuming
     /// that their safety preconditions are met:
@@ -984,6 +985,7 @@
     {
         #[cfg(debug_assertions)]
         #[inline]
+        #[rustc_allow_const_fn_unstable(const_eval_select)]
         const fn runtime_add_nowrap(this: *const (), count: usize, size: usize) -> bool {
             #[inline]
             fn runtime(this: *const (), count: usize, size: usize) -> bool {
@@ -1092,6 +1094,7 @@
     {
         #[cfg(debug_assertions)]
         #[inline]
+        #[rustc_allow_const_fn_unstable(const_eval_select)]
         const fn runtime_sub_nowrap(this: *const (), count: usize, size: usize) -> bool {
             #[inline]
             fn runtime(this: *const (), count: usize, size: usize) -> bool {
@@ -1871,6 +1874,7 @@
         }
 
         #[inline]
+        #[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")]
         const fn const_impl(ptr: *mut (), align: usize) -> bool {
             // We can't use the address of `self` in a `const fn`, so we use `align_offset` instead.
             ptr.align_offset(align) == 0
diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs
index d91bbe1..86ef1f3 100644
--- a/library/core/src/ptr/non_null.rs
+++ b/library/core/src/ptr/non_null.rs
@@ -107,9 +107,7 @@
     #[must_use]
     #[inline]
     pub const fn dangling() -> Self {
-        // SAFETY: mem::align_of() returns a non-zero usize which is then casted
-        // to a *mut T. Therefore, `ptr` is not null and the conditions for
-        // calling new_unchecked() are respected.
+        // SAFETY: ptr::dangling_mut() returns a non-null well-aligned pointer.
         unsafe {
             let ptr = crate::ptr::dangling_mut::<T>();
             NonNull::new_unchecked(ptr)
@@ -1510,7 +1508,6 @@
     #[inline]
     #[must_use]
     #[unstable(feature = "slice_ptr_get", issue = "74265")]
-    #[rustc_const_unstable(feature = "slice_ptr_get", issue = "74265")]
     pub const fn as_non_null_ptr(self) -> NonNull<T> {
         self.cast()
     }
diff --git a/library/core/src/ptr/unique.rs b/library/core/src/ptr/unique.rs
index 4810ebe..a796820 100644
--- a/library/core/src/ptr/unique.rs
+++ b/library/core/src/ptr/unique.rs
@@ -92,6 +92,7 @@
 
     /// Creates a new `Unique` if `ptr` is non-null.
     #[inline]
+    #[rustc_const_unstable(feature = "ptr_internals", issue = "none")]
     pub const fn new(ptr: *mut T) -> Option<Self> {
         if let Some(pointer) = NonNull::new(ptr) {
             Some(Unique { pointer, _marker: PhantomData })
diff --git a/library/core/src/slice/ascii.rs b/library/core/src/slice/ascii.rs
index a03e9fb..21e0460 100644
--- a/library/core/src/slice/ascii.rs
+++ b/library/core/src/slice/ascii.rs
@@ -346,6 +346,8 @@
 /// If any of these loads produces something for which `contains_nonascii`
 /// (above) returns true, then we know the answer is false.
 #[inline]
+#[rustc_allow_const_fn_unstable(const_raw_ptr_comparison, const_pointer_is_aligned)] // only in a debug assertion
+#[rustc_allow_const_fn_unstable(const_align_offset)] // behavior does not change when `align_offset` fails
 const fn is_ascii(s: &[u8]) -> bool {
     const USIZE_SIZE: usize = mem::size_of::<usize>();
 
diff --git a/library/core/src/slice/cmp.rs b/library/core/src/slice/cmp.rs
index 1769612..9cb0064 100644
--- a/library/core/src/slice/cmp.rs
+++ b/library/core/src/slice/cmp.rs
@@ -257,3 +257,29 @@
         memchr::memchr(byte, bytes).is_some()
     }
 }
+
+macro_rules! impl_slice_contains {
+    ($($t:ty),*) => {
+        $(
+            impl SliceContains for $t {
+                #[inline]
+                fn slice_contains(&self, arr: &[$t]) -> bool {
+                    // Make our LANE_COUNT 4x the normal lane count (aiming for 128 bit vectors).
+                    // The compiler will nicely unroll it.
+                    const LANE_COUNT: usize = 4 * (128 / (mem::size_of::<$t>() * 8));
+                    // SIMD
+                    let mut chunks = arr.chunks_exact(LANE_COUNT);
+                    for chunk in &mut chunks {
+                        if chunk.iter().fold(false, |acc, x| acc | (*x == *self)) {
+                            return true;
+                        }
+                    }
+                    // Scalar remainder
+                    return chunks.remainder().iter().any(|x| *x == *self);
+                }
+            }
+        )*
+    };
+}
+
+impl_slice_contains!(u16, u32, u64, i16, i32, i64, f32, f64, usize, isize);
diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs
index bc8571c..231ab73 100644
--- a/library/core/src/slice/index.rs
+++ b/library/core/src/slice/index.rs
@@ -31,6 +31,7 @@
 #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
 #[cfg_attr(feature = "panic_immediate_abort", inline)]
 #[track_caller]
+#[rustc_allow_const_fn_unstable(const_eval_select)]
 const fn slice_start_index_len_fail(index: usize, len: usize) -> ! {
     // FIXME(const-hack): once integer formatting in panics is possible, we
     // should use the same implementation at compiletime and runtime.
@@ -52,6 +53,7 @@
 #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
 #[cfg_attr(feature = "panic_immediate_abort", inline)]
 #[track_caller]
+#[rustc_allow_const_fn_unstable(const_eval_select)]
 const fn slice_end_index_len_fail(index: usize, len: usize) -> ! {
     // FIXME(const-hack): once integer formatting in panics is possible, we
     // should use the same implementation at compiletime and runtime.
@@ -73,6 +75,7 @@
 #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
 #[cfg_attr(feature = "panic_immediate_abort", inline)]
 #[track_caller]
+#[rustc_allow_const_fn_unstable(const_eval_select)]
 const fn slice_index_order_fail(index: usize, end: usize) -> ! {
     // FIXME(const-hack): once integer formatting in panics is possible, we
     // should use the same implementation at compiletime and runtime.
@@ -310,7 +313,6 @@
 
 /// Because `IndexRange` guarantees `start <= end`, fewer checks are needed here
 /// than there are for a general `Range<usize>` (which might be `100..3`).
-#[rustc_const_unstable(feature = "const_index_range_slice_index", issue = "none")]
 unsafe impl<T> SliceIndex<[T]> for ops::IndexRange {
     type Output = [T];
 
diff --git a/library/core/src/slice/memchr.rs b/library/core/src/slice/memchr.rs
index be19c3d..5760462 100644
--- a/library/core/src/slice/memchr.rs
+++ b/library/core/src/slice/memchr.rs
@@ -15,7 +15,7 @@
 /// bytes where the borrow propagated all the way to the most significant
 /// bit."
 #[inline]
-#[rustc_const_stable(feature = "const_memchr", since = "1.65.0")]
+#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_memchr", since = "1.65.0"))]
 const fn contains_zero_byte(x: usize) -> bool {
     x.wrapping_sub(LO_USIZE) & !x & HI_USIZE != 0
 }
@@ -23,7 +23,7 @@
 /// Returns the first index matching the byte `x` in `text`.
 #[inline]
 #[must_use]
-#[rustc_const_stable(feature = "const_memchr", since = "1.65.0")]
+#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_memchr", since = "1.65.0"))]
 pub const fn memchr(x: u8, text: &[u8]) -> Option<usize> {
     // Fast path for small slices.
     if text.len() < 2 * USIZE_BYTES {
@@ -34,7 +34,7 @@
 }
 
 #[inline]
-#[rustc_const_stable(feature = "const_memchr", since = "1.65.0")]
+#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_memchr", since = "1.65.0"))]
 const fn memchr_naive(x: u8, text: &[u8]) -> Option<usize> {
     let mut i = 0;
 
@@ -52,7 +52,7 @@
 
 #[rustc_allow_const_fn_unstable(const_cmp)]
 #[rustc_allow_const_fn_unstable(const_align_offset)]
-#[rustc_const_stable(feature = "const_memchr", since = "1.65.0")]
+#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_memchr", since = "1.65.0"))]
 const fn memchr_aligned(x: u8, text: &[u8]) -> Option<usize> {
     // Scan for a single byte value by reading two `usize` words at a time.
     //
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index dbcfe94..27e51af 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -1265,6 +1265,7 @@
     /// // let chunks: &[[_; 0]] = slice.as_chunks_unchecked() // Zero-length chunks are never allowed
     /// ```
     #[unstable(feature = "slice_as_chunks", issue = "74985")]
+    #[rustc_const_unstable(feature = "slice_as_chunks", issue = "74985")]
     #[inline]
     #[must_use]
     pub const unsafe fn as_chunks_unchecked<const N: usize>(&self) -> &[[T; N]] {
@@ -1310,6 +1311,7 @@
     /// assert_eq!(chunks, &[['R', 'u'], ['s', 't']]);
     /// ```
     #[unstable(feature = "slice_as_chunks", issue = "74985")]
+    #[rustc_const_unstable(feature = "slice_as_chunks", issue = "74985")]
     #[inline]
     #[track_caller]
     #[must_use]
@@ -1344,6 +1346,7 @@
     /// assert_eq!(chunks, &[['o', 'r'], ['e', 'm']]);
     /// ```
     #[unstable(feature = "slice_as_chunks", issue = "74985")]
+    #[rustc_const_unstable(feature = "slice_as_chunks", issue = "74985")]
     #[inline]
     #[track_caller]
     #[must_use]
@@ -1422,6 +1425,7 @@
     /// // let chunks: &[[_; 0]] = slice.as_chunks_unchecked_mut() // Zero-length chunks are never allowed
     /// ```
     #[unstable(feature = "slice_as_chunks", issue = "74985")]
+    #[rustc_const_unstable(feature = "slice_as_chunks", issue = "74985")]
     #[inline]
     #[must_use]
     pub const unsafe fn as_chunks_unchecked_mut<const N: usize>(&mut self) -> &mut [[T; N]] {
@@ -1462,6 +1466,7 @@
     /// assert_eq!(v, &[1, 1, 2, 2, 9]);
     /// ```
     #[unstable(feature = "slice_as_chunks", issue = "74985")]
+    #[rustc_const_unstable(feature = "slice_as_chunks", issue = "74985")]
     #[inline]
     #[track_caller]
     #[must_use]
@@ -1502,6 +1507,7 @@
     /// assert_eq!(v, &[9, 1, 1, 2, 2]);
     /// ```
     #[unstable(feature = "slice_as_chunks", issue = "74985")]
+    #[rustc_const_unstable(feature = "slice_as_chunks", issue = "74985")]
     #[inline]
     #[track_caller]
     #[must_use]
diff --git a/library/core/src/str/pattern.rs b/library/core/src/str/pattern.rs
index eb60eff..665c9fc 100644
--- a/library/core/src/str/pattern.rs
+++ b/library/core/src/str/pattern.rs
@@ -57,9 +57,9 @@
 /// [`Searcher`] type, which does the actual work of finding
 /// occurrences of the pattern in a string.
 ///
-/// Depending on the type of the pattern, the behaviour of methods like
+/// Depending on the type of the pattern, the behavior of methods like
 /// [`str::find`] and [`str::contains`] can change. The table below describes
-/// some of those behaviours.
+/// some of those behaviors.
 ///
 /// | Pattern type             | Match condition                           |
 /// |--------------------------|-------------------------------------------|
@@ -162,7 +162,9 @@
     }
 
     /// Returns the pattern as utf-8 bytes if possible.
-    fn as_utf8_pattern(&self) -> Option<Utf8Pattern<'_>>;
+    fn as_utf8_pattern(&self) -> Option<Utf8Pattern<'_>> {
+        None
+    }
 }
 /// Result of calling [`Pattern::as_utf8_pattern()`].
 /// Can be used for inspecting the contents of a [`Pattern`] in cases
@@ -675,11 +677,6 @@
     fn into_searcher(self, haystack: &str) -> MultiCharEqSearcher<'_, C> {
         MultiCharEqSearcher { haystack, char_eq: self.0, char_indices: haystack.char_indices() }
     }
-
-    #[inline]
-    fn as_utf8_pattern(&self) -> Option<Utf8Pattern<'_>> {
-        None
-    }
 }
 
 unsafe impl<'a, C: MultiCharEq> Searcher<'a> for MultiCharEqSearcher<'a, C> {
@@ -770,11 +767,6 @@
         {
             ($pmap)(self).strip_suffix_of(haystack)
         }
-
-        #[inline]
-        fn as_utf8_pattern(&self) -> Option<Utf8Pattern<'_>> {
-            None
-        }
     };
 }
 
diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs
index 17ba18c..93b4ad5 100644
--- a/library/core/src/sync/atomic.rs
+++ b/library/core/src/sync/atomic.rs
@@ -2122,7 +2122,8 @@
      $stable_access:meta,
      $stable_from:meta,
      $stable_nand:meta,
-     $const_stable:meta,
+     $const_stable_new:meta,
+     $const_stable_into_inner:meta,
      $diagnostic_item:meta,
      $s_int_type:literal,
      $extra_feature:expr,
@@ -2204,7 +2205,7 @@
             /// ```
             #[inline]
             #[$stable]
-            #[$const_stable]
+            #[$const_stable_new]
             #[must_use]
             pub const fn new(v: $int_type) -> Self {
                 Self {v: UnsafeCell::new(v)}
@@ -2406,7 +2407,7 @@
             /// ```
             #[inline]
             #[$stable_access]
-            #[rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0")]
+            #[$const_stable_into_inner]
             pub const fn into_inner(self) -> $int_type {
                 self.v.into_inner()
             }
@@ -3054,6 +3055,7 @@
     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"),
+    rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0"),
     cfg_attr(not(test), rustc_diagnostic_item = "AtomicI8"),
     "i8",
     "",
@@ -3072,6 +3074,7 @@
     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"),
+    rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0"),
     cfg_attr(not(test), rustc_diagnostic_item = "AtomicU8"),
     "u8",
     "",
@@ -3090,6 +3093,7 @@
     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"),
+    rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0"),
     cfg_attr(not(test), rustc_diagnostic_item = "AtomicI16"),
     "i16",
     "",
@@ -3108,6 +3112,7 @@
     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"),
+    rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0"),
     cfg_attr(not(test), rustc_diagnostic_item = "AtomicU16"),
     "u16",
     "",
@@ -3126,6 +3131,7 @@
     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"),
+    rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0"),
     cfg_attr(not(test), rustc_diagnostic_item = "AtomicI32"),
     "i32",
     "",
@@ -3144,6 +3150,7 @@
     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"),
+    rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0"),
     cfg_attr(not(test), rustc_diagnostic_item = "AtomicU32"),
     "u32",
     "",
@@ -3162,6 +3169,7 @@
     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"),
+    rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0"),
     cfg_attr(not(test), rustc_diagnostic_item = "AtomicI64"),
     "i64",
     "",
@@ -3180,6 +3188,7 @@
     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"),
+    rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0"),
     cfg_attr(not(test), rustc_diagnostic_item = "AtomicU64"),
     "u64",
     "",
@@ -3197,7 +3206,8 @@
     unstable(feature = "integer_atomics", issue = "99069"),
     unstable(feature = "integer_atomics", issue = "99069"),
     unstable(feature = "integer_atomics", issue = "99069"),
-    rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
+    rustc_const_unstable(feature = "integer_atomics", issue = "99069"),
+    rustc_const_unstable(feature = "integer_atomics", issue = "99069"),
     cfg_attr(not(test), rustc_diagnostic_item = "AtomicI128"),
     "i128",
     "#![feature(integer_atomics)]\n\n",
@@ -3215,7 +3225,8 @@
     unstable(feature = "integer_atomics", issue = "99069"),
     unstable(feature = "integer_atomics", issue = "99069"),
     unstable(feature = "integer_atomics", issue = "99069"),
-    rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
+    rustc_const_unstable(feature = "integer_atomics", issue = "99069"),
+    rustc_const_unstable(feature = "integer_atomics", issue = "99069"),
     cfg_attr(not(test), rustc_diagnostic_item = "AtomicU128"),
     "u128",
     "#![feature(integer_atomics)]\n\n",
@@ -3238,6 +3249,7 @@
             stable(feature = "atomic_from", since = "1.23.0"),
             stable(feature = "atomic_nand", since = "1.27.0"),
             rustc_const_stable(feature = "const_ptr_sized_atomics", since = "1.24.0"),
+            rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0"),
             cfg_attr(not(test), rustc_diagnostic_item = "AtomicIsize"),
             "isize",
             "",
@@ -3256,6 +3268,7 @@
             stable(feature = "atomic_from", since = "1.23.0"),
             stable(feature = "atomic_nand", since = "1.27.0"),
             rustc_const_stable(feature = "const_ptr_sized_atomics", since = "1.24.0"),
+            rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0"),
             cfg_attr(not(test), rustc_diagnostic_item = "AtomicUsize"),
             "usize",
             "",
diff --git a/library/core/src/sync/exclusive.rs b/library/core/src/sync/exclusive.rs
index fbf8daf..af25f13 100644
--- a/library/core/src/sync/exclusive.rs
+++ b/library/core/src/sync/exclusive.rs
@@ -106,6 +106,7 @@
 
     /// Unwrap the value contained in the `Exclusive`
     #[unstable(feature = "exclusive_wrapper", issue = "98407")]
+    #[rustc_const_unstable(feature = "exclusive_wrapper", issue = "98407")]
     #[must_use]
     #[inline]
     pub const fn into_inner(self) -> T {
@@ -129,6 +130,7 @@
     /// access to the underlying value, but _pinned_ `Exclusive`s only
     /// produce _pinned_ access to the underlying value.
     #[unstable(feature = "exclusive_wrapper", issue = "98407")]
+    #[rustc_const_unstable(feature = "exclusive_wrapper", issue = "98407")]
     #[must_use]
     #[inline]
     pub const fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut T> {
@@ -152,6 +154,7 @@
     /// a _pinned mutable_ reference to a `T`. This allows you to skip
     /// building an `Exclusive` with [`Exclusive::new`].
     #[unstable(feature = "exclusive_wrapper", issue = "98407")]
+    #[rustc_const_unstable(feature = "exclusive_wrapper", issue = "98407")]
     #[must_use]
     #[inline]
     pub const fn from_pin_mut(r: Pin<&'_ mut T>) -> Pin<&'_ mut Exclusive<T>> {
diff --git a/library/core/src/task/wake.rs b/library/core/src/task/wake.rs
index 3e795e7..fb7af82 100644
--- a/library/core/src/task/wake.rs
+++ b/library/core/src/task/wake.rs
@@ -321,7 +321,7 @@
     /// Creates a ContextBuilder from a Waker.
     #[inline]
     #[unstable(feature = "local_waker", issue = "118959")]
-    #[rustc_const_stable(feature = "const_waker", since = "1.82.0")]
+    #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_waker", since = "1.82.0"))]
     pub const fn from_waker(waker: &'a Waker) -> Self {
         // SAFETY: LocalWaker is just Waker without thread safety
         let local_waker = unsafe { transmute(waker) };
@@ -379,7 +379,7 @@
     /// Builds the `Context`.
     #[inline]
     #[unstable(feature = "local_waker", issue = "118959")]
-    #[rustc_const_stable(feature = "const_waker", since = "1.82.0")]
+    #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_waker", since = "1.82.0"))]
     pub const fn build(self) -> Context<'a> {
         let ContextBuilder { waker, local_waker, ext, _marker, _marker2 } = self;
         Context { waker, local_waker, ext: AssertUnwindSafe(ext), _marker, _marker2 }
diff --git a/library/core/src/ub_checks.rs b/library/core/src/ub_checks.rs
index daaaf5a..9156643 100644
--- a/library/core/src/ub_checks.rs
+++ b/library/core/src/ub_checks.rs
@@ -47,7 +47,7 @@
 /// order to call it. Since the precompiled standard library is built with full debuginfo and these
 /// variables cannot be optimized out in MIR, an innocent-looking `let` can produce enough
 /// debuginfo to have a measurable compile-time impact on debug builds.
-#[allow_internal_unstable(const_ub_checks)] // permit this to be called in stably-const fn
+#[cfg_attr(bootstrap, allow_internal_unstable(const_ub_checks))] // permit this to be called in stably-const fn
 #[macro_export]
 #[unstable(feature = "ub_checks", issue = "none")]
 macro_rules! assert_unsafe_precondition {
@@ -64,7 +64,8 @@
             #[rustc_no_mir_inline]
             #[inline]
             #[rustc_nounwind]
-            #[rustc_const_unstable(feature = "const_ub_checks", issue = "none")]
+            #[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_ub_checks", issue = "none"))]
+            #[rustc_allow_const_fn_unstable(const_ptr_is_null, const_ub_checks)] // only for UB checks
             const fn precondition_check($($name:$ty),*) {
                 if !$e {
                     ::core::panicking::panic_nounwind(
@@ -90,8 +91,9 @@
 ///
 /// The intention is to not do that when running in the interpreter, as that one has its own
 /// language UB checks which generally produce better errors.
-#[rustc_const_unstable(feature = "const_ub_checks", issue = "none")]
+#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_ub_checks", issue = "none"))]
 #[inline]
+#[rustc_allow_const_fn_unstable(const_eval_select)]
 pub(crate) const fn check_language_ub() -> bool {
     #[inline]
     fn runtime() -> bool {
@@ -116,6 +118,7 @@
 /// for `assert_unsafe_precondition!` with `check_language_ub`, in which case the
 /// check is anyway not executed in `const`.
 #[inline]
+#[rustc_const_unstable(feature = "const_ub_checks", issue = "none")]
 pub(crate) const fn is_aligned_and_not_null(ptr: *const (), align: usize, is_zst: bool) -> bool {
     ptr.is_aligned_to(align) && (is_zst || !ptr.is_null())
 }
@@ -132,6 +135,7 @@
 /// Note that in const-eval this function just returns `true` and therefore must
 /// only be used with `assert_unsafe_precondition!`, similar to `is_aligned_and_not_null`.
 #[inline]
+#[rustc_const_unstable(feature = "const_ub_checks", issue = "none")]
 pub(crate) const fn is_nonoverlapping(
     src: *const (),
     dst: *const (),
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index 5d69218..2a9f166 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -17,11 +17,13 @@
 #![feature(clone_to_uninit)]
 #![feature(const_align_of_val_raw)]
 #![feature(const_align_offset)]
+#![feature(const_bigint_helper_methods)]
 #![feature(const_black_box)]
+#![feature(const_eval_select)]
 #![feature(const_hash)]
 #![feature(const_heap)]
-#![feature(const_likely)]
 #![feature(const_nonnull_new)]
+#![feature(const_num_midpoint)]
 #![feature(const_option_ext)]
 #![feature(const_pin_2)]
 #![feature(const_pointer_is_aligned)]
@@ -46,11 +48,11 @@
 #![feature(get_many_mut)]
 #![feature(hasher_prefixfree_extras)]
 #![feature(hashmap_internals)]
+#![feature(inline_const_pat)]
 #![feature(int_roundings)]
 #![feature(ip)]
 #![feature(ip_from)]
 #![feature(is_ascii_octdigit)]
-#![feature(isqrt)]
 #![feature(iter_advance_by)]
 #![feature(iter_array_chunks)]
 #![feature(iter_chain)]
@@ -104,6 +106,37 @@
 #![deny(fuzzy_provenance_casts)]
 #![deny(unsafe_op_in_unsafe_fn)]
 
+/// Version of `assert_matches` that ignores fancy runtime printing in const context and uses structural equality.
+macro_rules! assert_eq_const_safe {
+    ($left:expr, $right:expr$(, $($arg:tt)+)?) => {
+        {
+            fn runtime() {
+                assert_eq!($left, $right, $($arg)*);
+            }
+            const fn compiletime() {
+                assert!(matches!($left, const { $right }));
+            }
+            core::intrinsics::const_eval_select((), compiletime, runtime)
+        }
+    };
+}
+
+/// Creates a test for runtime and a test for constant-time.
+macro_rules! test_runtime_and_compiletime {
+    ($(
+        $(#[$attr:meta])*
+        fn $test:ident() $block:block
+    )*) => {
+        $(
+            $(#[$attr])*
+            #[test]
+            fn $test() $block
+            $(#[$attr])*
+            const _: () = $block;
+        )*
+    }
+}
+
 mod alloc;
 mod any;
 mod array;
diff --git a/library/core/tests/num/int_macros.rs b/library/core/tests/num/int_macros.rs
index 6a26bd1..474d570 100644
--- a/library/core/tests/num/int_macros.rs
+++ b/library/core/tests/num/int_macros.rs
@@ -18,42 +18,6 @@
         }
 
         #[test]
-        fn test_rem_euclid() {
-            assert_eq!((-1 as $T).rem_euclid(MIN), MAX);
-        }
-
-        #[test]
-        pub fn test_abs() {
-            assert_eq!((1 as $T).abs(), 1 as $T);
-            assert_eq!((0 as $T).abs(), 0 as $T);
-            assert_eq!((-1 as $T).abs(), 1 as $T);
-        }
-
-        #[test]
-        fn test_signum() {
-            assert_eq!((1 as $T).signum(), 1 as $T);
-            assert_eq!((0 as $T).signum(), 0 as $T);
-            assert_eq!((-0 as $T).signum(), 0 as $T);
-            assert_eq!((-1 as $T).signum(), -1 as $T);
-        }
-
-        #[test]
-        fn test_is_positive() {
-            assert!((1 as $T).is_positive());
-            assert!(!(0 as $T).is_positive());
-            assert!(!(-0 as $T).is_positive());
-            assert!(!(-1 as $T).is_positive());
-        }
-
-        #[test]
-        fn test_is_negative() {
-            assert!(!(1 as $T).is_negative());
-            assert!(!(0 as $T).is_negative());
-            assert!(!(-0 as $T).is_negative());
-            assert!((-1 as $T).is_negative());
-        }
-
-        #[test]
         fn test_bitwise_operators() {
             assert_eq!(0b1110 as $T, (0b1100 as $T).bitor(0b1010 as $T));
             assert_eq!(0b1000 as $T, (0b1100 as $T).bitand(0b1010 as $T));
@@ -63,6 +27,40 @@
             assert_eq!(-(0b11 as $T) - (1 as $T), (0b11 as $T).not());
         }
 
+        test_runtime_and_compiletime! {
+
+            fn test_rem_euclid() {
+                assert_eq_const_safe!((-1 as $T).rem_euclid(MIN), MAX);
+            }
+
+            fn test_abs() {
+                assert_eq_const_safe!((1 as $T).abs(), 1 as $T);
+                assert_eq_const_safe!((0 as $T).abs(), 0 as $T);
+                assert_eq_const_safe!((-1 as $T).abs(), 1 as $T);
+            }
+
+            fn test_signum() {
+                assert_eq_const_safe!((1 as $T).signum(), 1 as $T);
+                assert_eq_const_safe!((0 as $T).signum(), 0 as $T);
+                assert_eq_const_safe!((-0 as $T).signum(), 0 as $T);
+                assert_eq_const_safe!((-1 as $T).signum(), -1 as $T);
+            }
+
+            fn test_is_positive() {
+                assert!((1 as $T).is_positive());
+                assert!(!(0 as $T).is_positive());
+                assert!(!(-0 as $T).is_positive());
+                assert!(!(-1 as $T).is_positive());
+            }
+
+            fn test_is_negative() {
+                assert!(!(1 as $T).is_negative());
+                assert!(!(0 as $T).is_negative());
+                assert!(!(-0 as $T).is_negative());
+                assert!((-1 as $T).is_negative());
+            }
+        }
+
         const A: $T = 0b0101100;
         const B: $T = 0b0100001;
         const C: $T = 0b1111001;
@@ -70,134 +68,126 @@
         const _0: $T = 0;
         const _1: $T = !0;
 
-        #[test]
-        fn test_count_ones() {
-            assert_eq!(A.count_ones(), 3);
-            assert_eq!(B.count_ones(), 2);
-            assert_eq!(C.count_ones(), 5);
-        }
+        test_runtime_and_compiletime! {
+            fn test_count_ones() {
+                assert_eq_const_safe!(A.count_ones(), 3);
+                assert_eq_const_safe!(B.count_ones(), 2);
+                assert_eq_const_safe!(C.count_ones(), 5);
+            }
 
-        #[test]
-        fn test_count_zeros() {
-            assert_eq!(A.count_zeros(), $T::BITS - 3);
-            assert_eq!(B.count_zeros(), $T::BITS - 2);
-            assert_eq!(C.count_zeros(), $T::BITS - 5);
-        }
+            fn test_count_zeros() {
+                assert_eq_const_safe!(A.count_zeros(), $T::BITS - 3);
+                assert_eq_const_safe!(B.count_zeros(), $T::BITS - 2);
+                assert_eq_const_safe!(C.count_zeros(), $T::BITS - 5);
+            }
 
-        #[test]
-        fn test_leading_trailing_ones() {
-            let a: $T = 0b0101_1111;
-            assert_eq!(a.trailing_ones(), 5);
-            assert_eq!((!a).leading_ones(), $T::BITS - 7);
+            fn test_leading_trailing_ones() {
+                const A: $T = 0b0101_1111;
+                assert_eq_const_safe!(A.trailing_ones(), 5);
+                assert_eq_const_safe!((!A).leading_ones(), $T::BITS - 7);
 
-            assert_eq!(a.reverse_bits().leading_ones(), 5);
+                assert_eq_const_safe!(A.reverse_bits().leading_ones(), 5);
 
-            assert_eq!(_1.leading_ones(), $T::BITS);
-            assert_eq!(_1.trailing_ones(), $T::BITS);
+                assert_eq_const_safe!(_1.leading_ones(), $T::BITS);
+                assert_eq_const_safe!(_1.trailing_ones(), $T::BITS);
 
-            assert_eq!((_1 << 1).trailing_ones(), 0);
-            assert_eq!(MAX.leading_ones(), 0);
+                assert_eq_const_safe!((_1 << 1).trailing_ones(), 0);
+                assert_eq_const_safe!(MAX.leading_ones(), 0);
 
-            assert_eq!((_1 << 1).leading_ones(), $T::BITS - 1);
-            assert_eq!(MAX.trailing_ones(), $T::BITS - 1);
+                assert_eq_const_safe!((_1 << 1).leading_ones(), $T::BITS - 1);
+                assert_eq_const_safe!(MAX.trailing_ones(), $T::BITS - 1);
 
-            assert_eq!(_0.leading_ones(), 0);
-            assert_eq!(_0.trailing_ones(), 0);
+                assert_eq_const_safe!(_0.leading_ones(), 0);
+                assert_eq_const_safe!(_0.trailing_ones(), 0);
 
-            let x: $T = 0b0010_1100;
-            assert_eq!(x.leading_ones(), 0);
-            assert_eq!(x.trailing_ones(), 0);
-        }
+                const X: $T = 0b0010_1100;
+                assert_eq_const_safe!(X.leading_ones(), 0);
+                assert_eq_const_safe!(X.trailing_ones(), 0);
+            }
 
-        #[test]
-        fn test_rotate() {
-            assert_eq!(A.rotate_left(6).rotate_right(2).rotate_right(4), A);
-            assert_eq!(B.rotate_left(3).rotate_left(2).rotate_right(5), B);
-            assert_eq!(C.rotate_left(6).rotate_right(2).rotate_right(4), C);
+            fn test_rotate() {
+                assert_eq_const_safe!(A.rotate_left(6).rotate_right(2).rotate_right(4), A);
+                assert_eq_const_safe!(B.rotate_left(3).rotate_left(2).rotate_right(5), B);
+                assert_eq_const_safe!(C.rotate_left(6).rotate_right(2).rotate_right(4), C);
 
-            // Rotating these should make no difference
-            //
-            // We test using 124 bits because to ensure that overlong bit shifts do
-            // not cause undefined behaviour. See #10183.
-            assert_eq!(_0.rotate_left(124), _0);
-            assert_eq!(_1.rotate_left(124), _1);
-            assert_eq!(_0.rotate_right(124), _0);
-            assert_eq!(_1.rotate_right(124), _1);
+                // Rotating these should make no difference
+                //
+                // We test using 124 bits because to ensure that overlong bit shifts do
+                // not cause undefined behavior. See #10183.
+                assert_eq_const_safe!(_0.rotate_left(124), _0);
+                assert_eq_const_safe!(_1.rotate_left(124), _1);
+                assert_eq_const_safe!(_0.rotate_right(124), _0);
+                assert_eq_const_safe!(_1.rotate_right(124), _1);
 
-            // Rotating by 0 should have no effect
-            assert_eq!(A.rotate_left(0), A);
-            assert_eq!(B.rotate_left(0), B);
-            assert_eq!(C.rotate_left(0), C);
-            // Rotating by a multiple of word size should also have no effect
-            assert_eq!(A.rotate_left(128), A);
-            assert_eq!(B.rotate_left(128), B);
-            assert_eq!(C.rotate_left(128), C);
-        }
+                // Rotating by 0 should have no effect
+                assert_eq_const_safe!(A.rotate_left(0), A);
+                assert_eq_const_safe!(B.rotate_left(0), B);
+                assert_eq_const_safe!(C.rotate_left(0), C);
+                // Rotating by a multiple of word size should also have no effect
+                assert_eq_const_safe!(A.rotate_left(128), A);
+                assert_eq_const_safe!(B.rotate_left(128), B);
+                assert_eq_const_safe!(C.rotate_left(128), C);
+            }
 
-        #[test]
-        fn test_swap_bytes() {
-            assert_eq!(A.swap_bytes().swap_bytes(), A);
-            assert_eq!(B.swap_bytes().swap_bytes(), B);
-            assert_eq!(C.swap_bytes().swap_bytes(), C);
+            fn test_swap_bytes() {
+                assert_eq_const_safe!(A.swap_bytes().swap_bytes(), A);
+                assert_eq_const_safe!(B.swap_bytes().swap_bytes(), B);
+                assert_eq_const_safe!(C.swap_bytes().swap_bytes(), C);
 
-            // Swapping these should make no difference
-            assert_eq!(_0.swap_bytes(), _0);
-            assert_eq!(_1.swap_bytes(), _1);
-        }
+                // Swapping these should make no difference
+                assert_eq_const_safe!(_0.swap_bytes(), _0);
+                assert_eq_const_safe!(_1.swap_bytes(), _1);
+            }
 
-        #[test]
-        fn test_le() {
-            assert_eq!($T::from_le(A.to_le()), A);
-            assert_eq!($T::from_le(B.to_le()), B);
-            assert_eq!($T::from_le(C.to_le()), C);
-            assert_eq!($T::from_le(_0), _0);
-            assert_eq!($T::from_le(_1), _1);
-            assert_eq!(_0.to_le(), _0);
-            assert_eq!(_1.to_le(), _1);
-        }
+            fn test_le() {
+                assert_eq_const_safe!($T::from_le(A.to_le()), A);
+                assert_eq_const_safe!($T::from_le(B.to_le()), B);
+                assert_eq_const_safe!($T::from_le(C.to_le()), C);
+                assert_eq_const_safe!($T::from_le(_0), _0);
+                assert_eq_const_safe!($T::from_le(_1), _1);
+                assert_eq_const_safe!(_0.to_le(), _0);
+                assert_eq_const_safe!(_1.to_le(), _1);
+            }
 
-        #[test]
-        fn test_be() {
-            assert_eq!($T::from_be(A.to_be()), A);
-            assert_eq!($T::from_be(B.to_be()), B);
-            assert_eq!($T::from_be(C.to_be()), C);
-            assert_eq!($T::from_be(_0), _0);
-            assert_eq!($T::from_be(_1), _1);
-            assert_eq!(_0.to_be(), _0);
-            assert_eq!(_1.to_be(), _1);
-        }
+            fn test_be() {
+                assert_eq_const_safe!($T::from_be(A.to_be()), A);
+                assert_eq_const_safe!($T::from_be(B.to_be()), B);
+                assert_eq_const_safe!($T::from_be(C.to_be()), C);
+                assert_eq_const_safe!($T::from_be(_0), _0);
+                assert_eq_const_safe!($T::from_be(_1), _1);
+                assert_eq_const_safe!(_0.to_be(), _0);
+                assert_eq_const_safe!(_1.to_be(), _1);
+            }
 
-        #[test]
-        fn test_signed_checked_div() {
-            assert_eq!((10 as $T).checked_div(2), Some(5));
-            assert_eq!((5 as $T).checked_div(0), None);
-            assert_eq!(isize::MIN.checked_div(-1), None);
-        }
+            fn test_signed_checked_div() {
+                assert_eq_const_safe!((10 as $T).checked_div(2), Some(5));
+                assert_eq_const_safe!((5 as $T).checked_div(0), None);
+                assert_eq_const_safe!(isize::MIN.checked_div(-1), None);
+            }
 
-        #[test]
-        fn test_saturating_abs() {
-            assert_eq!((0 as $T).saturating_abs(), 0);
-            assert_eq!((123 as $T).saturating_abs(), 123);
-            assert_eq!((-123 as $T).saturating_abs(), 123);
-            assert_eq!((MAX - 2).saturating_abs(), MAX - 2);
-            assert_eq!((MAX - 1).saturating_abs(), MAX - 1);
-            assert_eq!(MAX.saturating_abs(), MAX);
-            assert_eq!((MIN + 2).saturating_abs(), MAX - 1);
-            assert_eq!((MIN + 1).saturating_abs(), MAX);
-            assert_eq!(MIN.saturating_abs(), MAX);
-        }
+            fn test_saturating_abs() {
+                assert_eq_const_safe!((0 as $T).saturating_abs(), 0);
+                assert_eq_const_safe!((123 as $T).saturating_abs(), 123);
+                assert_eq_const_safe!((-123 as $T).saturating_abs(), 123);
+                assert_eq_const_safe!((MAX - 2).saturating_abs(), MAX - 2);
+                assert_eq_const_safe!((MAX - 1).saturating_abs(), MAX - 1);
+                assert_eq_const_safe!(MAX.saturating_abs(), MAX);
+                assert_eq_const_safe!((MIN + 2).saturating_abs(), MAX - 1);
+                assert_eq_const_safe!((MIN + 1).saturating_abs(), MAX);
+                assert_eq_const_safe!(MIN.saturating_abs(), MAX);
+            }
 
-        #[test]
-        fn test_saturating_neg() {
-            assert_eq!((0 as $T).saturating_neg(), 0);
-            assert_eq!((123 as $T).saturating_neg(), -123);
-            assert_eq!((-123 as $T).saturating_neg(), 123);
-            assert_eq!((MAX - 2).saturating_neg(), MIN + 3);
-            assert_eq!((MAX - 1).saturating_neg(), MIN + 2);
-            assert_eq!(MAX.saturating_neg(), MIN + 1);
-            assert_eq!((MIN + 2).saturating_neg(), MAX - 1);
-            assert_eq!((MIN + 1).saturating_neg(), MAX);
-            assert_eq!(MIN.saturating_neg(), MAX);
+            fn test_saturating_neg() {
+                assert_eq_const_safe!((0 as $T).saturating_neg(), 0);
+                assert_eq_const_safe!((123 as $T).saturating_neg(), -123);
+                assert_eq_const_safe!((-123 as $T).saturating_neg(), 123);
+                assert_eq_const_safe!((MAX - 2).saturating_neg(), MIN + 3);
+                assert_eq_const_safe!((MAX - 1).saturating_neg(), MIN + 2);
+                assert_eq_const_safe!(MAX.saturating_neg(), MIN + 1);
+                assert_eq_const_safe!((MIN + 2).saturating_neg(), MAX - 1);
+                assert_eq_const_safe!((MIN + 1).saturating_neg(), MAX);
+                assert_eq_const_safe!(MIN.saturating_neg(), MAX);
+            }
         }
 
         #[test]
@@ -222,173 +212,173 @@
             assert_eq!(from_str::<$T>("x"), None);
         }
 
-        #[test]
-        fn test_from_str_radix() {
-            assert_eq!($T::from_str_radix("123", 10), Ok(123 as $T));
-            assert_eq!($T::from_str_radix("1001", 2), Ok(9 as $T));
-            assert_eq!($T::from_str_radix("123", 8), Ok(83 as $T));
-            assert_eq!(i32::from_str_radix("123", 16), Ok(291 as i32));
-            assert_eq!(i32::from_str_radix("ffff", 16), Ok(65535 as i32));
-            assert_eq!(i32::from_str_radix("FFFF", 16), Ok(65535 as i32));
-            assert_eq!($T::from_str_radix("z", 36), Ok(35 as $T));
-            assert_eq!($T::from_str_radix("Z", 36), Ok(35 as $T));
+        test_runtime_and_compiletime! {
+            fn test_from_str_radix() {
+                assert_eq_const_safe!($T::from_str_radix("123", 10), Ok(123 as $T));
+                assert_eq_const_safe!($T::from_str_radix("1001", 2), Ok(9 as $T));
+                assert_eq_const_safe!($T::from_str_radix("123", 8), Ok(83 as $T));
+                assert_eq_const_safe!(i32::from_str_radix("123", 16), Ok(291 as i32));
+                assert_eq_const_safe!(i32::from_str_radix("ffff", 16), Ok(65535 as i32));
+                assert_eq_const_safe!(i32::from_str_radix("FFFF", 16), Ok(65535 as i32));
+                assert_eq_const_safe!($T::from_str_radix("z", 36), Ok(35 as $T));
+                assert_eq_const_safe!($T::from_str_radix("Z", 36), Ok(35 as $T));
 
-            assert_eq!($T::from_str_radix("-123", 10), Ok(-123 as $T));
-            assert_eq!($T::from_str_radix("-1001", 2), Ok(-9 as $T));
-            assert_eq!($T::from_str_radix("-123", 8), Ok(-83 as $T));
-            assert_eq!(i32::from_str_radix("-123", 16), Ok(-291 as i32));
-            assert_eq!(i32::from_str_radix("-ffff", 16), Ok(-65535 as i32));
-            assert_eq!(i32::from_str_radix("-FFFF", 16), Ok(-65535 as i32));
-            assert_eq!($T::from_str_radix("-z", 36), Ok(-35 as $T));
-            assert_eq!($T::from_str_radix("-Z", 36), Ok(-35 as $T));
+                assert_eq_const_safe!($T::from_str_radix("-123", 10), Ok(-123 as $T));
+                assert_eq_const_safe!($T::from_str_radix("-1001", 2), Ok(-9 as $T));
+                assert_eq_const_safe!($T::from_str_radix("-123", 8), Ok(-83 as $T));
+                assert_eq_const_safe!(i32::from_str_radix("-123", 16), Ok(-291 as i32));
+                assert_eq_const_safe!(i32::from_str_radix("-ffff", 16), Ok(-65535 as i32));
+                assert_eq_const_safe!(i32::from_str_radix("-FFFF", 16), Ok(-65535 as i32));
+                assert_eq_const_safe!($T::from_str_radix("-z", 36), Ok(-35 as $T));
+                assert_eq_const_safe!($T::from_str_radix("-Z", 36), Ok(-35 as $T));
 
-            assert_eq!($T::from_str_radix("Z", 35).ok(), None::<$T>);
-            assert_eq!($T::from_str_radix("-9", 2).ok(), None::<$T>);
-            assert_eq!($T::from_str_radix("10_0", 10).ok(), None::<$T>);
-            assert_eq!(u32::from_str_radix("-9", 10).ok(), None::<u32>);
-        }
+                assert!($T::from_str_radix("Z", 35).is_err());
+                assert!($T::from_str_radix("-9", 2).is_err());
+                assert!($T::from_str_radix("10_0", 10).is_err());
+                assert!(u32::from_str_radix("-9", 10).is_err());
+            }
 
-        #[test]
-        fn test_pow() {
-            let mut r = 2 as $T;
-            assert_eq!(r.pow(2), 4 as $T);
-            assert_eq!(r.pow(0), 1 as $T);
-            assert_eq!(r.wrapping_pow(2), 4 as $T);
-            assert_eq!(r.wrapping_pow(0), 1 as $T);
-            assert_eq!(r.checked_pow(2), Some(4 as $T));
-            assert_eq!(r.checked_pow(0), Some(1 as $T));
-            assert_eq!(r.overflowing_pow(2), (4 as $T, false));
-            assert_eq!(r.overflowing_pow(0), (1 as $T, false));
-            assert_eq!(r.saturating_pow(2), 4 as $T);
-            assert_eq!(r.saturating_pow(0), 1 as $T);
+            fn test_pow() {
+                {
+                    const R: $T = 2;
+                    assert_eq_const_safe!(R.pow(2), 4 as $T);
+                    assert_eq_const_safe!(R.pow(0), 1 as $T);
+                    assert_eq_const_safe!(R.wrapping_pow(2), 4 as $T);
+                    assert_eq_const_safe!(R.wrapping_pow(0), 1 as $T);
+                    assert_eq_const_safe!(R.checked_pow(2), Some(4 as $T));
+                    assert_eq_const_safe!(R.checked_pow(0), Some(1 as $T));
+                    assert_eq_const_safe!(R.overflowing_pow(2), (4 as $T, false));
+                    assert_eq_const_safe!(R.overflowing_pow(0), (1 as $T, false));
+                    assert_eq_const_safe!(R.saturating_pow(2), 4 as $T);
+                    assert_eq_const_safe!(R.saturating_pow(0), 1 as $T);
+                }
 
-            r = MAX;
-            // use `^` to represent .pow() with no overflow.
-            // if itest::MAX == 2^j-1, then itest is a `j` bit int,
-            // so that `itest::MAX*itest::MAX == 2^(2*j)-2^(j+1)+1`,
-            // thussaturating_pow the overflowing result is exactly 1.
-            assert_eq!(r.wrapping_pow(2), 1 as $T);
-            assert_eq!(r.checked_pow(2), None);
-            assert_eq!(r.overflowing_pow(2), (1 as $T, true));
-            assert_eq!(r.saturating_pow(2), MAX);
-            //test for negative exponent.
-            r = -2 as $T;
-            assert_eq!(r.pow(2), 4 as $T);
-            assert_eq!(r.pow(3), -8 as $T);
-            assert_eq!(r.pow(0), 1 as $T);
-            assert_eq!(r.wrapping_pow(2), 4 as $T);
-            assert_eq!(r.wrapping_pow(3), -8 as $T);
-            assert_eq!(r.wrapping_pow(0), 1 as $T);
-            assert_eq!(r.checked_pow(2), Some(4 as $T));
-            assert_eq!(r.checked_pow(3), Some(-8 as $T));
-            assert_eq!(r.checked_pow(0), Some(1 as $T));
-            assert_eq!(r.overflowing_pow(2), (4 as $T, false));
-            assert_eq!(r.overflowing_pow(3), (-8 as $T, false));
-            assert_eq!(r.overflowing_pow(0), (1 as $T, false));
-            assert_eq!(r.saturating_pow(2), 4 as $T);
-            assert_eq!(r.saturating_pow(3), -8 as $T);
-            assert_eq!(r.saturating_pow(0), 1 as $T);
-        }
+                {
+                    const R: $T = MAX;
+                    // use `^` to represent .pow() with no overflow.
+                    // if itest::MAX == 2^j-1, then itest is a `j` bit int,
+                    // so that `itest::MAX*itest::MAX == 2^(2*j)-2^(j+1)+1`,
+                    // thussaturating_pow the overflowing result is exactly 1.
+                    assert_eq_const_safe!(R.wrapping_pow(2), 1 as $T);
+                    assert_eq_const_safe!(R.checked_pow(2), None);
+                    assert_eq_const_safe!(R.overflowing_pow(2), (1 as $T, true));
+                    assert_eq_const_safe!(R.saturating_pow(2), MAX);
+                }
 
-        #[test]
-        fn test_div_floor() {
-            let a: $T = 8;
-            let b = 3;
-            assert_eq!(a.div_floor(b), 2);
-            assert_eq!(a.div_floor(-b), -3);
-            assert_eq!((-a).div_floor(b), -3);
-            assert_eq!((-a).div_floor(-b), 2);
-        }
+                {
+                    // test for negative exponent.
+                    const R: $T = -2;
+                    assert_eq_const_safe!(R.pow(2), 4 as $T);
+                    assert_eq_const_safe!(R.pow(3), -8 as $T);
+                    assert_eq_const_safe!(R.pow(0), 1 as $T);
+                    assert_eq_const_safe!(R.wrapping_pow(2), 4 as $T);
+                    assert_eq_const_safe!(R.wrapping_pow(3), -8 as $T);
+                    assert_eq_const_safe!(R.wrapping_pow(0), 1 as $T);
+                    assert_eq_const_safe!(R.checked_pow(2), Some(4 as $T));
+                    assert_eq_const_safe!(R.checked_pow(3), Some(-8 as $T));
+                    assert_eq_const_safe!(R.checked_pow(0), Some(1 as $T));
+                    assert_eq_const_safe!(R.overflowing_pow(2), (4 as $T, false));
+                    assert_eq_const_safe!(R.overflowing_pow(3), (-8 as $T, false));
+                    assert_eq_const_safe!(R.overflowing_pow(0), (1 as $T, false));
+                    assert_eq_const_safe!(R.saturating_pow(2), 4 as $T);
+                    assert_eq_const_safe!(R.saturating_pow(3), -8 as $T);
+                    assert_eq_const_safe!(R.saturating_pow(0), 1 as $T);
+                }
+            }
 
-        #[test]
-        fn test_div_ceil() {
-            let a: $T = 8;
-            let b = 3;
-            assert_eq!(a.div_ceil(b), 3);
-            assert_eq!(a.div_ceil(-b), -2);
-            assert_eq!((-a).div_ceil(b), -2);
-            assert_eq!((-a).div_ceil(-b), 3);
-        }
+            fn test_div_floor() {
+                const A: $T = 8;
+                const B: $T = 3;
+                assert_eq_const_safe!(A.div_floor(B), 2);
+                assert_eq_const_safe!(A.div_floor(-B), -3);
+                assert_eq_const_safe!((-A).div_floor(B), -3);
+                assert_eq_const_safe!((-A).div_floor(-B), 2);
+            }
 
-        #[test]
-        fn test_next_multiple_of() {
-            assert_eq!((16 as $T).next_multiple_of(8), 16);
-            assert_eq!((23 as $T).next_multiple_of(8), 24);
-            assert_eq!((16 as $T).next_multiple_of(-8), 16);
-            assert_eq!((23 as $T).next_multiple_of(-8), 16);
-            assert_eq!((-16 as $T).next_multiple_of(8), -16);
-            assert_eq!((-23 as $T).next_multiple_of(8), -16);
-            assert_eq!((-16 as $T).next_multiple_of(-8), -16);
-            assert_eq!((-23 as $T).next_multiple_of(-8), -24);
-            assert_eq!(MIN.next_multiple_of(-1), MIN);
-        }
+            fn test_div_ceil() {
+                const A: $T = 8;
+                const B: $T = 3;
+                assert_eq_const_safe!(A.div_ceil(B), 3);
+                assert_eq_const_safe!(A.div_ceil(-B), -2);
+                assert_eq_const_safe!((-A).div_ceil(B), -2);
+                assert_eq_const_safe!((-A).div_ceil(-B), 3);
+            }
 
-        #[test]
-        fn test_checked_next_multiple_of() {
-            assert_eq!((16 as $T).checked_next_multiple_of(8), Some(16));
-            assert_eq!((23 as $T).checked_next_multiple_of(8), Some(24));
-            assert_eq!((16 as $T).checked_next_multiple_of(-8), Some(16));
-            assert_eq!((23 as $T).checked_next_multiple_of(-8), Some(16));
-            assert_eq!((-16 as $T).checked_next_multiple_of(8), Some(-16));
-            assert_eq!((-23 as $T).checked_next_multiple_of(8), Some(-16));
-            assert_eq!((-16 as $T).checked_next_multiple_of(-8), Some(-16));
-            assert_eq!((-23 as $T).checked_next_multiple_of(-8), Some(-24));
-            assert_eq!((1 as $T).checked_next_multiple_of(0), None);
-            assert_eq!(MAX.checked_next_multiple_of(2), None);
-            assert_eq!(MIN.checked_next_multiple_of(-3), None);
-            assert_eq!(MIN.checked_next_multiple_of(-1), Some(MIN));
-        }
+            fn test_next_multiple_of() {
+                assert_eq_const_safe!((16 as $T).next_multiple_of(8), 16);
+                assert_eq_const_safe!((23 as $T).next_multiple_of(8), 24);
+                assert_eq_const_safe!((16 as $T).next_multiple_of(-8), 16);
+                assert_eq_const_safe!((23 as $T).next_multiple_of(-8), 16);
+                assert_eq_const_safe!((-16 as $T).next_multiple_of(8), -16);
+                assert_eq_const_safe!((-23 as $T).next_multiple_of(8), -16);
+                assert_eq_const_safe!((-16 as $T).next_multiple_of(-8), -16);
+                assert_eq_const_safe!((-23 as $T).next_multiple_of(-8), -24);
+                assert_eq_const_safe!(MIN.next_multiple_of(-1), MIN);
+            }
 
-        #[test]
-        fn test_carrying_add() {
-            assert_eq!($T::MAX.carrying_add(1, false), ($T::MIN, true));
-            assert_eq!($T::MAX.carrying_add(0, true), ($T::MIN, true));
-            assert_eq!($T::MAX.carrying_add(1, true), ($T::MIN + 1, true));
-            assert_eq!($T::MAX.carrying_add(-1, false), ($T::MAX - 1, false));
-            assert_eq!($T::MAX.carrying_add(-1, true), ($T::MAX, false)); // no intermediate overflow
-            assert_eq!($T::MIN.carrying_add(-1, false), ($T::MAX, true));
-            assert_eq!($T::MIN.carrying_add(-1, true), ($T::MIN, false)); // no intermediate overflow
-            assert_eq!((0 as $T).carrying_add($T::MAX, true), ($T::MIN, true));
-            assert_eq!((0 as $T).carrying_add($T::MIN, true), ($T::MIN + 1, false));
-        }
+            fn test_checked_next_multiple_of() {
+                assert_eq_const_safe!((16 as $T).checked_next_multiple_of(8), Some(16));
+                assert_eq_const_safe!((23 as $T).checked_next_multiple_of(8), Some(24));
+                assert_eq_const_safe!((16 as $T).checked_next_multiple_of(-8), Some(16));
+                assert_eq_const_safe!((23 as $T).checked_next_multiple_of(-8), Some(16));
+                assert_eq_const_safe!((-16 as $T).checked_next_multiple_of(8), Some(-16));
+                assert_eq_const_safe!((-23 as $T).checked_next_multiple_of(8), Some(-16));
+                assert_eq_const_safe!((-16 as $T).checked_next_multiple_of(-8), Some(-16));
+                assert_eq_const_safe!((-23 as $T).checked_next_multiple_of(-8), Some(-24));
+                assert_eq_const_safe!((1 as $T).checked_next_multiple_of(0), None);
+                assert_eq_const_safe!(MAX.checked_next_multiple_of(2), None);
+                assert_eq_const_safe!(MIN.checked_next_multiple_of(-3), None);
+                assert_eq_const_safe!(MIN.checked_next_multiple_of(-1), Some(MIN));
+            }
 
-        #[test]
-        fn test_borrowing_sub() {
-            assert_eq!($T::MIN.borrowing_sub(1, false), ($T::MAX, true));
-            assert_eq!($T::MIN.borrowing_sub(0, true), ($T::MAX, true));
-            assert_eq!($T::MIN.borrowing_sub(1, true), ($T::MAX - 1, true));
-            assert_eq!($T::MIN.borrowing_sub(-1, false), ($T::MIN + 1, false));
-            assert_eq!($T::MIN.borrowing_sub(-1, true), ($T::MIN, false)); // no intermediate overflow
-            assert_eq!($T::MAX.borrowing_sub(-1, false), ($T::MIN, true));
-            assert_eq!($T::MAX.borrowing_sub(-1, true), ($T::MAX, false)); // no intermediate overflow
-            assert_eq!((0 as $T).borrowing_sub($T::MIN, false), ($T::MIN, true));
-            assert_eq!((0 as $T).borrowing_sub($T::MIN, true), ($T::MAX, false));
-        }
+            fn test_carrying_add() {
+                assert_eq_const_safe!(MAX.carrying_add(1, false), (MIN, true));
+                assert_eq_const_safe!(MAX.carrying_add(0, true), (MIN, true));
+                assert_eq_const_safe!(MAX.carrying_add(1, true), (MIN + 1, true));
+                assert_eq_const_safe!(MAX.carrying_add(-1, false), (MAX - 1, false));
+                assert_eq_const_safe!(MAX.carrying_add(-1, true), (MAX, false)); // no intermediate overflow
+                assert_eq_const_safe!(MIN.carrying_add(-1, false), (MAX, true));
+                assert_eq_const_safe!(MIN.carrying_add(-1, true), (MIN, false)); // no intermediate overflow
+                assert_eq_const_safe!((0 as $T).carrying_add(MAX, true), (MIN, true));
+                assert_eq_const_safe!((0 as $T).carrying_add(MIN, true), (MIN + 1, false));
+            }
 
-        #[test]
-        fn test_midpoint() {
-            assert_eq!(<$T>::midpoint(1, 3), 2);
-            assert_eq!(<$T>::midpoint(3, 1), 2);
+            fn test_borrowing_sub() {
+                assert_eq_const_safe!(MIN.borrowing_sub(1, false), (MAX, true));
+                assert_eq_const_safe!(MIN.borrowing_sub(0, true), (MAX, true));
+                assert_eq_const_safe!(MIN.borrowing_sub(1, true), (MAX - 1, true));
+                assert_eq_const_safe!(MIN.borrowing_sub(-1, false), (MIN + 1, false));
+                assert_eq_const_safe!(MIN.borrowing_sub(-1, true), (MIN, false)); // no intermediate overflow
+                assert_eq_const_safe!(MAX.borrowing_sub(-1, false), (MIN, true));
+                assert_eq_const_safe!(MAX.borrowing_sub(-1, true), (MAX, false)); // no intermediate overflow
+                assert_eq_const_safe!((0 as $T).borrowing_sub(MIN, false), (MIN, true));
+                assert_eq_const_safe!((0 as $T).borrowing_sub(MIN, true), (MAX, false));
+            }
 
-            assert_eq!(<$T>::midpoint(0, 0), 0);
-            assert_eq!(<$T>::midpoint(0, 2), 1);
-            assert_eq!(<$T>::midpoint(2, 0), 1);
-            assert_eq!(<$T>::midpoint(2, 2), 2);
+            fn test_midpoint() {
+                assert_eq_const_safe!(<$T>::midpoint(1, 3), 2);
+                assert_eq_const_safe!(<$T>::midpoint(3, 1), 2);
 
-            assert_eq!(<$T>::midpoint(1, 4), 2);
-            assert_eq!(<$T>::midpoint(4, 1), 2);
-            assert_eq!(<$T>::midpoint(3, 4), 3);
-            assert_eq!(<$T>::midpoint(4, 3), 3);
+                assert_eq_const_safe!(<$T>::midpoint(0, 0), 0);
+                assert_eq_const_safe!(<$T>::midpoint(0, 2), 1);
+                assert_eq_const_safe!(<$T>::midpoint(2, 0), 1);
+                assert_eq_const_safe!(<$T>::midpoint(2, 2), 2);
 
-            assert_eq!(<$T>::midpoint(<$T>::MIN, <$T>::MAX), -1);
-            assert_eq!(<$T>::midpoint(<$T>::MAX, <$T>::MIN), -1);
-            assert_eq!(<$T>::midpoint(<$T>::MIN, <$T>::MIN), <$T>::MIN);
-            assert_eq!(<$T>::midpoint(<$T>::MAX, <$T>::MAX), <$T>::MAX);
+                assert_eq_const_safe!(<$T>::midpoint(1, 4), 2);
+                assert_eq_const_safe!(<$T>::midpoint(4, 1), 2);
+                assert_eq_const_safe!(<$T>::midpoint(3, 4), 3);
+                assert_eq_const_safe!(<$T>::midpoint(4, 3), 3);
 
-            assert_eq!(<$T>::midpoint(<$T>::MIN, 6), <$T>::MIN / 2 + 3);
-            assert_eq!(<$T>::midpoint(6, <$T>::MIN), <$T>::MIN / 2 + 3);
-            assert_eq!(<$T>::midpoint(<$T>::MAX, 6), <$T>::MAX / 2 + 3);
-            assert_eq!(<$T>::midpoint(6, <$T>::MAX), <$T>::MAX / 2 + 3);
+                assert_eq_const_safe!(<$T>::midpoint(<$T>::MIN, <$T>::MAX), 0);
+                assert_eq_const_safe!(<$T>::midpoint(<$T>::MAX, <$T>::MIN), 0);
+                assert_eq_const_safe!(<$T>::midpoint(<$T>::MIN, <$T>::MIN), <$T>::MIN);
+                assert_eq_const_safe!(<$T>::midpoint(<$T>::MAX, <$T>::MAX), <$T>::MAX);
+
+                assert_eq_const_safe!(<$T>::midpoint(<$T>::MIN, 6), <$T>::MIN / 2 + 3);
+                assert_eq_const_safe!(<$T>::midpoint(6, <$T>::MIN), <$T>::MIN / 2 + 3);
+                assert_eq_const_safe!(<$T>::midpoint(<$T>::MAX, 6), <$T>::MAX / 2 + 3);
+                assert_eq_const_safe!(<$T>::midpoint(6, <$T>::MAX), <$T>::MAX / 2 + 3);
+            }
         }
     };
 }
diff --git a/library/core/tests/num/midpoint.rs b/library/core/tests/num/midpoint.rs
new file mode 100644
index 0000000..71e9800
--- /dev/null
+++ b/library/core/tests/num/midpoint.rs
@@ -0,0 +1,54 @@
+//! Test the following expectations:
+//!  - midpoint(a, b) == (a + b) / 2
+//!  - midpoint(a, b) == midpoint(b, a)
+//!  - midpoint(-a, -b) == -midpoint(a, b)
+
+#[test]
+#[cfg(not(miri))]
+fn midpoint_obvious_impl_i8() {
+    for a in i8::MIN..=i8::MAX {
+        for b in i8::MIN..=i8::MAX {
+            assert_eq!(i8::midpoint(a, b), ((a as i16 + b as i16) / 2) as i8);
+        }
+    }
+}
+
+#[test]
+#[cfg(not(miri))]
+fn midpoint_obvious_impl_u8() {
+    for a in u8::MIN..=u8::MAX {
+        for b in u8::MIN..=u8::MAX {
+            assert_eq!(u8::midpoint(a, b), ((a as u16 + b as u16) / 2) as u8);
+        }
+    }
+}
+
+#[test]
+#[cfg(not(miri))]
+fn midpoint_order_expectation_i8() {
+    for a in i8::MIN..=i8::MAX {
+        for b in i8::MIN..=i8::MAX {
+            assert_eq!(i8::midpoint(a, b), i8::midpoint(b, a));
+        }
+    }
+}
+
+#[test]
+#[cfg(not(miri))]
+fn midpoint_order_expectation_u8() {
+    for a in u8::MIN..=u8::MAX {
+        for b in u8::MIN..=u8::MAX {
+            assert_eq!(u8::midpoint(a, b), u8::midpoint(b, a));
+        }
+    }
+}
+
+#[test]
+#[cfg(not(miri))]
+fn midpoint_negative_expectation() {
+    for a in 0..=i8::MAX {
+        for b in 0..=i8::MAX {
+            assert_eq!(i8::midpoint(-a, -b), -i8::midpoint(a, b));
+        }
+    }
+}
diff --git a/library/core/tests/num/mod.rs b/library/core/tests/num/mod.rs
index 6da9b9a..0add9a0 100644
--- a/library/core/tests/num/mod.rs
+++ b/library/core/tests/num/mod.rs
@@ -28,6 +28,7 @@
 mod flt2dec;
 mod int_log;
 mod int_sqrt;
+mod midpoint;
 mod ops;
 mod wrapping;
 
diff --git a/library/core/tests/num/uint_macros.rs b/library/core/tests/num/uint_macros.rs
index f4fa789..ad8e484 100644
--- a/library/core/tests/num/uint_macros.rs
+++ b/library/core/tests/num/uint_macros.rs
@@ -2,7 +2,6 @@
     ($T:ident) => {
         use core::ops::{BitAnd, BitOr, BitXor, Not, Shl, Shr};
         use core::$T::*;
-        use std::str::FromStr;
 
         use crate::num;
 
@@ -35,122 +34,115 @@
         const _0: $T = 0;
         const _1: $T = !0;
 
-        #[test]
-        fn test_count_ones() {
-            assert!(A.count_ones() == 3);
-            assert!(B.count_ones() == 2);
-            assert!(C.count_ones() == 5);
+        test_runtime_and_compiletime! {
+            fn test_count_ones() {
+                assert!(A.count_ones() == 3);
+                assert!(B.count_ones() == 2);
+                assert!(C.count_ones() == 5);
+            }
+
+            fn test_count_zeros() {
+                assert!(A.count_zeros() == $T::BITS - 3);
+                assert!(B.count_zeros() == $T::BITS - 2);
+                assert!(C.count_zeros() == $T::BITS - 5);
+            }
+
+            fn test_leading_trailing_ones() {
+                const A: $T = 0b0101_1111;
+                assert_eq_const_safe!(A.trailing_ones(), 5);
+                assert_eq_const_safe!((!A).leading_ones(), $T::BITS - 7);
+
+                assert_eq_const_safe!(A.reverse_bits().leading_ones(), 5);
+
+                assert_eq_const_safe!(_1.leading_ones(), $T::BITS);
+                assert_eq_const_safe!(_1.trailing_ones(), $T::BITS);
+
+                assert_eq_const_safe!((_1 << 1).trailing_ones(), 0);
+                assert_eq_const_safe!((_1 >> 1).leading_ones(), 0);
+
+                assert_eq_const_safe!((_1 << 1).leading_ones(), $T::BITS - 1);
+                assert_eq_const_safe!((_1 >> 1).trailing_ones(), $T::BITS - 1);
+
+                assert_eq_const_safe!(_0.leading_ones(), 0);
+                assert_eq_const_safe!(_0.trailing_ones(), 0);
+
+                const X: $T = 0b0010_1100;
+                assert_eq_const_safe!(X.leading_ones(), 0);
+                assert_eq_const_safe!(X.trailing_ones(), 0);
+            }
+
+            fn test_rotate() {
+                assert_eq_const_safe!(A.rotate_left(6).rotate_right(2).rotate_right(4), A);
+                assert_eq_const_safe!(B.rotate_left(3).rotate_left(2).rotate_right(5), B);
+                assert_eq_const_safe!(C.rotate_left(6).rotate_right(2).rotate_right(4), C);
+
+                // Rotating these should make no difference
+                //
+                // We test using 124 bits because to ensure that overlong bit shifts do
+                // not cause undefined behavior. See #10183.
+                assert_eq_const_safe!(_0.rotate_left(124), _0);
+                assert_eq_const_safe!(_1.rotate_left(124), _1);
+                assert_eq_const_safe!(_0.rotate_right(124), _0);
+                assert_eq_const_safe!(_1.rotate_right(124), _1);
+
+                // Rotating by 0 should have no effect
+                assert_eq_const_safe!(A.rotate_left(0), A);
+                assert_eq_const_safe!(B.rotate_left(0), B);
+                assert_eq_const_safe!(C.rotate_left(0), C);
+                // Rotating by a multiple of word size should also have no effect
+                assert_eq_const_safe!(A.rotate_left(128), A);
+                assert_eq_const_safe!(B.rotate_left(128), B);
+                assert_eq_const_safe!(C.rotate_left(128), C);
+            }
+
+            fn test_swap_bytes() {
+                assert_eq_const_safe!(A.swap_bytes().swap_bytes(), A);
+                assert_eq_const_safe!(B.swap_bytes().swap_bytes(), B);
+                assert_eq_const_safe!(C.swap_bytes().swap_bytes(), C);
+
+                // Swapping these should make no difference
+                assert_eq_const_safe!(_0.swap_bytes(), _0);
+                assert_eq_const_safe!(_1.swap_bytes(), _1);
+            }
+
+            fn test_reverse_bits() {
+                assert_eq_const_safe!(A.reverse_bits().reverse_bits(), A);
+                assert_eq_const_safe!(B.reverse_bits().reverse_bits(), B);
+                assert_eq_const_safe!(C.reverse_bits().reverse_bits(), C);
+
+                // Swapping these should make no difference
+                assert_eq_const_safe!(_0.reverse_bits(), _0);
+                assert_eq_const_safe!(_1.reverse_bits(), _1);
+            }
+
+            fn test_le() {
+                assert_eq_const_safe!($T::from_le(A.to_le()), A);
+                assert_eq_const_safe!($T::from_le(B.to_le()), B);
+                assert_eq_const_safe!($T::from_le(C.to_le()), C);
+                assert_eq_const_safe!($T::from_le(_0), _0);
+                assert_eq_const_safe!($T::from_le(_1), _1);
+                assert_eq_const_safe!(_0.to_le(), _0);
+                assert_eq_const_safe!(_1.to_le(), _1);
+            }
+
+            fn test_be() {
+                assert_eq_const_safe!($T::from_be(A.to_be()), A);
+                assert_eq_const_safe!($T::from_be(B.to_be()), B);
+                assert_eq_const_safe!($T::from_be(C.to_be()), C);
+                assert_eq_const_safe!($T::from_be(_0), _0);
+                assert_eq_const_safe!($T::from_be(_1), _1);
+                assert_eq_const_safe!(_0.to_be(), _0);
+                assert_eq_const_safe!(_1.to_be(), _1);
+            }
+
+            fn test_unsigned_checked_div() {
+                assert_eq_const_safe!((10 as $T).checked_div(2), Some(5));
+                assert_eq_const_safe!((5 as $T).checked_div(0), None);
+            }
         }
 
-        #[test]
-        fn test_count_zeros() {
-            assert!(A.count_zeros() == $T::BITS - 3);
-            assert!(B.count_zeros() == $T::BITS - 2);
-            assert!(C.count_zeros() == $T::BITS - 5);
-        }
-
-        #[test]
-        fn test_leading_trailing_ones() {
-            let a: $T = 0b0101_1111;
-            assert_eq!(a.trailing_ones(), 5);
-            assert_eq!((!a).leading_ones(), $T::BITS - 7);
-
-            assert_eq!(a.reverse_bits().leading_ones(), 5);
-
-            assert_eq!(_1.leading_ones(), $T::BITS);
-            assert_eq!(_1.trailing_ones(), $T::BITS);
-
-            assert_eq!((_1 << 1).trailing_ones(), 0);
-            assert_eq!((_1 >> 1).leading_ones(), 0);
-
-            assert_eq!((_1 << 1).leading_ones(), $T::BITS - 1);
-            assert_eq!((_1 >> 1).trailing_ones(), $T::BITS - 1);
-
-            assert_eq!(_0.leading_ones(), 0);
-            assert_eq!(_0.trailing_ones(), 0);
-
-            let x: $T = 0b0010_1100;
-            assert_eq!(x.leading_ones(), 0);
-            assert_eq!(x.trailing_ones(), 0);
-        }
-
-        #[test]
-        fn test_rotate() {
-            assert_eq!(A.rotate_left(6).rotate_right(2).rotate_right(4), A);
-            assert_eq!(B.rotate_left(3).rotate_left(2).rotate_right(5), B);
-            assert_eq!(C.rotate_left(6).rotate_right(2).rotate_right(4), C);
-
-            // Rotating these should make no difference
-            //
-            // We test using 124 bits because to ensure that overlong bit shifts do
-            // not cause undefined behaviour. See #10183.
-            assert_eq!(_0.rotate_left(124), _0);
-            assert_eq!(_1.rotate_left(124), _1);
-            assert_eq!(_0.rotate_right(124), _0);
-            assert_eq!(_1.rotate_right(124), _1);
-
-            // Rotating by 0 should have no effect
-            assert_eq!(A.rotate_left(0), A);
-            assert_eq!(B.rotate_left(0), B);
-            assert_eq!(C.rotate_left(0), C);
-            // Rotating by a multiple of word size should also have no effect
-            assert_eq!(A.rotate_left(128), A);
-            assert_eq!(B.rotate_left(128), B);
-            assert_eq!(C.rotate_left(128), C);
-        }
-
-        #[test]
-        fn test_swap_bytes() {
-            assert_eq!(A.swap_bytes().swap_bytes(), A);
-            assert_eq!(B.swap_bytes().swap_bytes(), B);
-            assert_eq!(C.swap_bytes().swap_bytes(), C);
-
-            // Swapping these should make no difference
-            assert_eq!(_0.swap_bytes(), _0);
-            assert_eq!(_1.swap_bytes(), _1);
-        }
-
-        #[test]
-        fn test_reverse_bits() {
-            assert_eq!(A.reverse_bits().reverse_bits(), A);
-            assert_eq!(B.reverse_bits().reverse_bits(), B);
-            assert_eq!(C.reverse_bits().reverse_bits(), C);
-
-            // Swapping these should make no difference
-            assert_eq!(_0.reverse_bits(), _0);
-            assert_eq!(_1.reverse_bits(), _1);
-        }
-
-        #[test]
-        fn test_le() {
-            assert_eq!($T::from_le(A.to_le()), A);
-            assert_eq!($T::from_le(B.to_le()), B);
-            assert_eq!($T::from_le(C.to_le()), C);
-            assert_eq!($T::from_le(_0), _0);
-            assert_eq!($T::from_le(_1), _1);
-            assert_eq!(_0.to_le(), _0);
-            assert_eq!(_1.to_le(), _1);
-        }
-
-        #[test]
-        fn test_be() {
-            assert_eq!($T::from_be(A.to_be()), A);
-            assert_eq!($T::from_be(B.to_be()), B);
-            assert_eq!($T::from_be(C.to_be()), C);
-            assert_eq!($T::from_be(_0), _0);
-            assert_eq!($T::from_be(_1), _1);
-            assert_eq!(_0.to_be(), _0);
-            assert_eq!(_1.to_be(), _1);
-        }
-
-        #[test]
-        fn test_unsigned_checked_div() {
-            assert!((10 as $T).checked_div(2) == Some(5));
-            assert!((5 as $T).checked_div(0) == None);
-        }
-
-        fn from_str<T: FromStr>(t: &str) -> Option<T> {
-            FromStr::from_str(t).ok()
+        fn from_str<T: core::str::FromStr>(t: &str) -> Option<T> {
+            core::str::FromStr::from_str(t).ok()
         }
 
         #[test]
@@ -166,52 +158,55 @@
             assert_eq!(from_str::<$T>("x"), None);
         }
 
-        #[test]
-        pub fn test_parse_bytes() {
-            assert_eq!($T::from_str_radix("123", 10), Ok(123 as $T));
-            assert_eq!($T::from_str_radix("1001", 2), Ok(9 as $T));
-            assert_eq!($T::from_str_radix("123", 8), Ok(83 as $T));
-            assert_eq!(u16::from_str_radix("123", 16), Ok(291 as u16));
-            assert_eq!(u16::from_str_radix("ffff", 16), Ok(65535 as u16));
-            assert_eq!($T::from_str_radix("z", 36), Ok(35 as $T));
+        test_runtime_and_compiletime! {
+            fn test_parse_bytes() {
+                assert_eq_const_safe!($T::from_str_radix("123", 10), Ok(123 as $T));
+                assert_eq_const_safe!($T::from_str_radix("1001", 2), Ok(9 as $T));
+                assert_eq_const_safe!($T::from_str_radix("123", 8), Ok(83 as $T));
+                assert_eq_const_safe!(u16::from_str_radix("123", 16), Ok(291 as u16));
+                assert_eq_const_safe!(u16::from_str_radix("ffff", 16), Ok(65535 as u16));
+                assert_eq_const_safe!($T::from_str_radix("z", 36), Ok(35 as $T));
 
-            assert_eq!($T::from_str_radix("Z", 10).ok(), None::<$T>);
-            assert_eq!($T::from_str_radix("_", 2).ok(), None::<$T>);
-        }
+                assert!($T::from_str_radix("Z", 10).is_err());
+                assert!($T::from_str_radix("_", 2).is_err());
+            }
 
-        #[test]
-        fn test_pow() {
-            let mut r = 2 as $T;
-            assert_eq!(r.pow(2), 4 as $T);
-            assert_eq!(r.pow(0), 1 as $T);
-            assert_eq!(r.wrapping_pow(2), 4 as $T);
-            assert_eq!(r.wrapping_pow(0), 1 as $T);
-            assert_eq!(r.checked_pow(2), Some(4 as $T));
-            assert_eq!(r.checked_pow(0), Some(1 as $T));
-            assert_eq!(r.overflowing_pow(2), (4 as $T, false));
-            assert_eq!(r.overflowing_pow(0), (1 as $T, false));
-            assert_eq!(r.saturating_pow(2), 4 as $T);
-            assert_eq!(r.saturating_pow(0), 1 as $T);
+            fn test_pow() {
+                {
+                    const R: $T = 2;
+                    assert_eq_const_safe!(R.pow(2), 4 as $T);
+                    assert_eq_const_safe!(R.pow(0), 1 as $T);
+                    assert_eq_const_safe!(R.wrapping_pow(2), 4 as $T);
+                    assert_eq_const_safe!(R.wrapping_pow(0), 1 as $T);
+                    assert_eq_const_safe!(R.checked_pow(2), Some(4 as $T));
+                    assert_eq_const_safe!(R.checked_pow(0), Some(1 as $T));
+                    assert_eq_const_safe!(R.overflowing_pow(2), (4 as $T, false));
+                    assert_eq_const_safe!(R.overflowing_pow(0), (1 as $T, false));
+                    assert_eq_const_safe!(R.saturating_pow(2), 4 as $T);
+                    assert_eq_const_safe!(R.saturating_pow(0), 1 as $T);
+                }
 
-            r = MAX;
-            // use `^` to represent .pow() with no overflow.
-            // if itest::MAX == 2^j-1, then itest is a `j` bit int,
-            // so that `itest::MAX*itest::MAX == 2^(2*j)-2^(j+1)+1`,
-            // thussaturating_pow the overflowing result is exactly 1.
-            assert_eq!(r.wrapping_pow(2), 1 as $T);
-            assert_eq!(r.checked_pow(2), None);
-            assert_eq!(r.overflowing_pow(2), (1 as $T, true));
-            assert_eq!(r.saturating_pow(2), MAX);
-        }
+                {
+                    const R: $T = $T::MAX;
+                    // use `^` to represent .pow() with no overflow.
+                    // if itest::MAX == 2^j-1, then itest is a `j` bit int,
+                    // so that `itest::MAX*itest::MAX == 2^(2*j)-2^(j+1)+1`,
+                    // thussaturating_pow the overflowing result is exactly 1.
+                    assert_eq_const_safe!(R.wrapping_pow(2), 1 as $T);
+                    assert_eq_const_safe!(R.checked_pow(2), None);
+                    assert_eq_const_safe!(R.overflowing_pow(2), (1 as $T, true));
+                    assert_eq_const_safe!(R.saturating_pow(2), MAX);
+                }
+            }
 
-        #[test]
-        fn test_isqrt() {
-            assert_eq!((0 as $T).isqrt(), 0 as $T);
-            assert_eq!((1 as $T).isqrt(), 1 as $T);
-            assert_eq!((2 as $T).isqrt(), 1 as $T);
-            assert_eq!((99 as $T).isqrt(), 9 as $T);
-            assert_eq!((100 as $T).isqrt(), 10 as $T);
-            assert_eq!($T::MAX.isqrt(), (1 << ($T::BITS / 2)) - 1);
+            fn test_isqrt() {
+                assert_eq_const_safe!((0 as $T).isqrt(), 0 as $T);
+                assert_eq_const_safe!((1 as $T).isqrt(), 1 as $T);
+                assert_eq_const_safe!((2 as $T).isqrt(), 1 as $T);
+                assert_eq_const_safe!((99 as $T).isqrt(), 9 as $T);
+                assert_eq_const_safe!((100 as $T).isqrt(), 10 as $T);
+                assert_eq_const_safe!($T::MAX.isqrt(), (1 << ($T::BITS / 2)) - 1);
+            }
         }
 
         #[cfg(not(miri))] // Miri is too slow
@@ -233,85 +228,79 @@
             }
         }
 
-        #[test]
-        fn test_div_floor() {
-            assert_eq!((8 as $T).div_floor(3), 2);
-        }
+        test_runtime_and_compiletime! {
+            fn test_div_floor() {
+                assert_eq_const_safe!((8 as $T).div_floor(3), 2);
+            }
 
-        #[test]
-        fn test_div_ceil() {
-            assert_eq!((8 as $T).div_ceil(3), 3);
-        }
+            fn test_div_ceil() {
+                assert_eq_const_safe!((8 as $T).div_ceil(3), 3);
+            }
 
-        #[test]
-        fn test_next_multiple_of() {
-            assert_eq!((16 as $T).next_multiple_of(8), 16);
-            assert_eq!((23 as $T).next_multiple_of(8), 24);
-            assert_eq!(MAX.next_multiple_of(1), MAX);
-        }
+            fn test_next_multiple_of() {
+                assert_eq_const_safe!((16 as $T).next_multiple_of(8), 16);
+                assert_eq_const_safe!((23 as $T).next_multiple_of(8), 24);
+                assert_eq_const_safe!(MAX.next_multiple_of(1), MAX);
+            }
 
-        #[test]
-        fn test_checked_next_multiple_of() {
-            assert_eq!((16 as $T).checked_next_multiple_of(8), Some(16));
-            assert_eq!((23 as $T).checked_next_multiple_of(8), Some(24));
-            assert_eq!((1 as $T).checked_next_multiple_of(0), None);
-            assert_eq!(MAX.checked_next_multiple_of(2), None);
-        }
+            fn test_checked_next_multiple_of() {
+                assert_eq_const_safe!((16 as $T).checked_next_multiple_of(8), Some(16));
+                assert_eq_const_safe!((23 as $T).checked_next_multiple_of(8), Some(24));
+                assert_eq_const_safe!((1 as $T).checked_next_multiple_of(0), None);
+                assert_eq_const_safe!(MAX.checked_next_multiple_of(2), None);
+            }
 
-        #[test]
-        fn test_is_next_multiple_of() {
-            assert!((12 as $T).is_multiple_of(4));
-            assert!(!(12 as $T).is_multiple_of(5));
-            assert!((0 as $T).is_multiple_of(0));
-            assert!(!(12 as $T).is_multiple_of(0));
-        }
+            fn test_is_next_multiple_of() {
+                assert!((12 as $T).is_multiple_of(4));
+                assert!(!(12 as $T).is_multiple_of(5));
+                assert!((0 as $T).is_multiple_of(0));
+                assert!(!(12 as $T).is_multiple_of(0));
+            }
 
-        #[test]
-        fn test_carrying_add() {
-            assert_eq!($T::MAX.carrying_add(1, false), (0, true));
-            assert_eq!($T::MAX.carrying_add(0, true), (0, true));
-            assert_eq!($T::MAX.carrying_add(1, true), (1, true));
+            fn test_carrying_add() {
+                assert_eq_const_safe!($T::MAX.carrying_add(1, false), (0, true));
+                assert_eq_const_safe!($T::MAX.carrying_add(0, true), (0, true));
+                assert_eq_const_safe!($T::MAX.carrying_add(1, true), (1, true));
 
-            assert_eq!($T::MIN.carrying_add($T::MAX, false), ($T::MAX, false));
-            assert_eq!($T::MIN.carrying_add(0, true), (1, false));
-            assert_eq!($T::MIN.carrying_add($T::MAX, true), (0, true));
-        }
+                assert_eq_const_safe!($T::MIN.carrying_add($T::MAX, false), ($T::MAX, false));
+                assert_eq_const_safe!($T::MIN.carrying_add(0, true), (1, false));
+                assert_eq_const_safe!($T::MIN.carrying_add($T::MAX, true), (0, true));
+            }
 
-        #[test]
-        fn test_borrowing_sub() {
-            assert_eq!($T::MIN.borrowing_sub(1, false), ($T::MAX, true));
-            assert_eq!($T::MIN.borrowing_sub(0, true), ($T::MAX, true));
-            assert_eq!($T::MIN.borrowing_sub(1, true), ($T::MAX - 1, true));
+            fn test_borrowing_sub() {
+                assert_eq_const_safe!($T::MIN.borrowing_sub(1, false), ($T::MAX, true));
+                assert_eq_const_safe!($T::MIN.borrowing_sub(0, true), ($T::MAX, true));
+                assert_eq_const_safe!($T::MIN.borrowing_sub(1, true), ($T::MAX - 1, true));
 
-            assert_eq!($T::MAX.borrowing_sub($T::MAX, false), (0, false));
-            assert_eq!($T::MAX.borrowing_sub(0, true), ($T::MAX - 1, false));
-            assert_eq!($T::MAX.borrowing_sub($T::MAX, true), ($T::MAX, true));
-        }
+                assert_eq_const_safe!($T::MAX.borrowing_sub($T::MAX, false), (0, false));
+                assert_eq_const_safe!($T::MAX.borrowing_sub(0, true), ($T::MAX - 1, false));
+                assert_eq_const_safe!($T::MAX.borrowing_sub($T::MAX, true), ($T::MAX, true));
+            }
 
-        #[test]
-        fn test_midpoint() {
-            assert_eq!(<$T>::midpoint(1, 3), 2);
-            assert_eq!(<$T>::midpoint(3, 1), 2);
+            fn test_midpoint() {
+                assert_eq_const_safe!(<$T>::midpoint(1, 3), 2);
+                assert_eq_const_safe!(<$T>::midpoint(3, 1), 2);
 
-            assert_eq!(<$T>::midpoint(0, 0), 0);
-            assert_eq!(<$T>::midpoint(0, 2), 1);
-            assert_eq!(<$T>::midpoint(2, 0), 1);
-            assert_eq!(<$T>::midpoint(2, 2), 2);
+                assert_eq_const_safe!(<$T>::midpoint(0, 0), 0);
+                assert_eq_const_safe!(<$T>::midpoint(0, 2), 1);
+                assert_eq_const_safe!(<$T>::midpoint(2, 0), 1);
+                assert_eq_const_safe!(<$T>::midpoint(2, 2), 2);
 
-            assert_eq!(<$T>::midpoint(1, 4), 2);
-            assert_eq!(<$T>::midpoint(4, 1), 2);
-            assert_eq!(<$T>::midpoint(3, 4), 3);
-            assert_eq!(<$T>::midpoint(4, 3), 3);
+                assert_eq_const_safe!(<$T>::midpoint(1, 4), 2);
+                assert_eq_const_safe!(<$T>::midpoint(4, 1), 2);
+                assert_eq_const_safe!(<$T>::midpoint(3, 4), 3);
+                assert_eq_const_safe!(<$T>::midpoint(4, 3), 3);
 
-            assert_eq!(<$T>::midpoint(<$T>::MIN, <$T>::MAX), (<$T>::MAX - <$T>::MIN) / 2);
-            assert_eq!(<$T>::midpoint(<$T>::MAX, <$T>::MIN), (<$T>::MAX - <$T>::MIN) / 2);
-            assert_eq!(<$T>::midpoint(<$T>::MIN, <$T>::MIN), <$T>::MIN);
-            assert_eq!(<$T>::midpoint(<$T>::MAX, <$T>::MAX), <$T>::MAX);
+                assert_eq_const_safe!(<$T>::midpoint(<$T>::MIN, <$T>::MAX), (<$T>::MAX - <$T>::MIN) / 2);
+                assert_eq_const_safe!(<$T>::midpoint(<$T>::MAX, <$T>::MIN), (<$T>::MAX - <$T>::MIN) / 2);
+                assert_eq_const_safe!(<$T>::midpoint(<$T>::MIN, <$T>::MIN), <$T>::MIN);
+                assert_eq_const_safe!(<$T>::midpoint(<$T>::MAX, <$T>::MAX), <$T>::MAX);
 
-            assert_eq!(<$T>::midpoint(<$T>::MIN, 6), <$T>::MIN / 2 + 3);
-            assert_eq!(<$T>::midpoint(6, <$T>::MIN), <$T>::MIN / 2 + 3);
-            assert_eq!(<$T>::midpoint(<$T>::MAX, 6), (<$T>::MAX - <$T>::MIN) / 2 + 3);
-            assert_eq!(<$T>::midpoint(6, <$T>::MAX), (<$T>::MAX - <$T>::MIN) / 2 + 3);
+                assert_eq_const_safe!(<$T>::midpoint(<$T>::MIN, 6), <$T>::MIN / 2 + 3);
+                assert_eq_const_safe!(<$T>::midpoint(6, <$T>::MIN), <$T>::MIN / 2 + 3);
+                assert_eq_const_safe!(<$T>::midpoint(<$T>::MAX, 6), (<$T>::MAX - <$T>::MIN) / 2 + 3);
+                assert_eq_const_safe!(<$T>::midpoint(6, <$T>::MAX), (<$T>::MAX - <$T>::MIN) / 2 + 3);
+            }
         }
     };
 }
diff --git a/library/proc_macro/src/bridge/symbol.rs b/library/proc_macro/src/bridge/symbol.rs
index 37aaee6..edad6e7 100644
--- a/library/proc_macro/src/bridge/symbol.rs
+++ b/library/proc_macro/src/bridge/symbol.rs
@@ -76,7 +76,7 @@
                 .all(|b| matches!(b, b'_' | b'a'..=b'z' | b'A'..=b'Z' | b'0'..=b'9'))
     }
 
-    // Mimics the behaviour of `Symbol::can_be_raw` from `rustc_span`
+    // Mimics the behavior of `Symbol::can_be_raw` from `rustc_span`
     fn can_be_raw(string: &str) -> bool {
         match string {
             "_" | "super" | "self" | "Self" | "crate" => false,
diff --git a/library/std/src/collections/hash/map/tests.rs b/library/std/src/collections/hash/map/tests.rs
index fa8ea95..b79ad1c 100644
--- a/library/std/src/collections/hash/map/tests.rs
+++ b/library/std/src/collections/hash/map/tests.rs
@@ -1098,7 +1098,7 @@
                 _ => panic!(),
             });
             catch_unwind(AssertUnwindSafe(|| while it.next().is_some() {})).unwrap_err();
-            // Iterator behaviour after a panic is explicitly unspecified,
+            // Iterator behavior after a panic is explicitly unspecified,
             // so this is just the current implementation:
             let result = catch_unwind(AssertUnwindSafe(|| it.next()));
             assert!(result.is_err());
diff --git a/library/std/src/env.rs b/library/std/src/env.rs
index 97a1b84..d732a15 100644
--- a/library/std/src/env.rs
+++ b/library/std/src/env.rs
@@ -618,7 +618,7 @@
 ///
 /// # Deprecation
 ///
-/// This function is deprecated because the behaviour on Windows is not correct.
+/// This function is deprecated because the behavior on Windows is not correct.
 /// The 'HOME' environment variable is not standard on Windows, and may not produce
 /// desired results; for instance, under Cygwin or Mingw it will return `/home/you`
 /// when it should return `C:\Users\you`.
diff --git a/library/std/src/io/impls.rs b/library/std/src/io/impls.rs
index 8502354..b952c85 100644
--- a/library/std/src/io/impls.rs
+++ b/library/std/src/io/impls.rs
@@ -453,6 +453,29 @@
         Ok(n)
     }
 
+    fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
+        let (front, back) = self.as_slices();
+
+        // Use only the front buffer if it is big enough to fill `buf`, else use
+        // the back buffer too.
+        match buf.split_at_mut_checked(front.len()) {
+            None => buf.copy_from_slice(&front[..buf.len()]),
+            Some((buf_front, buf_back)) => match back.split_at_checked(buf_back.len()) {
+                Some((back, _)) => {
+                    buf_front.copy_from_slice(front);
+                    buf_back.copy_from_slice(back);
+                }
+                None => {
+                    self.clear();
+                    return Err(io::Error::READ_EXACT_EOF);
+                }
+            },
+        }
+
+        self.drain(..buf.len());
+        Ok(())
+    }
+
     #[inline]
     fn read_buf(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> {
         let (ref mut front, _) = self.as_slices();
@@ -462,6 +485,29 @@
         Ok(())
     }
 
+    fn read_buf_exact(&mut self, mut cursor: BorrowedCursor<'_>) -> io::Result<()> {
+        let len = cursor.capacity();
+        let (front, back) = self.as_slices();
+
+        match front.split_at_checked(cursor.capacity()) {
+            Some((front, _)) => cursor.append(front),
+            None => {
+                cursor.append(front);
+                match back.split_at_checked(cursor.capacity()) {
+                    Some((back, _)) => cursor.append(back),
+                    None => {
+                        cursor.append(back);
+                        self.clear();
+                        return Err(io::Error::READ_EXACT_EOF);
+                    }
+                }
+            }
+        }
+
+        self.drain(..len);
+        Ok(())
+    }
+
     #[inline]
     fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
         // The total len is known upfront so we can reserve it in a single call.
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 8c1a3c7..1de52eb 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -364,6 +364,7 @@
 #![feature(std_internals)]
 #![feature(str_internals)]
 #![feature(strict_provenance_atomic_ptr)]
+#![feature(sync_unsafe_cell)]
 #![feature(ub_checks)]
 // tidy-alphabetical-end
 //
diff --git a/library/std/src/os/unix/fs.rs b/library/std/src/os/unix/fs.rs
index a964db2..ba6481f 100644
--- a/library/std/src/os/unix/fs.rs
+++ b/library/std/src/os/unix/fs.rs
@@ -153,7 +153,7 @@
     ///
     /// It is possible to inadvertently set this flag, like in the example below.
     /// Therefore, it is important to be vigilant while changing options to mitigate
-    /// unexpected behaviour.
+    /// unexpected behavior.
     ///
     /// ```no_run
     /// use std::fs::File;
diff --git a/library/std/src/path.rs b/library/std/src/path.rs
index 63edfdb..62125f8 100644
--- a/library/std/src/path.rs
+++ b/library/std/src/path.rs
@@ -1167,7 +1167,7 @@
 /// path.push(r"..\otherdir");
 /// path.push("system32");
 ///
-/// The behaviour of `PathBuf` may be changed to a panic on such inputs
+/// The behavior of `PathBuf` may be changed to a panic on such inputs
 /// in the future. [`Extend::extend`] should be used to add multi-part paths.
 #[cfg_attr(not(test), rustc_diagnostic_item = "PathBuf")]
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -1409,7 +1409,7 @@
     /// (That is, it will have the same parent.)
     ///
     /// The argument is not sanitized, so can include separators. This
-    /// behaviour may be changed to a panic in the future.
+    /// behavior may be changed to a panic in the future.
     ///
     /// [`self.file_name`]: Path::file_name
     /// [`pop`]: PathBuf::pop
diff --git a/library/std/src/process.rs b/library/std/src/process.rs
index f24fe35..6933528 100644
--- a/library/std/src/process.rs
+++ b/library/std/src/process.rs
@@ -119,7 +119,7 @@
 //! when given a `.bat` file as the application to run, it will automatically
 //! convert that into running `cmd.exe /c` with the batch file as the next argument.
 //!
-//! For historical reasons Rust currently preserves this behaviour when using
+//! For historical reasons Rust currently preserves this behavior when using
 //! [`Command::new`], and escapes the arguments according to `cmd.exe` rules.
 //! Due to the complexity of `cmd.exe` argument handling, it might not be
 //! possible to safely escape some special characters, and using them will result
@@ -2318,7 +2318,7 @@
 /// Rust IO buffers (eg, from `BufWriter`) will not be flushed.
 /// Likewise, C stdio buffers will (on most platforms) not be flushed.
 ///
-/// This is in contrast to the default behaviour of [`panic!`] which unwinds
+/// This is in contrast to the default behavior of [`panic!`] which unwinds
 /// the current thread's stack and calls all destructors.
 /// When `panic="abort"` is set, either as an argument to `rustc` or in a
 /// crate's Cargo.toml, [`panic!`] and `abort` are similar. However,
diff --git a/library/std/src/process/tests.rs b/library/std/src/process/tests.rs
index 88cc95c..fb0b495 100644
--- a/library/std/src/process/tests.rs
+++ b/library/std/src/process/tests.rs
@@ -96,9 +96,23 @@
 #[test]
 #[cfg_attr(any(windows, target_os = "vxworks"), ignore)]
 fn set_current_dir_works() {
+    // On many Unix platforms this will use the posix_spawn path.
     let mut cmd = shell_cmd();
     cmd.arg("-c").arg("pwd").current_dir("/").stdout(Stdio::piped());
     assert_eq!(run_output(cmd), "/\n");
+
+    // Also test the fork/exec path by setting a pre_exec function.
+    #[cfg(unix)]
+    {
+        use crate::os::unix::process::CommandExt;
+
+        let mut cmd = shell_cmd();
+        cmd.arg("-c").arg("pwd").current_dir("/").stdout(Stdio::piped());
+        unsafe {
+            cmd.pre_exec(|| Ok(()));
+        }
+        assert_eq!(run_output(cmd), "/\n");
+    }
 }
 
 #[test]
diff --git a/library/std/src/random.rs b/library/std/src/random.rs
index cdb88c7..45f51dd 100644
--- a/library/std/src/random.rs
+++ b/library/std/src/random.rs
@@ -38,7 +38,7 @@
 /// Vita                   | `arc4random_buf`
 /// Hermit                 | `read_entropy`
 /// Horizon                | `getrandom` shim
-/// Hurd, L4Re, QNX        | `/dev/urandom`
+/// AIX, Hurd, L4Re, QNX   | `/dev/urandom`
 /// Redox                  | `/scheme/rand`
 /// RTEMS                  | [`arc4random_buf`](https://docs.rtems.org/branches/master/bsp-howto/getentropy.html)
 /// SGX                    | [`rdrand`](https://en.wikipedia.org/wiki/RDRAND)
diff --git a/library/std/src/rt.rs b/library/std/src/rt.rs
index 80e7c3c..b249223 100644
--- a/library/std/src/rt.rs
+++ b/library/std/src/rt.rs
@@ -110,7 +110,7 @@
     // handle does not match the current ID, we should attempt to use the
     // current thread ID here instead of unconditionally creating a new
     // one. Also see #130210.
-    let thread = Thread::new_main(thread::current_id());
+    let thread = unsafe { Thread::new_main(thread::current_id()) };
     if let Err(_thread) = thread::set_current(thread) {
         // `thread::current` will create a new handle if none has been set yet.
         // Thus, if someone uses it before main, this call will fail. That's a
diff --git a/library/std/src/sync/mpmc/array.rs b/library/std/src/sync/mpmc/array.rs
index 34acd9c..2c8ba41 100644
--- a/library/std/src/sync/mpmc/array.rs
+++ b/library/std/src/sync/mpmc/array.rs
@@ -484,7 +484,7 @@
     ///
     /// # Panicking
     /// If a destructor panics, the remaining messages are leaked, matching the
-    /// behaviour of the unbounded channel.
+    /// behavior of the unbounded channel.
     ///
     /// # Safety
     /// This method must only be called when dropping the last receiver. The
diff --git a/library/std/src/sync/once.rs b/library/std/src/sync/once.rs
index 993df93..27db4b6 100644
--- a/library/std/src/sync/once.rs
+++ b/library/std/src/sync/once.rs
@@ -288,7 +288,7 @@
     ///
     /// If this [`Once`] has been poisoned because an initialization closure has
     /// panicked, this method will also panic. Use [`wait_force`](Self::wait_force)
-    /// if this behaviour is not desired.
+    /// if this behavior is not desired.
     #[unstable(feature = "once_wait", issue = "127527")]
     pub fn wait(&self) {
         if !self.inner.is_completed() {
diff --git a/library/std/src/sync/once_lock.rs b/library/std/src/sync/once_lock.rs
index be615a5..0ae3cf4 100644
--- a/library/std/src/sync/once_lock.rs
+++ b/library/std/src/sync/once_lock.rs
@@ -634,6 +634,26 @@
 
 #[stable(feature = "once_cell", since = "1.70.0")]
 impl<T: PartialEq> PartialEq for OnceLock<T> {
+    /// Equality for two `OnceLock`s.
+    ///
+    /// Two `OnceLock`s are equal if they either both contain values and their
+    /// values are equal, or if neither contains a value.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::sync::OnceLock;
+    ///
+    /// let five = OnceLock::new();
+    /// five.set(5).unwrap();
+    ///
+    /// let also_five = OnceLock::new();
+    /// also_five.set(5).unwrap();
+    ///
+    /// assert!(five == also_five);
+    ///
+    /// assert!(OnceLock::<u32>::new() == OnceLock::<u32>::new());
+    /// ```
     #[inline]
     fn eq(&self, other: &OnceLock<T>) -> bool {
         self.get() == other.get()
diff --git a/library/std/src/sys/pal/unix/process/process_fuchsia.rs b/library/std/src/sys/pal/unix/process/process_fuchsia.rs
index 5d0110c..8f7d786 100644
--- a/library/std/src/sys/pal/unix/process/process_fuchsia.rs
+++ b/library/std/src/sys/pal/unix/process/process_fuchsia.rs
@@ -273,7 +273,7 @@
         // We don't know what someone who calls into_raw() will do with this value, but it should
         // have the conventional Unix representation. Despite the fact that this is not
         // standardised in SuS or POSIX, all Unix systems encode the signal and exit status the
-        // same way. (Ie the WIFEXITED, WEXITSTATUS etc. macros have identical behaviour on every
+        // same way. (Ie the WIFEXITED, WEXITSTATUS etc. macros have identical behavior on every
         // Unix.)
         //
         // The caller of `std::os::unix::into_raw` is probably wanting a Unix exit status, and may
diff --git a/library/std/src/sys/pal/unix/process/process_unix.rs b/library/std/src/sys/pal/unix/process/process_unix.rs
index 4551d49..8faf1fd 100644
--- a/library/std/src/sys/pal/unix/process/process_unix.rs
+++ b/library/std/src/sys/pal/unix/process/process_unix.rs
@@ -448,7 +448,6 @@
         use core::sync::atomic::{AtomicU8, Ordering};
 
         use crate::mem::MaybeUninit;
-        use crate::sys::weak::weak;
         use crate::sys::{self, cvt_nz, on_broken_pipe_flag_used};
 
         if self.get_gid().is_some()
@@ -462,6 +461,8 @@
 
         cfg_if::cfg_if! {
             if #[cfg(target_os = "linux")] {
+                use crate::sys::weak::weak;
+
                 weak! {
                     fn pidfd_spawnp(
                         *mut libc::c_int,
@@ -575,16 +576,44 @@
             }
         }
 
-        // Solaris, glibc 2.29+, and musl 1.24+ can set a new working directory,
-        // and maybe others will gain this non-POSIX function too. We'll check
-        // for this weak symbol as soon as it's needed, so we can return early
-        // otherwise to do a manual chdir before exec.
-        weak! {
-            fn posix_spawn_file_actions_addchdir_np(
-                *mut libc::posix_spawn_file_actions_t,
-                *const libc::c_char
-            ) -> libc::c_int
+        type PosixSpawnAddChdirFn = unsafe extern "C" fn(
+            *mut libc::posix_spawn_file_actions_t,
+            *const libc::c_char,
+        ) -> libc::c_int;
+
+        /// Get the function pointer for adding a chdir action to a
+        /// `posix_spawn_file_actions_t`, if available, assuming a dynamic libc.
+        ///
+        /// Some platforms can set a new working directory for a spawned process in the
+        /// `posix_spawn` path. This function looks up the function pointer for adding
+        /// such an action to a `posix_spawn_file_actions_t` struct.
+        #[cfg(not(all(target_os = "linux", target_env = "musl")))]
+        fn get_posix_spawn_addchdir() -> Option<PosixSpawnAddChdirFn> {
+            use crate::sys::weak::weak;
+
+            weak! {
+                fn posix_spawn_file_actions_addchdir_np(
+                    *mut libc::posix_spawn_file_actions_t,
+                    *const libc::c_char
+                ) -> libc::c_int
+            }
+
+            posix_spawn_file_actions_addchdir_np.get()
         }
+
+        /// Get the function pointer for adding a chdir action to a
+        /// `posix_spawn_file_actions_t`, if available, on platforms where the function
+        /// is known to exist.
+        ///
+        /// Weak symbol lookup doesn't work with statically linked libcs, so in cases
+        /// where static linking is possible we need to either check for the presence
+        /// of the symbol at compile time or know about it upfront.
+        #[cfg(all(target_os = "linux", target_env = "musl"))]
+        fn get_posix_spawn_addchdir() -> Option<PosixSpawnAddChdirFn> {
+            // Our minimum required musl supports this function, so we can just use it.
+            Some(libc::posix_spawn_file_actions_addchdir_np)
+        }
+
         let addchdir = match self.get_cwd() {
             Some(cwd) => {
                 if cfg!(target_vendor = "apple") {
@@ -597,7 +626,10 @@
                         return Ok(None);
                     }
                 }
-                match posix_spawn_file_actions_addchdir_np.get() {
+                // Check for the availability of the posix_spawn addchdir
+                // function now. If it isn't available, bail and use the
+                // fork/exec path.
+                match get_posix_spawn_addchdir() {
                     Some(f) => Some((f, cwd)),
                     None => return Ok(None),
                 }
diff --git a/library/std/src/sys/pal/windows/fs.rs b/library/std/src/sys/pal/windows/fs.rs
index b237fa4..5a9bfcc 100644
--- a/library/std/src/sys/pal/windows/fs.rs
+++ b/library/std/src/sys/pal/windows/fs.rs
@@ -1159,7 +1159,7 @@
     // Formerly, symlink creation required the SeCreateSymbolicLink privilege. For the Windows 10
     // Creators Update, Microsoft loosened this to allow unprivileged symlink creation if the
     // computer is in Developer Mode, but SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE must be
-    // added to dwFlags to opt into this behaviour.
+    // added to dwFlags to opt into this behavior.
     let result = cvt(unsafe {
         c::CreateSymbolicLinkW(
             link.as_ptr(),
diff --git a/library/std/src/sys/pal/windows/process.rs b/library/std/src/sys/pal/windows/process.rs
index 95b51e7..17bb03f 100644
--- a/library/std/src/sys/pal/windows/process.rs
+++ b/library/std/src/sys/pal/windows/process.rs
@@ -47,7 +47,7 @@
     }
 }
 
-// Comparing Windows environment variable keys[1] are behaviourally the
+// Comparing Windows environment variable keys[1] are behaviorally the
 // composition of two operations[2]:
 //
 // 1. Case-fold both strings. This is done using a language-independent
@@ -338,8 +338,8 @@
 
         // If at least one of stdin, stdout or stderr are set (i.e. are non null)
         // then set the `hStd` fields in `STARTUPINFO`.
-        // Otherwise skip this and allow the OS to apply its default behaviour.
-        // This provides more consistent behaviour between Win7 and Win8+.
+        // Otherwise skip this and allow the OS to apply its default behavior.
+        // This provides more consistent behavior between Win7 and Win8+.
         let is_set = |stdio: &Handle| !stdio.as_raw_handle().is_null();
         if is_set(&stderr) || is_set(&stdout) || is_set(&stdin) {
             si.dwFlags |= c::STARTF_USESTDHANDLES;
@@ -507,7 +507,7 @@
     Exists: FnMut(PathBuf) -> Option<Vec<u16>>,
 {
     // 1. Child paths
-    // This is for consistency with Rust's historic behaviour.
+    // This is for consistency with Rust's historic behavior.
     if let Some(paths) = child_paths {
         for path in env::split_paths(paths).filter(|p| !p.as_os_str().is_empty()) {
             if let Some(path) = exists(path) {
diff --git a/library/std/src/sys/pal/windows/process/tests.rs b/library/std/src/sys/pal/windows/process/tests.rs
index b567151..1bcc5fa 100644
--- a/library/std/src/sys/pal/windows/process/tests.rs
+++ b/library/std/src/sys/pal/windows/process/tests.rs
@@ -191,7 +191,7 @@
 
     /*
     Some of the following tests may need to be changed if you are deliberately
-    changing the behaviour of `resolve_exe`.
+    changing the behavior of `resolve_exe`.
     */
 
     let empty_paths = || None;
diff --git a/library/std/src/sys/pal/windows/thread.rs b/library/std/src/sys/pal/windows/thread.rs
index 28bce52..2c8ce42 100644
--- a/library/std/src/sys/pal/windows/thread.rs
+++ b/library/std/src/sys/pal/windows/thread.rs
@@ -99,7 +99,7 @@
         }
         // Attempt to use high-precision sleep (Windows 10, version 1803+).
         // On error fallback to the standard `Sleep` function.
-        // Also preserves the zero duration behaviour of `Sleep`.
+        // Also preserves the zero duration behavior of `Sleep`.
         if dur.is_zero() || high_precision_sleep(dur).is_err() {
             unsafe { c::Sleep(super::dur2timeout(dur)) }
         }
diff --git a/library/std/src/sys/path/windows/tests.rs b/library/std/src/sys/path/windows/tests.rs
index 623c623..f2a60e3 100644
--- a/library/std/src/sys/path/windows/tests.rs
+++ b/library/std/src/sys/path/windows/tests.rs
@@ -119,7 +119,7 @@
 
 /// See #101358.
 ///
-/// Note that the exact behaviour here may change in the future.
+/// Note that the exact behavior here may change in the future.
 /// In which case this test will need to adjusted.
 #[test]
 fn broken_unc_path() {
diff --git a/library/std/src/sys/random/linux.rs b/library/std/src/sys/random/linux.rs
index 073fdc4..e3cb792 100644
--- a/library/std/src/sys/random/linux.rs
+++ b/library/std/src/sys/random/linux.rs
@@ -30,7 +30,7 @@
 //! data the system has available at the time.
 //!
 //! So in conclusion, we always want the output of the non-blocking pool, but
-//! may need to wait until it is initalized. The default behaviour of `getrandom`
+//! may need to wait until it is initalized. The default behavior of `getrandom`
 //! is to wait until the non-blocking pool is initialized and then draw from there,
 //! so if `getrandom` is available, we use its default to generate the bytes. For
 //! `HashMap`, however, we need to specify the `GRND_INSECURE` flags, but that
@@ -39,7 +39,7 @@
 //! succeed if the pool is initialized. If it isn't, we fall back to the file
 //! access method.
 //!
-//! The behaviour of `/dev/urandom` is inverse to that of `getrandom`: it always
+//! The behavior of `/dev/urandom` is inverse to that of `getrandom`: it always
 //! yields data, even when the pool is not initialized. For generating `HashMap`
 //! keys, this is not important, so we can use it directly. For secure data
 //! however, we need to wait until initialization, which we can do by `poll`ing
diff --git a/library/std/src/sys/random/mod.rs b/library/std/src/sys/random/mod.rs
index edc2cac..f42351d 100644
--- a/library/std/src/sys/random/mod.rs
+++ b/library/std/src/sys/random/mod.rs
@@ -40,6 +40,7 @@
         mod horizon;
         pub use horizon::fill_bytes;
     } else if #[cfg(any(
+        target_os = "aix",
         target_os = "hurd",
         target_os = "l4re",
         target_os = "nto",
diff --git a/library/std/src/sys/sync/condvar/no_threads.rs b/library/std/src/sys/sync/condvar/no_threads.rs
index 36b89c5..2a67ed7 100644
--- a/library/std/src/sys/sync/condvar/no_threads.rs
+++ b/library/std/src/sys/sync/condvar/no_threads.rs
@@ -5,7 +5,7 @@
 
 impl Condvar {
     #[inline]
-    #[rustc_const_stable(feature = "const_locks", since = "1.63.0")]
+    #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_locks", since = "1.63.0"))]
     pub const fn new() -> Condvar {
         Condvar {}
     }
diff --git a/library/std/src/sys/sync/condvar/pthread.rs b/library/std/src/sys/sync/condvar/pthread.rs
index 986cd0c..cee728e 100644
--- a/library/std/src/sys/sync/condvar/pthread.rs
+++ b/library/std/src/sys/sync/condvar/pthread.rs
@@ -66,7 +66,7 @@
             // On DragonFly pthread_cond_destroy() returns EINVAL if called on
             // a condvar that was just initialized with
             // libc::PTHREAD_COND_INITIALIZER. Once it is used or
-            // pthread_cond_init() is called, this behaviour no longer occurs.
+            // pthread_cond_init() is called, this behavior no longer occurs.
             debug_assert!(r == 0 || r == libc::EINVAL);
         } else {
             debug_assert_eq!(r, 0);
diff --git a/library/std/src/sys/sync/mutex/no_threads.rs b/library/std/src/sys/sync/mutex/no_threads.rs
index 4a13c55..7b24357 100644
--- a/library/std/src/sys/sync/mutex/no_threads.rs
+++ b/library/std/src/sys/sync/mutex/no_threads.rs
@@ -10,7 +10,7 @@
 
 impl Mutex {
     #[inline]
-    #[rustc_const_stable(feature = "const_locks", since = "1.63.0")]
+    #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_locks", since = "1.63.0"))]
     pub const fn new() -> Mutex {
         Mutex { locked: Cell::new(false) }
     }
diff --git a/library/std/src/sys/sync/mutex/pthread.rs b/library/std/src/sys/sync/mutex/pthread.rs
index 87c95f4..abd5812 100644
--- a/library/std/src/sys/sync/mutex/pthread.rs
+++ b/library/std/src/sys/sync/mutex/pthread.rs
@@ -65,7 +65,7 @@
             // On DragonFly pthread_mutex_destroy() returns EINVAL if called on a
             // mutex that was just initialized with libc::PTHREAD_MUTEX_INITIALIZER.
             // Once it is used (locked/unlocked) or pthread_mutex_init() is called,
-            // this behaviour no longer occurs.
+            // this behavior no longer occurs.
             debug_assert!(r == 0 || r == libc::EINVAL);
         } else {
             debug_assert_eq!(r, 0);
@@ -88,7 +88,7 @@
     /// since the `lock` and the lock must have occurred on the current thread.
     ///
     /// # Safety
-    /// Causes undefined behaviour if the mutex is not locked.
+    /// Causes undefined behavior if the mutex is not locked.
     #[inline]
     pub(crate) unsafe fn get_assert_locked(&self) -> *mut libc::pthread_mutex_t {
         unsafe { self.inner.get_unchecked().0.get() }
diff --git a/library/std/src/sys/sync/once/no_threads.rs b/library/std/src/sys/sync/once/no_threads.rs
index cdcffe7..fb1b496 100644
--- a/library/std/src/sys/sync/once/no_threads.rs
+++ b/library/std/src/sys/sync/once/no_threads.rs
@@ -35,7 +35,7 @@
 
 impl Once {
     #[inline]
-    #[rustc_const_stable(feature = "const_once_new", since = "1.32.0")]
+    #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_once_new", since = "1.32.0"))]
     pub const fn new() -> Once {
         Once { state: Cell::new(State::Incomplete) }
     }
diff --git a/library/std/src/sys/sync/once/queue.rs b/library/std/src/sys/sync/once/queue.rs
index 3e83a4a..177d0d7 100644
--- a/library/std/src/sys/sync/once/queue.rs
+++ b/library/std/src/sys/sync/once/queue.rs
@@ -116,7 +116,7 @@
 
 impl Once {
     #[inline]
-    #[rustc_const_stable(feature = "const_once_new", since = "1.32.0")]
+    #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_once_new", since = "1.32.0"))]
     pub const fn new() -> Once {
         Once { state_and_queue: AtomicPtr::new(ptr::without_provenance_mut(INCOMPLETE)) }
     }
diff --git a/library/std/src/sys/sync/once_box.rs b/library/std/src/sys/sync/once_box.rs
index 9d24db2..4105af5 100644
--- a/library/std/src/sys/sync/once_box.rs
+++ b/library/std/src/sys/sync/once_box.rs
@@ -36,7 +36,7 @@
     /// ```
     ///
     /// # Safety
-    /// This causes undefined behaviour if the assumption above is violated.
+    /// This causes undefined behavior if the assumption above is violated.
     #[inline]
     pub unsafe fn get_unchecked(&self) -> &T {
         unsafe { &*self.ptr.load(Relaxed) }
diff --git a/library/std/src/sys/sync/rwlock/futex.rs b/library/std/src/sys/sync/rwlock/futex.rs
index df22c36..447048e 100644
--- a/library/std/src/sys/sync/rwlock/futex.rs
+++ b/library/std/src/sys/sync/rwlock/futex.rs
@@ -283,7 +283,7 @@
         futex_wake(&self.writer_notify)
         // Note that FreeBSD and DragonFlyBSD don't tell us whether they woke
         // up any threads or not, and always return `false` here. That still
-        // results in correct behaviour: it just means readers get woken up as
+        // results in correct behavior: it just means readers get woken up as
         // well in case both readers and writers were waiting.
     }
 
diff --git a/library/std/src/sys/sync/rwlock/no_threads.rs b/library/std/src/sys/sync/rwlock/no_threads.rs
index 789ef9b..6965e2e 100644
--- a/library/std/src/sys/sync/rwlock/no_threads.rs
+++ b/library/std/src/sys/sync/rwlock/no_threads.rs
@@ -10,7 +10,7 @@
 
 impl RwLock {
     #[inline]
-    #[rustc_const_stable(feature = "const_locks", since = "1.63.0")]
+    #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_locks", since = "1.63.0"))]
     pub const fn new() -> RwLock {
         RwLock { mode: Cell::new(0) }
     }
diff --git a/library/std/src/sys/sync/rwlock/queue.rs b/library/std/src/sys/sync/rwlock/queue.rs
index 733f51c..8899619 100644
--- a/library/std/src/sys/sync/rwlock/queue.rs
+++ b/library/std/src/sys/sync/rwlock/queue.rs
@@ -8,7 +8,7 @@
 //! * `pthread` is an external library, meaning the fast path of acquiring an
 //! uncontended lock cannot be inlined.
 //! * Some platforms (at least glibc before version 2.25) have buggy implementations
-//! that can easily lead to undefined behaviour in safe Rust code when not properly
+//! that can easily lead to undefined behavior in safe Rust code when not properly
 //! guarded against.
 //! * On some platforms (e.g. macOS), the lock is very slow.
 //!
diff --git a/library/std/src/sys/sync/thread_parking/darwin.rs b/library/std/src/sys/sync/thread_parking/darwin.rs
index 96e3d23..0553c5e 100644
--- a/library/std/src/sys/sync/thread_parking/darwin.rs
+++ b/library/std/src/sys/sync/thread_parking/darwin.rs
@@ -5,7 +5,7 @@
 //! rejection from the App Store).
 //!
 //! Therefore, we need to look for other synchronization primitives. Luckily, Darwin
-//! supports semaphores, which allow us to implement the behaviour we need with
+//! supports semaphores, which allow us to implement the behavior we need with
 //! only one primitive (as opposed to a mutex-condvar pair). We use the semaphore
 //! provided by libdispatch, as the underlying Mach semaphore is only dubiously
 //! public.
diff --git a/library/std/src/sys/sync/thread_parking/pthread.rs b/library/std/src/sys/sync/thread_parking/pthread.rs
index 5f195d0..76df73b 100644
--- a/library/std/src/sys/sync/thread_parking/pthread.rs
+++ b/library/std/src/sys/sync/thread_parking/pthread.rs
@@ -97,7 +97,7 @@
     /// The constructed parker must never be moved.
     pub unsafe fn new_in_place(parker: *mut Parker) {
         // Use the default mutex implementation to allow for simpler initialization.
-        // This could lead to undefined behaviour when deadlocking. This is avoided
+        // This could lead to undefined behavior when deadlocking. This is avoided
         // by not deadlocking. Note in particular the unlocking operation before any
         // panic, as code after the panic could try to park again.
         (&raw mut (*parker).state).write(AtomicUsize::new(EMPTY));
diff --git a/library/std/src/sys/sync/thread_parking/windows7.rs b/library/std/src/sys/sync/thread_parking/windows7.rs
index 8f7e66c..f7585e8 100644
--- a/library/std/src/sys/sync/thread_parking/windows7.rs
+++ b/library/std/src/sys/sync/thread_parking/windows7.rs
@@ -35,7 +35,7 @@
 // different implementations.
 //
 // Unfortunately, NT Keyed Events are an undocumented Windows API. However:
-// - This API is relatively simple with obvious behaviour, and there are
+// - This API is relatively simple with obvious behavior, and there are
 //   several (unofficial) articles documenting the details. [1]
 // - `parking_lot` has been using this API for years (on Windows versions
 //   before Windows 8). [2] Many big projects extensively use parking_lot,
@@ -43,7 +43,7 @@
 // - It is the underlying API used by Windows SRW locks and Windows critical
 //   sections. [3] [4]
 // - The source code of the implementations of Wine, ReactOs, and Windows XP
-//   are available and match the expected behaviour.
+//   are available and match the expected behavior.
 // - The main risk with an undocumented API is that it might change in the
 //   future. But since we only use it for older versions of Windows, that's not
 //   a problem.
diff --git a/library/std/src/sys/thread_local/key/racy.rs b/library/std/src/sys/thread_local/key/racy.rs
index 69f1145..97df899 100644
--- a/library/std/src/sys/thread_local/key/racy.rs
+++ b/library/std/src/sys/thread_local/key/racy.rs
@@ -30,7 +30,7 @@
 const KEY_SENTVAL: usize = libc::PTHREAD_KEYS_MAX + 1;
 
 impl LazyKey {
-    #[rustc_const_unstable(feature = "thread_local_internals", issue = "none")]
+    #[cfg_attr(bootstrap, rustc_const_unstable(feature = "thread_local_internals", issue = "none"))]
     pub const fn new(dtor: Option<unsafe extern "C" fn(*mut u8)>) -> LazyKey {
         LazyKey { key: atomic::AtomicUsize::new(KEY_SENTVAL), dtor }
     }
diff --git a/library/std/src/sys/thread_local/os.rs b/library/std/src/sys/thread_local/os.rs
index f5a2aaa..58f291f 100644
--- a/library/std/src/sys/thread_local/os.rs
+++ b/library/std/src/sys/thread_local/os.rs
@@ -60,7 +60,7 @@
 }
 
 impl<T: 'static> Storage<T> {
-    #[rustc_const_unstable(feature = "thread_local_internals", issue = "none")]
+    #[cfg_attr(bootstrap, rustc_const_unstable(feature = "thread_local_internals", issue = "none"))]
     pub const fn new() -> Storage<T> {
         Storage { key: LazyKey::new(Some(destroy_value::<T>)), marker: PhantomData }
     }
diff --git a/library/std/src/sys/thread_local/statik.rs b/library/std/src/sys/thread_local/statik.rs
index ba94caa..4da01a8 100644
--- a/library/std/src/sys/thread_local/statik.rs
+++ b/library/std/src/sys/thread_local/statik.rs
@@ -14,12 +14,11 @@
     (@key $t:ty, const $init:expr) => {{
         const __INIT: $t = $init;
 
+        // NOTE: Please update the shadowing test in `tests/thread.rs` if these types are renamed.
         unsafe {
-            use $crate::thread::LocalKey;
-            use $crate::thread::local_impl::EagerStorage;
-
-            LocalKey::new(|_| {
-                static VAL: EagerStorage<$t> = EagerStorage { value: __INIT };
+            $crate::thread::LocalKey::new(|_| {
+                static VAL: $crate::thread::local_impl::EagerStorage<$t> =
+                    $crate::thread::local_impl::EagerStorage { value: __INIT };
                 &VAL.value
             })
         }
diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs
index 88bf186..9edb3fa 100644
--- a/library/std/src/thread/local.rs
+++ b/library/std/src/thread/local.rs
@@ -237,7 +237,7 @@
         reason = "recently added to create a key",
         issue = "none"
     )]
-    #[rustc_const_unstable(feature = "thread_local_internals", issue = "none")]
+    #[cfg_attr(bootstrap, rustc_const_unstable(feature = "thread_local_internals", issue = "none"))]
     pub const unsafe fn new(inner: fn(Option<&mut Option<T>>) -> *const T) -> LocalKey<T> {
         LocalKey { inner }
     }
diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs
index 3975388..227ee9d 100644
--- a/library/std/src/thread/mod.rs
+++ b/library/std/src/thread/mod.rs
@@ -158,9 +158,12 @@
 #[cfg(all(test, not(any(target_os = "emscripten", target_os = "wasi"))))]
 mod tests;
 
+use core::cell::SyncUnsafeCell;
+use core::ffi::CStr;
+use core::mem::MaybeUninit;
+
 use crate::any::Any;
 use crate::cell::UnsafeCell;
-use crate::ffi::CStr;
 use crate::marker::PhantomData;
 use crate::mem::{self, ManuallyDrop, forget};
 use crate::num::NonZero;
@@ -875,7 +878,7 @@
 ///
 /// # Platform-specific behavior
 ///
-/// This function uses [`sleep`] internally, see its platform-specific behaviour.
+/// This function uses [`sleep`] internally, see its platform-specific behavior.
 ///
 ///
 /// # Examples
@@ -946,7 +949,7 @@
 }
 
 /// Used to ensure that `park` and `park_timeout` do not unwind, as that can
-/// cause undefined behaviour if not handled correctly (see #102398 for context).
+/// cause undefined behavior if not handled correctly (see #102398 for context).
 struct PanicGuard;
 
 impl Drop for PanicGuard {
@@ -1125,7 +1128,7 @@
     let guard = PanicGuard;
     // SAFETY: park_timeout is called on the parker owned by this thread.
     unsafe {
-        current().inner.as_ref().parker().park_timeout(dur);
+        current().0.parker().park_timeout(dur);
     }
     // No panic occurred, do not abort.
     forget(guard);
@@ -1232,30 +1235,31 @@
 // Thread
 ////////////////////////////////////////////////////////////////////////////////
 
-/// The internal representation of a `Thread`'s name.
-enum ThreadName {
-    Main,
-    Other(ThreadNameString),
-    Unnamed,
-}
-
 // This module ensures private fields are kept private, which is necessary to enforce the safety requirements.
 mod thread_name_string {
     use core::str;
 
-    use super::ThreadName;
     use crate::ffi::{CStr, CString};
 
     /// Like a `String` it's guaranteed UTF-8 and like a `CString` it's null terminated.
     pub(crate) struct ThreadNameString {
         inner: CString,
     }
+
+    impl ThreadNameString {
+        pub fn as_str(&self) -> &str {
+            // SAFETY: `self.inner` is only initialised via `String`, which upholds the validity invariant of `str`.
+            unsafe { str::from_utf8_unchecked(self.inner.to_bytes()) }
+        }
+    }
+
     impl core::ops::Deref for ThreadNameString {
         type Target = CStr;
         fn deref(&self) -> &CStr {
             &self.inner
         }
     }
+
     impl From<String> for ThreadNameString {
         fn from(s: String) -> Self {
             Self {
@@ -1263,34 +1267,82 @@
             }
         }
     }
-    impl ThreadName {
-        pub fn as_cstr(&self) -> Option<&CStr> {
-            match self {
-                ThreadName::Main => Some(c"main"),
-                ThreadName::Other(other) => Some(other),
-                ThreadName::Unnamed => None,
-            }
-        }
-
-        pub fn as_str(&self) -> Option<&str> {
-            // SAFETY: `as_cstr` can only return `Some` for a fixed CStr or a `ThreadNameString`,
-            // which is guaranteed to be UTF-8.
-            self.as_cstr().map(|s| unsafe { str::from_utf8_unchecked(s.to_bytes()) })
-        }
-    }
 }
 pub(crate) use thread_name_string::ThreadNameString;
 
-/// The internal representation of a `Thread` handle
-struct Inner {
-    name: ThreadName, // Guaranteed to be UTF-8
+static MAIN_THREAD_INFO: SyncUnsafeCell<(MaybeUninit<ThreadId>, MaybeUninit<Parker>)> =
+    SyncUnsafeCell::new((MaybeUninit::uninit(), MaybeUninit::uninit()));
+
+/// The internal representation of a `Thread` that is not the main thread.
+struct OtherInner {
+    name: Option<ThreadNameString>,
     id: ThreadId,
     parker: Parker,
 }
 
+/// The internal representation of a `Thread` handle.
+#[derive(Clone)]
+enum Inner {
+    /// Represents the main thread. May only be constructed by Thread::new_main.
+    Main(&'static (ThreadId, Parker)),
+    /// Represents any other thread.
+    Other(Pin<Arc<OtherInner>>),
+}
+
 impl Inner {
-    fn parker(self: Pin<&Self>) -> Pin<&Parker> {
-        unsafe { Pin::map_unchecked(self, |inner| &inner.parker) }
+    fn id(&self) -> ThreadId {
+        match self {
+            Self::Main((thread_id, _)) => *thread_id,
+            Self::Other(other) => other.id,
+        }
+    }
+
+    fn cname(&self) -> Option<&CStr> {
+        match self {
+            Self::Main(_) => Some(c"main"),
+            Self::Other(other) => other.name.as_deref(),
+        }
+    }
+
+    fn name(&self) -> Option<&str> {
+        match self {
+            Self::Main(_) => Some("main"),
+            Self::Other(other) => other.name.as_ref().map(ThreadNameString::as_str),
+        }
+    }
+
+    fn into_raw(self) -> *const () {
+        match self {
+            // Just return the pointer to `MAIN_THREAD_INFO`.
+            Self::Main(ptr) => crate::ptr::from_ref(ptr).cast(),
+            Self::Other(arc) => {
+                // Safety: We only expose an opaque pointer, which maintains the `Pin` invariant.
+                let inner = unsafe { Pin::into_inner_unchecked(arc) };
+                Arc::into_raw(inner) as *const ()
+            }
+        }
+    }
+
+    /// # Safety
+    ///
+    /// See [`Thread::from_raw`].
+    unsafe fn from_raw(ptr: *const ()) -> Self {
+        // If the pointer is to `MAIN_THREAD_INFO`, we know it is the `Main` variant.
+        if crate::ptr::eq(ptr.cast(), &MAIN_THREAD_INFO) {
+            Self::Main(unsafe { &*ptr.cast() })
+        } else {
+            // Safety: Upheld by caller
+            Self::Other(unsafe { Pin::new_unchecked(Arc::from_raw(ptr as *const OtherInner)) })
+        }
+    }
+
+    fn parker(&self) -> Pin<&Parker> {
+        match self {
+            Self::Main((_, parker_ref)) => Pin::static_ref(parker_ref),
+            Self::Other(inner) => unsafe {
+                Pin::map_unchecked(inner.as_ref(), |inner| &inner.parker)
+            },
+        }
     }
 }
 
@@ -1314,33 +1366,47 @@
 /// docs of [`Builder`] and [`spawn`] for more details.
 ///
 /// [`thread::current`]: current::current
-pub struct Thread {
-    inner: Pin<Arc<Inner>>,
-}
+pub struct Thread(Inner);
 
 impl Thread {
     /// Used only internally to construct a thread object without spawning.
     pub(crate) fn new(id: ThreadId, name: String) -> Thread {
-        Self::new_inner(id, ThreadName::Other(name.into()))
+        Self::new_inner(id, Some(ThreadNameString::from(name)))
     }
 
     pub(crate) fn new_unnamed(id: ThreadId) -> Thread {
-        Self::new_inner(id, ThreadName::Unnamed)
+        Self::new_inner(id, None)
     }
 
-    /// Constructs the thread handle for the main thread.
-    pub(crate) fn new_main(id: ThreadId) -> Thread {
-        Self::new_inner(id, ThreadName::Main)
+    /// Used in runtime to construct main thread
+    ///
+    /// # Safety
+    ///
+    /// This must only ever be called once, and must be called on the main thread.
+    pub(crate) unsafe fn new_main(thread_id: ThreadId) -> Thread {
+        // Safety: As this is only called once and on the main thread, nothing else is accessing MAIN_THREAD_INFO
+        // as the only other read occurs in `main_thread_info` *after* the main thread has been constructed,
+        // and this function is the only one that constructs the main thread.
+        //
+        // Pre-main thread spawning cannot hit this either, as the caller promises that this is only called on the main thread.
+        let main_thread_info = unsafe { &mut *MAIN_THREAD_INFO.get() };
+
+        unsafe { Parker::new_in_place((&raw mut main_thread_info.1).cast()) };
+        main_thread_info.0.write(thread_id);
+
+        // Store a `'static` ref to the initialised ThreadId and Parker,
+        // to avoid having to repeatedly prove initialisation.
+        Self(Inner::Main(unsafe { &*MAIN_THREAD_INFO.get().cast() }))
     }
 
-    fn new_inner(id: ThreadId, name: ThreadName) -> Thread {
+    fn new_inner(id: ThreadId, name: Option<ThreadNameString>) -> Thread {
         // We have to use `unsafe` here to construct the `Parker` in-place,
         // which is required for the UNIX implementation.
         //
         // SAFETY: We pin the Arc immediately after creation, so its address never
         // changes.
         let inner = unsafe {
-            let mut arc = Arc::<Inner>::new_uninit();
+            let mut arc = Arc::<OtherInner>::new_uninit();
             let ptr = Arc::get_mut_unchecked(&mut arc).as_mut_ptr();
             (&raw mut (*ptr).name).write(name);
             (&raw mut (*ptr).id).write(id);
@@ -1348,7 +1414,7 @@
             Pin::new_unchecked(arc.assume_init())
         };
 
-        Thread { inner }
+        Self(Inner::Other(inner))
     }
 
     /// Like the public [`park`], but callable on any handle. This is used to
@@ -1357,7 +1423,7 @@
     /// # Safety
     /// May only be called from the thread to which this handle belongs.
     pub(crate) unsafe fn park(&self) {
-        unsafe { self.inner.as_ref().parker().park() }
+        unsafe { self.0.parker().park() }
     }
 
     /// Atomically makes the handle's token available if it is not already.
@@ -1393,7 +1459,7 @@
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn unpark(&self) {
-        self.inner.as_ref().parker().unpark();
+        self.0.parker().unpark();
     }
 
     /// Gets the thread's unique identifier.
@@ -1413,7 +1479,7 @@
     #[stable(feature = "thread_id", since = "1.19.0")]
     #[must_use]
     pub fn id(&self) -> ThreadId {
-        self.inner.id
+        self.0.id()
     }
 
     /// Gets the thread's name.
@@ -1456,7 +1522,11 @@
     #[stable(feature = "rust1", since = "1.0.0")]
     #[must_use]
     pub fn name(&self) -> Option<&str> {
-        self.inner.name.as_str()
+        self.0.name()
+    }
+
+    fn cname(&self) -> Option<&CStr> {
+        self.0.cname()
     }
 
     /// Consumes the `Thread`, returning a raw pointer.
@@ -1480,9 +1550,7 @@
     /// ```
     #[unstable(feature = "thread_raw", issue = "97523")]
     pub fn into_raw(self) -> *const () {
-        // Safety: We only expose an opaque pointer, which maintains the `Pin` invariant.
-        let inner = unsafe { Pin::into_inner_unchecked(self.inner) };
-        Arc::into_raw(inner) as *const ()
+        self.0.into_raw()
     }
 
     /// Constructs a `Thread` from a raw pointer.
@@ -1504,11 +1572,7 @@
     #[unstable(feature = "thread_raw", issue = "97523")]
     pub unsafe fn from_raw(ptr: *const ()) -> Thread {
         // Safety: Upheld by caller.
-        unsafe { Thread { inner: Pin::new_unchecked(Arc::from_raw(ptr as *const Inner)) } }
-    }
-
-    fn cname(&self) -> Option<&CStr> {
-        self.inner.name.as_cstr()
+        unsafe { Thread(Inner::from_raw(ptr)) }
     }
 }
 
diff --git a/library/std/src/time.rs b/library/std/src/time.rs
index f28a056..9f4f8a0 100644
--- a/library/std/src/time.rs
+++ b/library/std/src/time.rs
@@ -178,9 +178,9 @@
 /// system.
 ///
 /// A `SystemTime` does not count leap seconds.
-/// `SystemTime::now()`'s behaviour around a leap second
+/// `SystemTime::now()`'s behavior around a leap second
 /// is the same as the operating system's wall clock.
-/// The precise behaviour near a leap second
+/// The precise behavior near a leap second
 /// (e.g. whether the clock appears to run slow or fast, or stop, or jump)
 /// depends on platform and configuration,
 /// so should not be relied on.
diff --git a/library/stdarch b/library/stdarch
index c881fe3..ff9a444 160000
--- a/library/stdarch
+++ b/library/stdarch
@@ -1 +1 @@
-Subproject commit c881fe3231b3947a4766aa15a26a93022fbb8723
+Subproject commit ff9a4445038eae46fd095188740946808581bc0e
diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py
index 04909cd..d7ae029 100644
--- a/src/bootstrap/bootstrap.py
+++ b/src/bootstrap/bootstrap.py
@@ -1092,9 +1092,6 @@
             if not os.path.exists(cargo_dir):
                 eprint('ERROR: vendoring required, but .cargo/config does not exist.')
                 raise Exception("{} not found".format(cargo_dir))
-        else:
-            if os.path.exists(cargo_dir):
-                shutil.rmtree(cargo_dir)
 
 def parse_args(args):
     """Parse the command line arguments that the python script needs."""
diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py
index 15137fb..2e173c9 100755
--- a/src/bootstrap/configure.py
+++ b/src/bootstrap/configure.py
@@ -72,6 +72,7 @@
 o("optimize-llvm", "llvm.optimize", "build optimized LLVM")
 o("llvm-assertions", "llvm.assertions", "build LLVM with assertions")
 o("llvm-enzyme", "llvm.enzyme", "build LLVM with enzyme")
+o("llvm-offload", "llvm.offload", "build LLVM with gpu offload support")
 o("llvm-plugins", "llvm.plugins", "build LLVM with plugin interface")
 o("debug-assertions", "rust.debug-assertions", "build with debugging assertions")
 o("debug-assertions-std", "rust.debug-assertions-std", "build the standard library with debugging assertions")
diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs
index 27bbc8b..e13d4cc 100644
--- a/src/bootstrap/src/core/build_steps/compile.rs
+++ b/src/bootstrap/src/core/build_steps/compile.rs
@@ -15,7 +15,6 @@
 use std::process::Stdio;
 use std::{env, fs, str};
 
-use build_helper::git::get_closest_merge_commit;
 use serde_derive::Deserialize;
 
 use crate::core::build_steps::tool::SourceType;
@@ -27,7 +26,7 @@
 use crate::core::config::{DebuginfoLevel, LlvmLibunwind, RustcLto, TargetSelection};
 use crate::utils::exec::command;
 use crate::utils::helpers::{
-    self, exe, get_clang_cl_resource_dir, is_debug_info, is_dylib, symlink_dir, t, up_to_date,
+    exe, get_clang_cl_resource_dir, is_debug_info, is_dylib, symlink_dir, t, up_to_date,
 };
 use crate::{CLang, Compiler, DependencyType, GitRepo, LLVM_TOOLS, Mode};
 
@@ -125,23 +124,9 @@
         // Force compilation of the standard library from source if the `library` is modified. This allows
         // library team to compile the standard library without needing to compile the compiler with
         // the `rust.download-rustc=true` option.
-        let force_recompile =
-            if builder.rust_info().is_managed_git_subrepository() && builder.download_rustc() {
-                let closest_merge_commit =
-                    get_closest_merge_commit(Some(&builder.src), &builder.config.git_config(), &[])
-                        .unwrap();
-
-                // Check if `library` has changes (returns false otherwise)
-                !t!(helpers::git(Some(&builder.src))
-                    .args(["diff-index", "--quiet", &closest_merge_commit])
-                    .arg("--")
-                    .arg(builder.src.join("library"))
-                    .as_command_mut()
-                    .status())
-                .success()
-            } else {
-                false
-            };
+        let force_recompile = builder.rust_info().is_managed_git_subrepository()
+            && builder.download_rustc()
+            && builder.config.last_modified_commit(&["library"], "download-rustc", true).is_none();
 
         run.builder.ensure(Std {
             compiler: run.builder.compiler(run.builder.top_stage, run.build_triple()),
diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs
index ca2b874..69ec832 100644
--- a/src/bootstrap/src/core/build_steps/doc.rs
+++ b/src/bootstrap/src/core/build_steps/doc.rs
@@ -170,7 +170,14 @@
                 builder.add_rustc_lib_path(compiler, &mut rustbook_cmd);
             }
 
-            rustbook_cmd.arg("build").arg(&src).arg("-d").arg(&out).run(builder);
+            rustbook_cmd
+                .arg("build")
+                .arg(&src)
+                .arg("-d")
+                .arg(&out)
+                .arg("--rust-root")
+                .arg(&builder.src)
+                .run(builder);
 
             for lang in &self.languages {
                 let out = out.join(lang);
diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs
index a2d40f6..ffb7d9a 100644
--- a/src/bootstrap/src/core/build_steps/llvm.rs
+++ b/src/bootstrap/src/core/build_steps/llvm.rs
@@ -472,6 +472,21 @@
             cfg.define("LLVM_ENABLE_PROJECTS", enabled_llvm_projects.join(";"));
         }
 
+        let mut enabled_llvm_runtimes = Vec::new();
+
+        if builder.config.llvm_offload {
+            enabled_llvm_runtimes.push("offload");
+            //FIXME(ZuseZ4): LLVM intends to drop the offload dependency on openmp.
+            //Remove this line once they achieved it.
+            enabled_llvm_runtimes.push("openmp");
+        }
+
+        if !enabled_llvm_runtimes.is_empty() {
+            enabled_llvm_runtimes.sort();
+            enabled_llvm_runtimes.dedup();
+            cfg.define("LLVM_ENABLE_RUNTIMES", enabled_llvm_runtimes.join(";"));
+        }
+
         if let Some(num_linkers) = builder.config.llvm_link_jobs {
             if num_linkers > 0 {
                 cfg.define("LLVM_PARALLEL_LINK_JOBS", num_linkers.to_string());
diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs
index e25b571..2ad1b39 100644
--- a/src/bootstrap/src/core/build_steps/test.rs
+++ b/src/bootstrap/src/core/build_steps/test.rs
@@ -1734,13 +1734,15 @@
             } else {
                 // We need to properly build cargo using the suitable stage compiler.
 
-                // HACK: currently tool stages are off-by-one compared to compiler stages, i.e. if
-                // you give `tool::Cargo` a stage 1 rustc, it will cause stage 2 rustc to be built
-                // and produce a cargo built with stage 2 rustc. To fix this, we need to chop off
-                // the compiler stage by 1 to align with expected `./x test run-make --stage N`
-                // behavior, i.e. we need to pass `N - 1` compiler stage to cargo. See also Miri
-                // which does a similar hack.
-                let compiler = builder.compiler(builder.top_stage - 1, compiler.host);
+                let compiler = builder.download_rustc().then_some(compiler).unwrap_or_else(||
+                    // HACK: currently tool stages are off-by-one compared to compiler stages, i.e. if
+                    // you give `tool::Cargo` a stage 1 rustc, it will cause stage 2 rustc to be built
+                    // and produce a cargo built with stage 2 rustc. To fix this, we need to chop off
+                    // the compiler stage by 1 to align with expected `./x test run-make --stage N`
+                    // behavior, i.e. we need to pass `N - 1` compiler stage to cargo. See also Miri
+                    // which does a similar hack.
+                    builder.compiler(builder.top_stage - 1, compiler.host));
+
                 builder.ensure(tool::Cargo { compiler, target: compiler.host })
             };
 
@@ -1834,6 +1836,9 @@
         if builder.config.cmd.only_modified() {
             cmd.arg("--only-modified");
         }
+        if let Some(compiletest_diff_tool) = &builder.config.compiletest_diff_tool {
+            cmd.arg("--compiletest-diff-tool").arg(compiletest_diff_tool);
+        }
 
         let mut flags = if is_rustdoc { Vec::new() } else { vec!["-Crpath".to_string()] };
         flags.push(format!("-Cdebuginfo={}", builder.config.rust_debuginfo_level_tests));
@@ -3549,9 +3554,7 @@
         let path = self.path.to_str().unwrap();
         let crate_name = self.path.components().last().unwrap().as_os_str().to_str().unwrap();
 
-        if !builder.download_rustc() {
-            builder.ensure(compile::Std::new(compiler, self.host));
-        }
+        builder.ensure(tool::TestFloatParse { host: self.host });
 
         // Run any unit tests in the crate
         let cargo_test = tool::prepare_tool_cargo(
diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs
index f5afa6c..bb837eb 100644
--- a/src/bootstrap/src/core/build_steps/tool.rs
+++ b/src/bootstrap/src/core/build_steps/tool.rs
@@ -1,8 +1,6 @@
 use std::path::PathBuf;
 use std::{env, fs};
 
-use build_helper::git::get_closest_merge_commit;
-
 use crate::core::build_steps::compile;
 use crate::core::build_steps::toolstate::ToolState;
 use crate::core::builder;
@@ -10,7 +8,7 @@
 use crate::core::config::TargetSelection;
 use crate::utils::channel::GitInfo;
 use crate::utils::exec::{BootstrapCommand, command};
-use crate::utils::helpers::{add_dylib_path, exe, git, t};
+use crate::utils::helpers::{add_dylib_path, exe, t};
 use crate::{Compiler, Kind, Mode, gha};
 
 #[derive(Debug, Clone, Hash, PartialEq, Eq)]
@@ -596,28 +594,11 @@
             && target_compiler.stage > 0
             && builder.rust_info().is_managed_git_subrepository()
         {
-            let commit = get_closest_merge_commit(
-                Some(&builder.config.src),
-                &builder.config.git_config(),
-                &[],
-            )
-            .unwrap();
+            let files_to_track = &["src/librustdoc", "src/tools/rustdoc"];
 
-            let librustdoc_src = builder.config.src.join("src/librustdoc");
-            let rustdoc_src = builder.config.src.join("src/tools/rustdoc");
-
-            // FIXME: The change detection logic here is quite similar to `Config::download_ci_rustc_commit`.
-            // It would be better to unify them.
-            let has_changes = !git(Some(&builder.config.src))
-                .allow_failure()
-                .run_always()
-                .args(["diff-index", "--quiet", &commit])
-                .arg("--")
-                .arg(librustdoc_src)
-                .arg(rustdoc_src)
-                .run(builder);
-
-            if !has_changes {
+            // Check if unchanged
+            if builder.config.last_modified_commit(files_to_track, "download-rustc", true).is_some()
+            {
                 let precompiled_rustdoc = builder
                     .config
                     .ci_rustc_dir()
@@ -1097,6 +1078,38 @@
     Rustfmt, "src/tools/rustfmt", "rustfmt", stable=true, add_bins_to_sysroot = ["rustfmt", "cargo-fmt"];
 );
 
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct TestFloatParse {
+    pub host: TargetSelection,
+}
+
+impl Step for TestFloatParse {
+    type Output = ();
+    const ONLY_HOSTS: bool = true;
+    const DEFAULT: bool = false;
+
+    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
+        run.path("src/etc/test-float-parse")
+    }
+
+    fn run(self, builder: &Builder<'_>) {
+        let bootstrap_host = builder.config.build;
+        let compiler = builder.compiler(builder.top_stage, bootstrap_host);
+
+        builder.ensure(ToolBuild {
+            compiler,
+            target: bootstrap_host,
+            tool: "test-float-parse",
+            mode: Mode::ToolStd,
+            path: "src/etc/test-float-parse",
+            source_type: SourceType::InTree,
+            extra_features: Vec::new(),
+            allow_features: "",
+            cargo_args: Vec::new(),
+        });
+    }
+}
+
 impl Builder<'_> {
     /// Gets a `BootstrapCommand` which is ready to run `tool` in `stage` built for
     /// `host`.
diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs
index aeb81b1..139ca7e 100644
--- a/src/bootstrap/src/core/config/config.rs
+++ b/src/bootstrap/src/core/config/config.rs
@@ -224,6 +224,7 @@
     pub llvm_assertions: bool,
     pub llvm_tests: bool,
     pub llvm_enzyme: bool,
+    pub llvm_offload: bool,
     pub llvm_plugins: bool,
     pub llvm_optimize: bool,
     pub llvm_thin_lto: bool,
@@ -368,6 +369,9 @@
     /// The paths to work with. For example: with `./x check foo bar` we get
     /// `paths=["foo", "bar"]`.
     pub paths: Vec<PathBuf>,
+
+    /// Command for visual diff display, e.g. `diff-tool --color=always`.
+    pub compiletest_diff_tool: Option<String>,
 }
 
 #[derive(Clone, Debug, Default)]
@@ -892,6 +896,7 @@
         android_ndk: Option<PathBuf> = "android-ndk",
         optimized_compiler_builtins: Option<bool> = "optimized-compiler-builtins",
         jobs: Option<u32> = "jobs",
+        compiletest_diff_tool: Option<String> = "compiletest-diff-tool",
     }
 }
 
@@ -934,6 +939,7 @@
         use_libcxx: Option<bool> = "use-libcxx",
         use_linker: Option<String> = "use-linker",
         allow_old_toolchain: Option<bool> = "allow-old-toolchain",
+        offload: Option<bool> = "offload",
         polly: Option<bool> = "polly",
         clang: Option<bool> = "clang",
         enable_warnings: Option<bool> = "enable-warnings",
@@ -1512,6 +1518,7 @@
             android_ndk,
             optimized_compiler_builtins,
             jobs,
+            compiletest_diff_tool,
         } = toml.build.unwrap_or_default();
 
         config.jobs = Some(threads_from_config(flags.jobs.unwrap_or(jobs.unwrap_or(0))));
@@ -1642,6 +1649,7 @@
         // we'll infer default values for them later
         let mut llvm_tests = None;
         let mut llvm_enzyme = None;
+        let mut llvm_offload = None;
         let mut llvm_plugins = None;
         let mut debug = None;
         let mut debug_assertions = None;
@@ -1879,6 +1887,7 @@
                 use_libcxx,
                 use_linker,
                 allow_old_toolchain,
+                offload,
                 polly,
                 clang,
                 enable_warnings,
@@ -1895,6 +1904,7 @@
             set(&mut config.ninja_in_file, ninja);
             llvm_tests = tests;
             llvm_enzyme = enzyme;
+            llvm_offload = offload;
             llvm_plugins = plugins;
             set(&mut config.llvm_optimize, optimize_toml);
             set(&mut config.llvm_thin_lto, thin_lto);
@@ -1916,6 +1926,7 @@
             set(&mut config.llvm_use_libcxx, use_libcxx);
             config.llvm_use_linker.clone_from(&use_linker);
             config.llvm_allow_old_toolchain = allow_old_toolchain.unwrap_or(false);
+            config.llvm_offload = offload.unwrap_or(false);
             config.llvm_polly = polly.unwrap_or(false);
             config.llvm_clang = clang.unwrap_or(false);
             config.llvm_enable_warnings = enable_warnings.unwrap_or(false);
@@ -2092,6 +2103,7 @@
 
         config.llvm_tests = llvm_tests.unwrap_or(false);
         config.llvm_enzyme = llvm_enzyme.unwrap_or(false);
+        config.llvm_offload = llvm_offload.unwrap_or(false);
         config.llvm_plugins = llvm_plugins.unwrap_or(false);
         config.rust_optimize = optimize.unwrap_or(RustOptimize::Bool(true));
 
@@ -2158,6 +2170,7 @@
         config.rust_debuginfo_level_tests = debuginfo_level_tests.unwrap_or(DebuginfoLevel::None);
         config.optimized_compiler_builtins =
             optimized_compiler_builtins.unwrap_or(config.channel != "dev");
+        config.compiletest_diff_tool = compiletest_diff_tool;
 
         let download_rustc = config.download_rustc_commit.is_some();
         // See https://github.com/rust-lang/compiler-team/issues/326
@@ -2754,25 +2767,25 @@
             }
         };
 
-        let files_to_track = &[
-            self.src.join("compiler"),
-            self.src.join("library"),
-            self.src.join("src/version"),
-            self.src.join("src/stage0"),
-            self.src.join("src/ci/channel"),
-        ];
+        let files_to_track =
+            &["compiler", "library", "src/version", "src/stage0", "src/ci/channel"];
 
         // Look for a version to compare to based on the current commit.
         // Only commits merged by bors will have CI artifacts.
-        let commit =
-            get_closest_merge_commit(Some(&self.src), &self.git_config(), files_to_track).unwrap();
-        if commit.is_empty() {
-            println!("ERROR: could not find commit hash for downloading rustc");
-            println!("HELP: maybe your repository history is too shallow?");
-            println!("HELP: consider disabling `download-rustc`");
-            println!("HELP: or fetch enough history to include one upstream commit");
-            crate::exit!(1);
-        }
+        let commit = match self.last_modified_commit(files_to_track, "download-rustc", if_unchanged)
+        {
+            Some(commit) => commit,
+            None => {
+                if if_unchanged {
+                    return None;
+                }
+                println!("ERROR: could not find commit hash for downloading rustc");
+                println!("HELP: maybe your repository history is too shallow?");
+                println!("HELP: consider disabling `download-rustc`");
+                println!("HELP: or fetch enough history to include one upstream commit");
+                crate::exit!(1);
+            }
+        };
 
         if CiEnv::is_ci() && {
             let head_sha =
@@ -2787,31 +2800,7 @@
             return None;
         }
 
-        // Warn if there were changes to the compiler or standard library since the ancestor commit.
-        let has_changes = !t!(helpers::git(Some(&self.src))
-            .args(["diff-index", "--quiet", &commit])
-            .arg("--")
-            .args(files_to_track)
-            .as_command_mut()
-            .status())
-        .success();
-        if has_changes {
-            if if_unchanged {
-                if self.is_verbose() {
-                    println!(
-                        "WARNING: saw changes to compiler/ or library/ since {commit}; \
-                            ignoring `download-rustc`"
-                    );
-                }
-                return None;
-            }
-            println!(
-                "WARNING: `download-rustc` is enabled, but there are changes to \
-                    compiler/ or library/"
-            );
-        }
-
-        Some(commit.to_string())
+        Some(commit)
     }
 
     fn parse_download_ci_llvm(
@@ -2882,14 +2871,7 @@
 
         // Warn if there were changes to the compiler or standard library since the ancestor commit.
         let mut git = helpers::git(Some(&self.src));
-        git.args(["diff-index", "--quiet", &commit, "--"]);
-
-        // Handle running from a directory other than the top level
-        let top_level = &self.src;
-
-        for path in modified_paths {
-            git.arg(top_level.join(path));
-        }
+        git.args(["diff-index", "--quiet", &commit, "--"]).args(modified_paths);
 
         let has_changes = !t!(git.as_command_mut().status()).success();
         if has_changes {
@@ -2981,6 +2963,7 @@
         use_libcxx,
         use_linker,
         allow_old_toolchain,
+        offload,
         polly,
         clang,
         enable_warnings,
@@ -3003,6 +2986,7 @@
     err!(current_llvm_config.use_libcxx, use_libcxx);
     err!(current_llvm_config.use_linker, use_linker);
     err!(current_llvm_config.allow_old_toolchain, allow_old_toolchain);
+    err!(current_llvm_config.offload, offload);
     err!(current_llvm_config.polly, polly);
     err!(current_llvm_config.clang, clang);
     err!(current_llvm_config.build_config, build_config);
diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs
index 3924a6d..ba74cab 100644
--- a/src/bootstrap/src/lib.rs
+++ b/src/bootstrap/src/lib.rs
@@ -541,27 +541,32 @@
         }
         let output = helpers::git(Some(&self.src))
             .args(["config", "--file"])
-            .arg(self.config.src.join(".gitmodules"))
+            .arg(".gitmodules")
             .args(["--get-regexp", "path"])
             .run_capture(self)
             .stdout();
-        for line in output.lines() {
+        std::thread::scope(|s| {
             // Look for `submodule.$name.path = $path`
             // Sample output: `submodule.src/rust-installer.path src/tools/rust-installer`
-            let submodule = line.split_once(' ').unwrap().1;
-            self.update_existing_submodule(submodule);
-        }
+            for line in output.lines() {
+                let submodule = line.split_once(' ').unwrap().1;
+                let config = self.config.clone();
+                s.spawn(move || {
+                    Self::update_existing_submodule(&config, submodule);
+                });
+            }
+        });
     }
 
     /// Updates the given submodule only if it's initialized already; nothing happens otherwise.
-    pub fn update_existing_submodule(&self, submodule: &str) {
+    pub fn update_existing_submodule(config: &Config, submodule: &str) {
         // Avoid running git when there isn't a git checkout.
-        if !self.config.submodules() {
+        if !config.submodules() {
             return;
         }
 
         if GitInfo::new(false, Path::new(submodule)).is_managed_git_subrepository() {
-            self.config.update_submodule(submodule);
+            config.update_submodule(submodule);
         }
     }
 
diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs
index 9169bc9..b9cf8f0 100644
--- a/src/bootstrap/src/utils/change_tracker.rs
+++ b/src/bootstrap/src/utils/change_tracker.rs
@@ -280,4 +280,14 @@
         severity: ChangeSeverity::Info,
         summary: "Allow setting `--jobs` in config.toml with `build.jobs`.",
     },
+    ChangeInfo {
+        change_id: 131181,
+        severity: ChangeSeverity::Info,
+        summary: "New option `build.compiletest-diff-tool` that adds support for a custom differ for compiletest",
+    },
+    ChangeInfo {
+        change_id: 131513,
+        severity: ChangeSeverity::Info,
+        summary: "New option `llvm.offload` to control whether the llvm offload runtime for GPU support is built. Implicitly enables the openmp runtime as dependency.",
+    },
 ];
diff --git a/src/bootstrap/src/utils/channel.rs b/src/bootstrap/src/utils/channel.rs
index c361abb..4a9ecc7 100644
--- a/src/bootstrap/src/utils/channel.rs
+++ b/src/bootstrap/src/utils/channel.rs
@@ -10,7 +10,7 @@
 
 use super::helpers;
 use crate::Build;
-use crate::utils::helpers::{output, t};
+use crate::utils::helpers::{start_process, t};
 
 #[derive(Clone, Default)]
 pub enum GitInfo {
@@ -56,7 +56,7 @@
         }
 
         // Ok, let's scrape some info
-        let ver_date = output(
+        let ver_date = start_process(
             helpers::git(Some(dir))
                 .arg("log")
                 .arg("-1")
@@ -65,14 +65,14 @@
                 .as_command_mut(),
         );
         let ver_hash =
-            output(helpers::git(Some(dir)).arg("rev-parse").arg("HEAD").as_command_mut());
-        let short_ver_hash = output(
+            start_process(helpers::git(Some(dir)).arg("rev-parse").arg("HEAD").as_command_mut());
+        let short_ver_hash = start_process(
             helpers::git(Some(dir)).arg("rev-parse").arg("--short=9").arg("HEAD").as_command_mut(),
         );
         GitInfo::Present(Some(Info {
-            commit_date: ver_date.trim().to_string(),
-            sha: ver_hash.trim().to_string(),
-            short_sha: short_ver_hash.trim().to_string(),
+            commit_date: ver_date().trim().to_string(),
+            sha: ver_hash().trim().to_string(),
+            short_sha: short_ver_hash().trim().to_string(),
         }))
     }
 
diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs
index 2519ace..7162007 100644
--- a/src/bootstrap/src/utils/helpers.rs
+++ b/src/bootstrap/src/utils/helpers.rs
@@ -288,6 +288,33 @@
     String::from_utf8(output.stdout).unwrap()
 }
 
+/// Spawn a process and return a closure that will wait for the process
+/// to finish and then return its output. This allows the spawned process
+/// to do work without immediately blocking bootstrap.
+#[track_caller]
+pub fn start_process(cmd: &mut Command) -> impl FnOnce() -> String {
+    let child = match cmd.stderr(Stdio::inherit()).stdout(Stdio::piped()).spawn() {
+        Ok(child) => child,
+        Err(e) => fail(&format!("failed to execute command: {cmd:?}\nERROR: {e}")),
+    };
+
+    let command = format!("{:?}", cmd);
+
+    move || {
+        let output = child.wait_with_output().unwrap();
+
+        if !output.status.success() {
+            panic!(
+                "command did not execute successfully: {}\n\
+                 expected success, got: {}",
+                command, output.status
+            );
+        }
+
+        String::from_utf8(output.stdout).unwrap()
+    }
+}
+
 /// Returns the last-modified time for `path`, or zero if it doesn't exist.
 pub fn mtime(path: &Path) -> SystemTime {
     fs::metadata(path).and_then(|f| f.modified()).unwrap_or(UNIX_EPOCH)
diff --git a/src/ci/docker/host-aarch64/aarch64-gnu-debug/Dockerfile b/src/ci/docker/host-aarch64/aarch64-gnu-debug/Dockerfile
new file mode 100644
index 0000000..dcfea77
--- /dev/null
+++ b/src/ci/docker/host-aarch64/aarch64-gnu-debug/Dockerfile
@@ -0,0 +1,58 @@
+FROM ubuntu:22.04
+
+ARG DEBIAN_FRONTEND=noninteractive
+RUN apt-get update && apt-get install -y --no-install-recommends \
+  g++ \
+  make \
+  ninja-build \
+  file \
+  curl \
+  ca-certificates \
+  python3 \
+  python3-dev \
+  libxml2-dev \
+  libncurses-dev \
+  libedit-dev \
+  swig \
+  doxygen \
+  git \
+  cmake \
+  sudo \
+  gdb \
+  libssl-dev \
+  pkg-config \
+  xz-utils \
+  lld \
+  clang \
+  && rm -rf /var/lib/apt/lists/*
+
+COPY scripts/sccache.sh /scripts/
+RUN sh /scripts/sccache.sh
+
+ENV RUSTBUILD_FORCE_CLANG_BASED_TESTS 1
+ENV RUN_CHECK_WITH_PARALLEL_QUERIES 1
+
+# llvm.use-linker conflicts with downloading CI LLVM
+ENV NO_DOWNLOAD_CI_LLVM 1
+
+ENV RUST_CONFIGURE_ARGS \
+      --build=aarch64-unknown-linux-gnu \
+      --enable-debug \
+      --enable-lld \
+      --set llvm.use-linker=lld \
+      --set target.aarch64-unknown-linux-gnu.linker=clang \
+      --set target.aarch64-unknown-linux-gnu.cc=clang \
+      --set target.aarch64-unknown-linux-gnu.cxx=clang++
+
+# This job appears to be checking two separate things:
+# - That we can build the compiler with `--enable-debug`
+#   (without necessarily testing the result).
+# - That the tests with `//@ needs-force-clang-based-tests` pass, since they
+#   don't run by default unless RUSTBUILD_FORCE_CLANG_BASED_TESTS is set.
+#   - FIXME(https://github.com/rust-lang/rust/pull/126155#issuecomment-2156314273):
+#     Currently we only run the subset of tests with "clang" in their name.
+#   - See also FIXME(#132034)
+
+ENV SCRIPT \
+  python3 ../x.py --stage 2 build && \
+  python3 ../x.py --stage 2 test tests/run-make --test-args clang
diff --git a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile
index 410f0f9..ece5f17 100644
--- a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile
@@ -56,9 +56,9 @@
     CFLAGS_x86_64_fortanix_unknown_sgx="-D__ELF__ -isystem/usr/include/x86_64-linux-gnu -mlvi-hardening -mllvm -x86-experimental-lvi-inline-asm-hardening" \
     CXX_x86_64_fortanix_unknown_sgx=clang++-11 \
     CXXFLAGS_x86_64_fortanix_unknown_sgx="-D__ELF__ -isystem/usr/include/x86_64-linux-gnu -mlvi-hardening -mllvm -x86-experimental-lvi-inline-asm-hardening" \
-    AR_i686_unknown_freebsd=i686-unknown-freebsd13-ar \
-    CC_i686_unknown_freebsd=i686-unknown-freebsd13-clang \
-    CXX_i686_unknown_freebsd=i686-unknown-freebsd13-clang++ \
+    AR_i686_unknown_freebsd=i686-unknown-freebsd12-ar \
+    CC_i686_unknown_freebsd=i686-unknown-freebsd12-clang \
+    CXX_i686_unknown_freebsd=i686-unknown-freebsd12-clang++ \
     CC_aarch64_unknown_uefi=clang-11 \
     CXX_aarch64_unknown_uefi=clang++-11 \
     CC_i686_unknown_uefi=clang-11 \
@@ -118,6 +118,7 @@
 ENV TARGETS=$TARGETS,wasm32-wasip1
 ENV TARGETS=$TARGETS,wasm32-wasip1-threads
 ENV TARGETS=$TARGETS,wasm32-wasip2
+ENV TARGETS=$TARGETS,wasm32v1-none
 ENV TARGETS=$TARGETS,sparcv9-sun-solaris
 ENV TARGETS=$TARGETS,x86_64-pc-solaris
 ENV TARGETS=$TARGETS,x86_64-unknown-linux-gnux32
diff --git a/src/ci/docker/host-x86_64/dist-x86_64-freebsd/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-freebsd/Dockerfile
index fd0f5da..f42e6f7 100644
--- a/src/ci/docker/host-x86_64/dist-x86_64-freebsd/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-x86_64-freebsd/Dockerfile
@@ -29,9 +29,9 @@
 RUN /scripts/cmake.sh
 
 ENV \
-    AR_x86_64_unknown_freebsd=x86_64-unknown-freebsd13-ar \
-    CC_x86_64_unknown_freebsd=x86_64-unknown-freebsd13-clang \
-    CXX_x86_64_unknown_freebsd=x86_64-unknown-freebsd13-clang++
+    AR_x86_64_unknown_freebsd=x86_64-unknown-freebsd12-ar \
+    CC_x86_64_unknown_freebsd=x86_64-unknown-freebsd12-clang \
+    CXX_x86_64_unknown_freebsd=x86_64-unknown-freebsd12-clang++
 
 ENV HOSTS=x86_64-unknown-freebsd
 
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile
index fa31801..292dbfd 100644
--- a/src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile
@@ -49,9 +49,7 @@
 #   (without necessarily testing the result).
 # - That the tests with `//@ needs-force-clang-based-tests` pass, since they
 #   don't run by default unless RUSTBUILD_FORCE_CLANG_BASED_TESTS is set.
-#   - FIXME(https://github.com/rust-lang/rust/pull/126155#issuecomment-2156314273):
-#     Currently we only run the subset of tests with "clang" in their name.
 
 ENV SCRIPT \
   python3 ../x.py --stage 2 build && \
-  python3 ../x.py --stage 2 test tests/run-make --test-args clang
+  python3 ../x.py --stage 2 test tests/run-make
diff --git a/src/ci/docker/scripts/freebsd-toolchain.sh b/src/ci/docker/scripts/freebsd-toolchain.sh
index 4826b81..0d02636 100755
--- a/src/ci/docker/scripts/freebsd-toolchain.sh
+++ b/src/ci/docker/scripts/freebsd-toolchain.sh
@@ -5,8 +5,8 @@
 
 arch=$1
 binutils_version=2.40
-freebsd_version=13.2
-triple=$arch-unknown-freebsd13
+freebsd_version=12.3
+triple=$arch-unknown-freebsd12
 sysroot=/usr/local/$triple
 
 hide_output() {
@@ -59,7 +59,7 @@
 
 # Originally downloaded from:
 # URL=https://download.freebsd.org/ftp/releases/${freebsd_arch}/${freebsd_version}-RELEASE/base.txz
-URL=https://ci-mirrors.rust-lang.org/rustc/2024-02-18-freebsd-${freebsd_version}-${freebsd_arch}-base.txz
+URL=https://ci-mirrors.rust-lang.org/rustc/2022-05-06-freebsd-${freebsd_version}-${freebsd_arch}-base.txz
 curl "$URL" | tar xJf - -C "$sysroot" --wildcards "${files_to_extract[@]}"
 
 # Clang can do cross-builds out of the box, if we give it the right
@@ -68,7 +68,7 @@
 # there might be other problems.)
 #
 # The --target option is last because the cross-build of LLVM uses
-# --target without an OS version ("-freebsd" vs. "-freebsd13").  This
+# --target without an OS version ("-freebsd" vs. "-freebsd12").  This
 # makes Clang default to libstdc++ (which no longer exists), and also
 # controls other features, like GNU-style symbol table hashing and
 # anything predicated on the version number in the __FreeBSD__
diff --git a/src/ci/docker/scripts/fuchsia-test-runner.py b/src/ci/docker/scripts/fuchsia-test-runner.py
index 1aa9a4a..77e2741 100755
--- a/src/ci/docker/scripts/fuchsia-test-runner.py
+++ b/src/ci/docker/scripts/fuchsia-test-runner.py
@@ -287,7 +287,7 @@
 
     @property
     def package_server_log_path(self) -> Path:
-        return self.tmp_dir().joinpath("package_server_log")
+        return self.tmp_dir().joinpath(f"repo_{self.TEST_REPO_NAME}.log")
 
     @property
     def emulator_log_path(self) -> Path:
@@ -401,6 +401,7 @@
         # Set configs
         configs = {
             "log.enabled": "true",
+            "log.dir": self.tmp_dir(),
             "test.is_isolated": "true",
             "test.experimental_structured_output": "true",
         }
@@ -575,43 +576,19 @@
             stderr_handler=self.subprocess_logger.debug,
         )
 
-        # Add repository
-        check_call_with_logging(
-            [
-                ffx_path,
-                "repository",
-                "add-from-pm",
-                "--repository",
-                self.TEST_REPO_NAME,
-                self.repo_dir(),
-            ],
-            env=ffx_env,
-            stdout_handler=self.subprocess_logger.debug,
-            stderr_handler=self.subprocess_logger.debug,
-        )
-
-        # Start repository server
-        # Note that we must first enable the repository server daemon.
-        check_call_with_logging(
-            [
-                ffx_path,
-                "config",
-                "set",
-                "repository.server.enabled",
-                "true",
-            ],
-            env=ffx_env,
-            stdout_handler=self.subprocess_logger.debug,
-            stderr_handler=self.subprocess_logger.debug,
-        )
         check_call_with_logging(
             [
                 ffx_path,
                 "repository",
                 "server",
                 "start",
+                "--background",
                 "--address",
                 "[::]:0",
+                "--repo-path",
+                self.repo_dir(),
+                "--repository",
+                self.TEST_REPO_NAME
             ],
             env=ffx_env,
             stdout_handler=self.subprocess_logger.debug,
@@ -1009,6 +986,21 @@
             stderr_handler=self.subprocess_logger.debug,
         )
 
+        # Stop the package server
+        self.env_logger.info("Stopping package server...")
+        check_call_with_logging(
+            [
+                self.tool_path("ffx"),
+                "repository",
+                "server",
+                "stop",
+                self.TEST_REPO_NAME
+            ],
+            env=self.ffx_cmd_env(),
+            stdout_handler=self.subprocess_logger.debug,
+            stderr_handler=self.subprocess_logger.debug,
+        )
+
         # Stop ffx isolation
         self.env_logger.info("Stopping ffx isolation...")
         self.stop_ffx_isolation()
diff --git a/src/ci/docker/scripts/rfl-build.sh b/src/ci/docker/scripts/rfl-build.sh
index 27dbfc6..f07515f 100755
--- a/src/ci/docker/scripts/rfl-build.sh
+++ b/src/ci/docker/scripts/rfl-build.sh
@@ -2,7 +2,7 @@
 
 set -euo pipefail
 
-LINUX_VERSION=v6.12-rc2
+LINUX_VERSION=28e848386b92645f93b9f2fdba5882c3ca7fb3e2
 
 # Build rustc, rustdoc, cargo, clippy-driver and rustfmt
 ../x.py build --stage 2 library rustdoc clippy rustfmt
diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml
index 2b63660..a401092 100644
--- a/src/ci/github-actions/jobs.yml
+++ b/src/ci/github-actions/jobs.yml
@@ -123,6 +123,9 @@
   - image: aarch64-gnu
     <<: *job-aarch64-linux
 
+  - image: aarch64-gnu-debug
+    <<: *job-aarch64-linux
+
   - image: arm-android
     <<: *job-linux-4c
 
@@ -253,7 +256,9 @@
     <<: *job-linux-4c
 
   - image: x86_64-gnu-debug
-    <<: *job-linux-4c
+    # This seems to be needed because a full stage 2 build + run-make tests
+    # overwhelms the storage capacity of the standard 4c runner.
+    <<: *job-linux-4c-largedisk
 
   - image: x86_64-gnu-distcheck
     <<: *job-linux-8c
diff --git a/src/ci/run.sh b/src/ci/run.sh
index 3962c35..8e2f525 100755
--- a/src/ci/run.sh
+++ b/src/ci/run.sh
@@ -47,11 +47,6 @@
 
 export CARGO_REGISTRIES_CRATES_IO_PROTOCOL=sparse
 
-# suppress change-tracker warnings on CI
-if [ "$CI" != "" ]; then
-    RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set change-id=99999999"
-fi
-
 # If runner uses an incompatible option and `FORCE_CI_RUSTC` is not defined,
 # switch to in-tree rustc.
 if [ "$FORCE_CI_RUSTC" == "" ]; then
diff --git a/src/doc/edition-guide b/src/doc/edition-guide
index c7ebae2..1f07c24 160000
--- a/src/doc/edition-guide
+++ b/src/doc/edition-guide
@@ -1 +1 @@
-Subproject commit c7ebae25cb4801a31b6f05353f6d85bfa6feedd1
+Subproject commit 1f07c242f8162a711a5ac5a4ea8fa7ec884ee7a9
diff --git a/src/doc/embedded-book b/src/doc/embedded-book
index f40a8b4..ddbf1b4 160000
--- a/src/doc/embedded-book
+++ b/src/doc/embedded-book
@@ -1 +1 @@
-Subproject commit f40a8b420ec4b4505d9489965e261f1d5c28ba23
+Subproject commit ddbf1b4e2858fedb71b7c42eb15c4576517dc125
diff --git a/src/doc/reference b/src/doc/reference
index c64e52a..23ce619 160000
--- a/src/doc/reference
+++ b/src/doc/reference
@@ -1 +1 @@
-Subproject commit c64e52a3d306eac0129f3ad6c6d8806ab99ae2e9
+Subproject commit 23ce619966541bf2c80d45fdfeecf3393e360a13
diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide
index 07bc9ca..59d94ea 160000
--- a/src/doc/rustc-dev-guide
+++ b/src/doc/rustc-dev-guide
@@ -1 +1 @@
-Subproject commit 07bc9ca9eb1cd6d9fbbf758c2753b748804a134f
+Subproject commit 59d94ea75a0b157e148af14c73c2dd60efb7b60a
diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md
index 795908b..18f76ac 100644
--- a/src/doc/rustc/src/SUMMARY.md
+++ b/src/doc/rustc/src/SUMMARY.md
@@ -66,9 +66,10 @@
     - [powerpc-unknown-openbsd](platform-support/powerpc-unknown-openbsd.md)
     - [powerpc-unknown-linux-muslspe](platform-support/powerpc-unknown-linux-muslspe.md)
     - [powerpc64-ibm-aix](platform-support/aix.md)
+    - [riscv32e*-unknown-none-elf](platform-support/riscv32e-unknown-none-elf.md)
+    - [riscv32i*-unknown-none-elf](platform-support/riscv32-unknown-none-elf.md)
     - [riscv32im-risc0-zkvm-elf](platform-support/riscv32im-risc0-zkvm-elf.md)
     - [riscv32imac-unknown-xous-elf](platform-support/riscv32imac-unknown-xous-elf.md)
-    - [riscv32*-unknown-none-elf](platform-support/riscv32-unknown-none-elf.md)
     - [riscv64gc-unknown-linux-gnu](platform-support/riscv64gc-unknown-linux-gnu.md)
     - [riscv64gc-unknown-linux-musl](platform-support/riscv64gc-unknown-linux-musl.md)
     - [sparc-unknown-none-elf](./platform-support/sparc-unknown-none-elf.md)
@@ -86,6 +87,7 @@
     - [wasm32-wasip2](platform-support/wasm32-wasip2.md)
     - [wasm32-unknown-emscripten](platform-support/wasm32-unknown-emscripten.md)
     - [wasm32-unknown-unknown](platform-support/wasm32-unknown-unknown.md)
+    - [wasm32v1-none](platform-support/wasm32v1-none.md)
     - [wasm64-unknown-unknown](platform-support/wasm64-unknown-unknown.md)
     - [\*-win7-windows-msvc](platform-support/win7-windows-msvc.md)
     - [x86_64-fortanix-unknown-sgx](platform-support/x86_64-fortanix-unknown-sgx.md)
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index e9c73ef..04bb40d 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -100,7 +100,7 @@
 [`riscv64gc-unknown-linux-gnu`](platform-support/riscv64gc-unknown-linux-gnu.md) | RISC-V Linux (kernel 4.20, glibc 2.29)
 [`riscv64gc-unknown-linux-musl`](platform-support/riscv64gc-unknown-linux-musl.md) | RISC-V Linux (kernel 4.20, musl 1.2.3)
 `s390x-unknown-linux-gnu` | S390x Linux (kernel 3.2, glibc 2.17)
-`x86_64-unknown-freebsd` | 64-bit FreeBSD (version 13.2)
+`x86_64-unknown-freebsd` | 64-bit FreeBSD
 `x86_64-unknown-illumos` | illumos
 `x86_64-unknown-linux-musl` | 64-bit Linux with musl 1.2.3
 [`x86_64-unknown-netbsd`](platform-support/netbsd.md) | NetBSD/amd64
@@ -166,7 +166,7 @@
 `i586-unknown-linux-musl` | ✓ | 32-bit Linux w/o SSE, musl 1.2.3 [^x86_32-floats-x87]
 [`i686-linux-android`](platform-support/android.md) | ✓ | 32-bit x86 Android [^x86_32-floats-return-ABI]
 [`i686-pc-windows-gnullvm`](platform-support/pc-windows-gnullvm.md) | ✓ | 32-bit x86 MinGW (Windows 10+), LLVM ABI [^x86_32-floats-return-ABI]
-`i686-unknown-freebsd` | ✓ | 32-bit FreeBSD (version 13.2) [^x86_32-floats-return-ABI]
+`i686-unknown-freebsd` | ✓ | 32-bit FreeBSD [^x86_32-floats-return-ABI]
 `i686-unknown-linux-musl` | ✓ | 32-bit Linux with musl 1.2.3 [^x86_32-floats-return-ABI]
 [`i686-unknown-uefi`](platform-support/unknown-uefi.md) | ? | 32-bit UEFI
 [`loongarch64-unknown-none`](platform-support/loongarch-none.md) | * | LoongArch64 Bare-metal (LP64D ABI)
@@ -195,6 +195,7 @@
 `wasm32-wasi` | ✓ | WebAssembly with WASI (undergoing a [rename to `wasm32-wasip1`][wasi-rename])
 [`wasm32-wasip1`](platform-support/wasm32-wasip1.md) | ✓ | WebAssembly with WASI
 [`wasm32-wasip1-threads`](platform-support/wasm32-wasip1-threads.md) | ✓ | WebAssembly with WASI Preview 1 and threads
+[`wasm32v1-none`](platform-support/wasm32v1-none.md) | * | WebAssembly limited to 1.0 features and no imports
 [`x86_64-apple-ios`](platform-support/apple-ios.md) | ✓ | 64-bit x86 iOS
 [`x86_64-apple-ios-macabi`](platform-support/apple-ios-macabi.md) | ✓ | Mac Catalyst on x86_64
 [`x86_64-fortanix-unknown-sgx`](platform-support/x86_64-fortanix-unknown-sgx.md) | ✓ | [Fortanix ABI] for 64-bit Intel SGX
@@ -257,7 +258,7 @@
 [`aarch64-unknown-teeos`](platform-support/aarch64-unknown-teeos.md) | ? |  | ARM64 TEEOS |
 [`aarch64-unknown-nto-qnx700`](platform-support/nto-qnx.md) | ? |  | ARM64 QNX Neutrino 7.0 RTOS |
 [`aarch64-unknown-nto-qnx710`](platform-support/nto-qnx.md) | ✓ |  | ARM64 QNX Neutrino 7.1 RTOS |
-`aarch64-unknown-freebsd` | ✓ | ✓ | ARM64 FreeBSD (version 13.2)
+`aarch64-unknown-freebsd` | ✓ | ✓ | ARM64 FreeBSD
 [`aarch64-unknown-hermit`](platform-support/hermit.md) | ✓ |  | ARM64 Hermit
 `aarch64-unknown-illumos` | ✓ | ✓ | ARM64 illumos
 `aarch64-unknown-linux-gnu_ilp32` | ✓ | ✓ | ARM64 Linux (ILP32 ABI)
@@ -276,14 +277,14 @@
 `armv4t-unknown-linux-gnueabi` | ? |  | Armv4T Linux
 [`armv5te-none-eabi`](platform-support/armv5te-none-eabi.md) | * |  | Bare Armv5TE
 `armv5te-unknown-linux-uclibceabi` | ? |  | Armv5TE Linux with uClibc
-`armv6-unknown-freebsd` | ✓ | ✓ | Armv6 FreeBSD (version 13.2)
+`armv6-unknown-freebsd` | ✓ | ✓ | Armv6 FreeBSD
 [`armv6-unknown-netbsd-eabihf`](platform-support/netbsd.md) | ✓ | ✓ | Armv6 NetBSD w/hard-float
 [`armv6k-nintendo-3ds`](platform-support/armv6k-nintendo-3ds.md) | ? |  | Armv6k Nintendo 3DS, Horizon (Requires devkitARM toolchain)
 [`armv7-rtems-eabihf`](platform-support/armv7-rtems-eabihf.md) | ? |  | RTEMS OS for ARM BSPs
 [`armv7-sony-vita-newlibeabihf`](platform-support/armv7-sony-vita-newlibeabihf.md) | ✓ |  | Armv7-A Cortex-A9 Sony PlayStation Vita (requires VITASDK toolchain)
 [`armv7-unknown-linux-uclibceabi`](platform-support/armv7-unknown-linux-uclibceabi.md) | ✓ | ✓ | Armv7-A Linux with uClibc, softfloat
 [`armv7-unknown-linux-uclibceabihf`](platform-support/armv7-unknown-linux-uclibceabihf.md) | ✓ | ? | Armv7-A Linux with uClibc, hardfloat
-`armv7-unknown-freebsd` | ✓ | ✓ | Armv7-A FreeBSD (version 13.2)
+`armv7-unknown-freebsd` | ✓ | ✓ | Armv7-A FreeBSD
 [`armv7-unknown-netbsd-eabihf`](platform-support/netbsd.md) | ✓ | ✓ | Armv7-A NetBSD w/hard-float
 [`armv7-unknown-trusty`](platform-support/trusty.md) | ? |  |
 [`armv7-wrs-vxworks-eabihf`](platform-support/vxworks.md) | ✓ |  | Armv7-A for VxWorks
@@ -342,9 +343,9 @@
 [`powerpc-unknown-openbsd`](platform-support/powerpc-unknown-openbsd.md) | * |  |
 [`powerpc-wrs-vxworks-spe`](platform-support/vxworks.md) | ✓ |  |
 [`powerpc-wrs-vxworks`](platform-support/vxworks.md) | ✓ |  |
-`powerpc64-unknown-freebsd` | ✓ | ✓ | PPC64 FreeBSD (ELFv1 and ELFv2, version 13.2)
-`powerpc64le-unknown-freebsd` |   |   | PPC64LE FreeBSD (version 13.2)
-`powerpc-unknown-freebsd` |   |   | PowerPC FreeBSD (version 13.2)
+`powerpc64-unknown-freebsd` | ✓ | ✓ | PPC64 FreeBSD (ELFv1 and ELFv2)
+`powerpc64le-unknown-freebsd` |   |   | PPC64LE FreeBSD
+`powerpc-unknown-freebsd` |   |   | PowerPC FreeBSD
 `powerpc64-unknown-linux-musl` | ? |  | 64-bit PowerPC Linux with musl 1.2.3
 [`powerpc64-wrs-vxworks`](platform-support/vxworks.md) | ✓ |  |
 `powerpc64le-unknown-linux-musl` | ? |  | 64-bit PowerPC Linux with musl 1.2.3, Little Endian
@@ -360,7 +361,7 @@
 [`riscv32imafc-esp-espidf`](platform-support/esp-idf.md) | ✓ |  | RISC-V ESP-IDF
 [`riscv32-wrs-vxworks`](platform-support/vxworks.md) | ✓ |  |
 [`riscv64gc-unknown-hermit`](platform-support/hermit.md) | ✓ |   | RISC-V Hermit
-`riscv64gc-unknown-freebsd` |   |   | RISC-V FreeBSD (version 13.2)
+`riscv64gc-unknown-freebsd` |   |   | RISC-V FreeBSD
 `riscv64gc-unknown-fuchsia` |   |   | RISC-V Fuchsia
 [`riscv64gc-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | RISC-V NetBSD
 [`riscv64gc-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | OpenBSD/riscv64
@@ -413,8 +414,8 @@
 [`riscv32imafc-unknown-nuttx-elf`](platform-support/nuttx.md) | * |  | RISC-V 32bit with NuttX
 [`riscv64imac-unknown-nuttx-elf`](platform-support/nuttx.md) | * |  | RISC-V 64bit with NuttX
 [`riscv64gc-unknown-nuttx-elf`](platform-support/nuttx.md) | * |  | RISC-V 64bit with NuttX
-[`riscv32e-unknown-none-elf`](platform-support/riscv32-unknown-none-elf.md) | * |  | Bare RISC-V (RV32E ISA)
-[`riscv32em-unknown-none-elf`](platform-support/riscv32-unknown-none-elf.md) | * |  | Bare RISC-V (RV32EM ISA)
-[`riscv32emc-unknown-none-elf`](platform-support/riscv32-unknown-none-elf.md) | * |  | Bare RISC-V (RV32EMC ISA)
+[`riscv32e-unknown-none-elf`](platform-support/riscv32e-unknown-none-elf.md) | * |  | Bare RISC-V (RV32E ISA)
+[`riscv32em-unknown-none-elf`](platform-support/riscv32e-unknown-none-elf.md) | * |  | Bare RISC-V (RV32EM ISA)
+[`riscv32emc-unknown-none-elf`](platform-support/riscv32e-unknown-none-elf.md) | * |  | Bare RISC-V (RV32EMC ISA)
 
 [runs on NVIDIA GPUs]: https://github.com/japaric-archived/nvptx#targets
diff --git a/src/doc/rustc/src/platform-support/nuttx.md b/src/doc/rustc/src/platform-support/nuttx.md
index cbbede4..433a092 100644
--- a/src/doc/rustc/src/platform-support/nuttx.md
+++ b/src/doc/rustc/src/platform-support/nuttx.md
@@ -35,7 +35,7 @@
 
 ## Building the target
 
-The target can be built by enabled in the `rustc` build:
+The target can be built by enabling it in the `rustc` build:
 
 ```toml
 [build]
diff --git a/src/doc/rustc/src/platform-support/wasm32-unknown-unknown.md b/src/doc/rustc/src/platform-support/wasm32-unknown-unknown.md
index 48a8df0..73264ab 100644
--- a/src/doc/rustc/src/platform-support/wasm32-unknown-unknown.md
+++ b/src/doc/rustc/src/platform-support/wasm32-unknown-unknown.md
@@ -132,10 +132,20 @@
 
 If you're compiling WebAssembly code for an engine that does not support a
 feature in LLVM's default feature set then the feature must be disabled at
-compile time. Note, though, that enabled features may be used in the standard
-library or precompiled libraries shipped via rustup. This means that not only
-does your own code need to be compiled with the correct set of flags but the
-Rust standard library additionally must be recompiled.
+compile time. There are two approaches to choose from:
+
+  - If you are targeting a feature set no smaller than the W3C WebAssembly Core
+    1.0 recommendation -- which is equivalent to the WebAssembly MVP plus the
+    `mutable-globals` feature -- and you are building `no_std`, then you can
+    simply use the [`wasm32v1-none` target](./wasm32v1-none.md) instead of
+    `wasm32-unknown-unknown`, which uses only those minimal features and
+    includes a core and alloc library built with only those minimal features.
+
+  - Otherwise -- if you need std, or if you need to target the ultra-minimal
+    "MVP" feature set, excluding `mutable-globals` -- you will need to manually
+    specify `-Ctarget-cpu=mvp` and also rebuild the stdlib using that target to
+    ensure no features are used in the stdlib. This in turn requires use of a
+    nightly compiler.
 
 Compiling all code for the initial release of WebAssembly looks like:
 
@@ -150,9 +160,9 @@
 will produce a binary that uses only the original WebAssembly features by
 default and no proposals since its inception.
 
-To enable individual features it can be done with `-Ctarget-feature=+foo`.
-Available features for Rust code itself are documented in the [reference] and
-can also be found through:
+To enable individual features on either this target or `wasm32v1-none`, pass
+arguments of the form `-Ctarget-feature=+foo`.  Available features for Rust code
+itself are documented in the [reference] and can also be found through:
 
 ```sh
 $ rustc -Ctarget-feature=help --target wasm32-unknown-unknown
diff --git a/src/doc/rustc/src/platform-support/wasm32v1-none.md b/src/doc/rustc/src/platform-support/wasm32v1-none.md
new file mode 100644
index 0000000..46f89c2
--- /dev/null
+++ b/src/doc/rustc/src/platform-support/wasm32v1-none.md
@@ -0,0 +1,109 @@
+# `wasm32v1-none`
+
+**Tier: 2**
+
+The `wasm32v1-none` target is a WebAssembly compilation target that:
+
+- Imports nothing from its host environment
+- Enables no proposals / features past the [W3C WebAssembly Core 1.0 spec]
+
+[W3C WebAssembly Core 1.0 spec]: https://www.w3.org/TR/wasm-core-1/
+
+The target is very similar to [`wasm32-unknown-unknown`](./wasm32-unknown-unknown.md) and similarly uses LLVM's `wasm32-unknown-unknown` backend target. It contains only three minor differences:
+
+* Setting the `target-cpu` to `mvp` rather than the default `generic`. Requesting `mvp` disables _all_ WebAssembly proposals / LLVM target feature flags.
+* Enabling the [Import/Export of Mutable Globals] proposal (i.e. the `+mutable-globals` LLVM target feature flag)
+* Not compiling the `std` library at all, rather than compiling it with stubs.
+
+[Import/Export of Mutable Globals]: https://github.com/WebAssembly/mutable-global
+
+## Target maintainers
+
+- Alex Crichton, https://github.com/alexcrichton
+- Graydon Hoare, https://github.com/graydon
+
+## Requirements
+
+This target is cross-compiled. It does not support `std`, only `core` and `alloc`. Since it imports nothing from its environment, any `std` parts that use OS facilities would be stubbed out with functions-that-fail anyways, and the experience of working with the stub `std` in the `wasm32-unknown-unknown` target was deemed not something worth repeating here.
+
+Everything else about this target's requirements, building, usage and testing is the same as what's described in the [`wasm32-unknown-unknown` document](./wasm32-unknown-unknown.md), just using the target string `wasm32v1-none` in place of `wasm32-unknown-unknown`.
+
+## Conditionally compiling code
+
+It's recommended to conditionally compile code for this target with:
+
+```text
+#[cfg(all(target_family = "wasm", target_os = "none"))]
+```
+
+Note that there is no way to tell via `#[cfg]` whether code will be running on
+the web or not.
+
+## Enabled WebAssembly features
+
+As noted above, _no WebAssembly proposals past 1.0_ are enabled on this target by default. Indeed, the entire point of this target is to have a way to compile for a stable "no post-1.0 proposals" subset of WebAssembly _on stable Rust_.
+
+The [W3C WebAssembly Core 1.0 spec] was adopted as a W3C recommendation in December 2019, and includes exactly one "post-MVP" proposal: the [Import/Export of Mutable Globals] proposal.
+
+All subsequent proposals are _disabled_ on this target by default, though they can be individually enabled by passing LLVM target-feature flags.
+
+For reference sake, the set of proposals that LLVM supports at the time of writing, that this target _does not enable by default_, are listed here along with their LLVM target-feature flags:
+
+* Post-1.0 proposals (integrated into the WebAssembly core 2.0 spec):
+    * [Bulk memory] - `+bulk-memory`
+    * [Sign-extending operations] - `+sign-ext`
+    * [Non-trapping fp-to-int operations] - `+nontrapping-fptoint`
+    * [Multi-value] - `+multivalue`
+    * [Reference Types] - `+reference-types`
+    * [Fixed-width SIMD] - `+simd128`
+* Post-2.0 proposals:
+    * [Threads] (supported by atomics) - `+atomics`
+    * [Exception handling]  - `+exception-handling`
+    * [Extended Constant Expressions]  - `+extended-const`
+    * [Half Precision]  - `+half-precision`
+    * [Multiple memories]- `+multimemory`
+    * [Relaxed SIMD] - `+relaxed-simd`
+    * [Tail call] - `+tail-call`
+
+[Bulk memory]: https://github.com/WebAssembly/spec/blob/main/proposals/bulk-memory-operations/Overview.md
+[Sign-extending operations]: https://github.com/WebAssembly/spec/blob/main/proposals/sign-extension-ops/Overview.md
+[Non-trapping fp-to-int operations]: https://github.com/WebAssembly/spec/blob/main/proposals/nontrapping-float-to-int-conversion/Overview.md
+[Multi-value]: https://github.com/WebAssembly/spec/blob/main/proposals/multi-value/Overview.md
+[Reference Types]: https://github.com/WebAssembly/spec/blob/main/proposals/reference-types/Overview.md
+[Fixed-width SIMD]: https://github.com/WebAssembly/spec/blob/main/proposals/simd/SIMD.md
+[Threads]: https://github.com/webassembly/threads
+[Exception handling]: https://github.com/WebAssembly/exception-handling
+[Extended Constant Expressions]: https://github.com/WebAssembly/extended-const
+[Half Precision]: https://github.com/WebAssembly/half-precision
+[Multiple memories]: https://github.com/WebAssembly/multi-memory
+[Relaxed SIMD]: https://github.com/WebAssembly/relaxed-simd
+[Tail call]: https://github.com/WebAssembly/tail-call
+
+Additional proposals in the future are, of course, also not enabled by default.
+
+## Rationale relative to wasm32-unknown-unknown
+
+As noted in the [`wasm32-unknown-unknown` document](./wasm32-unknown-unknown.md), it is possible to compile with `--target wasm32-unknown-unknown` and disable all WebAssembly proposals "by hand", by passing `-Ctarget-cpu=mvp`. Furthermore one can enable proposals one by one by passing LLVM target feature flags, such as `-Ctarget-feature=+mutable-globals`.
+
+Is it therefore reasonable to wonder what the difference is between building with this:
+
+```sh
+$ rustc --target wasm32-unknown-unknown -Ctarget-cpu=mvp -Ctarget-feature=+mutable-globals
+```
+
+and building with this:
+
+```sh
+$ rustc --target wasm32v1-none
+```
+
+The difference is in how the `core` and `alloc` crates are compiled for distribution with the toolchain, and whether it works on _stable_ Rust toolchains or requires _nightly_ ones. Again referring back to the [`wasm32-unknown-unknown` document](./wasm32-unknown-unknown.md), note that to disable all post-MVP proposals on that target one _actually_ has to compile with this:
+
+```sh
+$ export RUSTFLAGS="-Ctarget-cpu=mvp -Ctarget-feature=+mutable-globals"
+$ cargo +nightly build -Zbuild-std=panic_abort,std --target wasm32-unknown-unknown
+```
+
+Which not only rebuilds `std`, `core` and `alloc` (which is somewhat costly and annoying) but more importantly requires the use of nightly Rust toolchains (for the `-Zbuild-std` flag). This is very undesirable for the target audience, which consists of people targeting WebAssembly implementations that prioritize stability, simplicity and/or security over feature support.
+
+This `wasm32v1-none` target exists as an alternative option that works on stable Rust toolchains, without rebuilding the stdlib.
diff --git a/src/doc/rustc/src/symbol-mangling/v0.md b/src/doc/rustc/src/symbol-mangling/v0.md
index 6329e87..1099425 100644
--- a/src/doc/rustc/src/symbol-mangling/v0.md
+++ b/src/doc/rustc/src/symbol-mangling/v0.md
@@ -1208,7 +1208,7 @@
 
 * Named functions, methods, and statics shall be represented by a *[path]* production.
 
-* Paths should be rooted at the inner-most entity that can act as a path root.
+* Paths should be rooted at the innermost entity that can act as a path root.
   Roots can be crate-ids, inherent impls, trait impls, and (for items within default methods) trait definitions.
 
 * The compiler is free to choose disambiguation indices and namespace tags from
diff --git a/src/doc/unstable-book/src/compiler-flags/regparm.md b/src/doc/unstable-book/src/compiler-flags/regparm.md
new file mode 100644
index 0000000..8f311f0
--- /dev/null
+++ b/src/doc/unstable-book/src/compiler-flags/regparm.md
@@ -0,0 +1,20 @@
+# `regparm`
+
+The tracking issue for this feature is: https://github.com/rust-lang/rust/issues/131749.
+
+------------------------
+
+Option -Zregparm=N causes the compiler to pass N arguments
+in registers EAX, EDX, and ECX instead of on the stack for "C", "cdecl", and "stdcall" fn.
+It is UNSOUND to link together crates that use different values for this flag.
+It is only supported on `x86`.
+
+It is equivalent to [Clang]'s and [GCC]'s `-mregparm`.
+
+Supported values for this option are 0-3.
+
+[Clang]: https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-mregparm
+[GCC]: https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html#index-regparm-function-attribute_002c-x86
+
+Implementation details:
+For eligible arguments, llvm `inreg` attribute is set.
diff --git a/src/doc/unstable-book/src/compiler-flags/sanitizer.md b/src/doc/unstable-book/src/compiler-flags/sanitizer.md
index 24940f0..4679acf 100644
--- a/src/doc/unstable-book/src/compiler-flags/sanitizer.md
+++ b/src/doc/unstable-book/src/compiler-flags/sanitizer.md
@@ -690,7 +690,6 @@
 
 LeakSanitizer is supported on the following targets:
 
-* `aarch64-apple-darwin`
 * `aarch64-unknown-linux-gnu`
 * `x86_64-apple-darwin`
 * `x86_64-unknown-linux-gnu`
diff --git a/src/etc/cat-and-grep.sh b/src/etc/cat-and-grep.sh
index 238f7f5..68c6993 100755
--- a/src/etc/cat-and-grep.sh
+++ b/src/etc/cat-and-grep.sh
@@ -33,7 +33,6 @@
     case "$OPTION" in
         v)
             INVERT=1
-            ERROR_MSG='should not be found'
             ;;
         i)
             GREPFLAGS="i$GREPFLAGS"
diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml
index 42df0b2..57b6de6 100644
--- a/src/librustdoc/Cargo.toml
+++ b/src/librustdoc/Cargo.toml
@@ -2,6 +2,7 @@
 name = "rustdoc"
 version = "0.0.0"
 edition = "2021"
+build = "build.rs"
 
 [lib]
 path = "lib.rs"
@@ -24,13 +25,15 @@
 tracing-tree = "0.3.0"
 threadpool = "1.8.1"
 unicode-segmentation = "1.9"
-sha2 = "0.10.8"
 
 [dependencies.tracing-subscriber]
 version = "0.3.3"
 default-features = false
 features = ["fmt", "env-filter", "smallvec", "parking_lot", "ansi"]
 
+[build-dependencies]
+sha2 = "0.10.8"
+
 [dev-dependencies]
 expect-test = "1.4.0"
 
diff --git a/src/librustdoc/build.rs b/src/librustdoc/build.rs
new file mode 100644
index 0000000..69337fb
--- /dev/null
+++ b/src/librustdoc/build.rs
@@ -0,0 +1,48 @@
+fn main() {
+    // generate sha256 files
+    // this avoids having to perform hashing at runtime
+    let files = &[
+        "static/css/rustdoc.css",
+        "static/css/noscript.css",
+        "static/css/normalize.css",
+        "static/js/main.js",
+        "static/js/search.js",
+        "static/js/settings.js",
+        "static/js/src-script.js",
+        "static/js/storage.js",
+        "static/js/scrape-examples.js",
+        "static/COPYRIGHT.txt",
+        "static/LICENSE-APACHE.txt",
+        "static/LICENSE-MIT.txt",
+        "static/images/rust-logo.svg",
+        "static/images/favicon.svg",
+        "static/images/favicon-32x32.png",
+        "static/fonts/FiraSans-Regular.woff2",
+        "static/fonts/FiraSans-Medium.woff2",
+        "static/fonts/FiraSans-LICENSE.txt",
+        "static/fonts/SourceSerif4-Regular.ttf.woff2",
+        "static/fonts/SourceSerif4-Bold.ttf.woff2",
+        "static/fonts/SourceSerif4-It.ttf.woff2",
+        "static/fonts/SourceSerif4-LICENSE.md",
+        "static/fonts/SourceCodePro-Regular.ttf.woff2",
+        "static/fonts/SourceCodePro-Semibold.ttf.woff2",
+        "static/fonts/SourceCodePro-It.ttf.woff2",
+        "static/fonts/SourceCodePro-LICENSE.txt",
+        "static/fonts/NanumBarunGothic.ttf.woff2",
+        "static/fonts/NanumBarunGothic-LICENSE.txt",
+    ];
+    let out_dir = std::env::var("OUT_DIR").expect("standard Cargo environment variable");
+    for path in files {
+        let inpath = format!("html/{path}");
+        println!("cargo::rerun-if-changed={inpath}");
+        let bytes = std::fs::read(inpath).expect("static path exists");
+        use sha2::Digest;
+        let bytes = sha2::Sha256::digest(bytes);
+        let mut digest = format!("-{bytes:x}");
+        digest.truncate(9);
+        let outpath = std::path::PathBuf::from(format!("{out_dir}/{path}.sha256"));
+        std::fs::create_dir_all(outpath.parent().expect("all file paths are in a directory"))
+            .expect("should be able to write to out_dir");
+        std::fs::write(&outpath, digest.as_bytes()).expect("write to out_dir");
+    }
+}
diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs
index d966f99..31e4e79 100644
--- a/src/librustdoc/clean/auto_trait.rs
+++ b/src/librustdoc/clean/auto_trait.rs
@@ -156,7 +156,7 @@
         .iter()
         .inspect(|param| {
             if cfg!(debug_assertions) {
-                debug_assert!(!param.is_anonymous_lifetime() && !param.is_host_effect());
+                debug_assert!(!param.is_anonymous_lifetime());
                 if let ty::GenericParamDefKind::Type { synthetic, .. } = param.kind {
                     debug_assert!(!synthetic && param.name != kw::SelfUpper);
                 }
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index e7f921e..97529e4 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -248,9 +248,7 @@
         // Check to see if it is a macro 2.0 or built-in macro
         if matches!(
             CStore::from_tcx(cx.tcx).load_macro_untracked(did, cx.tcx),
-            LoadedMacro::MacroDef(def, _)
-                if matches!(&def.kind, ast::ItemKind::MacroDef(ast_def)
-                    if !ast_def.macro_rules)
+            LoadedMacro::MacroDef { def, .. } if !def.macro_rules
         ) {
             once(crate_name).chain(relative).collect()
         } else {
@@ -747,24 +745,12 @@
     is_doc_hidden: bool,
 ) -> clean::ItemKind {
     match CStore::from_tcx(cx.tcx).load_macro_untracked(def_id, cx.tcx) {
-        LoadedMacro::MacroDef(item_def, _) => match macro_kind {
+        LoadedMacro::MacroDef { def, .. } => match macro_kind {
             MacroKind::Bang => {
-                if let ast::ItemKind::MacroDef(ref def) = item_def.kind {
-                    let vis =
-                        cx.tcx.visibility(import_def_id.map(|d| d.to_def_id()).unwrap_or(def_id));
-                    clean::MacroItem(clean::Macro {
-                        source: utils::display_macro_source(
-                            cx,
-                            name,
-                            def,
-                            def_id,
-                            vis,
-                            is_doc_hidden,
-                        ),
-                    })
-                } else {
-                    unreachable!()
-                }
+                let vis = cx.tcx.visibility(import_def_id.map(|d| d.to_def_id()).unwrap_or(def_id));
+                clean::MacroItem(clean::Macro {
+                    source: utils::display_macro_source(cx, name, &def, def_id, vis, is_doc_hidden),
+                })
             }
             MacroKind::Derive | MacroKind::Attr => {
                 clean::ProcMacroItem(clean::ProcMacro { kind: macro_kind, helpers: Vec::new() })
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 7d4d8d8..ea349f8 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -216,7 +216,7 @@
         hir::GenericBound::Outlives(lt) => GenericBound::Outlives(clean_lifetime(lt, cx)),
         hir::GenericBound::Trait(ref t) => {
             // `T: ~const Destruct` is hidden because `T: Destruct` is a no-op.
-            if t.modifiers == hir::TraitBoundModifier::MaybeConst
+            if let hir::BoundConstness::Maybe(_) = t.modifiers.constness
                 && cx.tcx.lang_items().destruct_trait() == Some(t.trait_ref.trait_def_id().unwrap())
             {
                 return None;
@@ -263,7 +263,7 @@
             trait_: clean_trait_ref_with_constraints(cx, poly_trait_ref, constraints),
             generic_params: clean_bound_vars(poly_trait_ref.bound_vars()),
         },
-        hir::TraitBoundModifier::None,
+        hir::TraitBoundModifiers::NONE,
     )
 }
 
@@ -368,7 +368,9 @@
         // FIXME(generic_const_exprs): should this do something?
         ty::ClauseKind::ConstEvaluatable(..)
         | ty::ClauseKind::WellFormed(..)
-        | ty::ClauseKind::ConstArgHasType(..) => None,
+        | ty::ClauseKind::ConstArgHasType(..)
+        // FIXME(effects): We can probably use this `HostEffect` pred to render `~const`.
+        | ty::ClauseKind::HostEffect(_) => None,
     }
 }
 
@@ -542,7 +544,7 @@
                 synthetic,
             })
         }
-        ty::GenericParamDefKind::Const { has_default, synthetic, is_host_effect: _ } => {
+        ty::GenericParamDefKind::Const { has_default, synthetic } => {
             (def.name, GenericParamDefKind::Const {
                 ty: Box::new(clean_middle_ty(
                     ty::Binder::dummy(
@@ -617,7 +619,7 @@
                 synthetic,
             })
         }
-        hir::GenericParamKind::Const { ty, default, synthetic, is_host_effect: _ } => {
+        hir::GenericParamKind::Const { ty, default, synthetic } => {
             (param.name.ident().name, GenericParamDefKind::Const {
                 ty: Box::new(clean_ty(ty, cx)),
                 default: default.map(|ct| {
@@ -797,7 +799,7 @@
                 }
                 true
             }
-            ty::GenericParamDefKind::Const { is_host_effect, .. } => !is_host_effect,
+            ty::GenericParamDefKind::Const { .. } => true,
         })
         .map(|param| clean_generic_param_def(param, ParamDefaults::Yes, cx))
         .collect();
@@ -1398,7 +1400,6 @@
                 clean_ty_generics(cx, tcx.generics_of(assoc_item.def_id), ty::GenericPredicates {
                     parent: None,
                     predicates,
-                    effects_min_tys: ty::List::empty(),
                 });
             simplify::move_bounds_to_generic_parameters(&mut generics);
 
@@ -2189,7 +2190,7 @@
         }
 
         ty::Alias(ty::Weak, data) => {
-            if cx.tcx.features().lazy_type_alias {
+            if cx.tcx.features().lazy_type_alias() {
                 // Weak type alias `data` represents the `type X` in `type X = Y`. If we need `Y`,
                 // we need to use `type_of`.
                 let path = clean_middle_path(
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 675507a..c62144b 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -8,7 +8,6 @@
 use rustc_ast::MetaItemInner;
 use rustc_ast_pretty::pprust;
 use rustc_attr::{ConstStability, Deprecation, Stability, StableSince};
-use rustc_const_eval::const_eval::is_unstable_const_fn;
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId};
@@ -641,12 +640,11 @@
             asyncness: ty::Asyncness,
         ) -> hir::FnHeader {
             let sig = tcx.fn_sig(def_id).skip_binder();
-            let constness =
-                if tcx.is_const_fn(def_id) || is_unstable_const_fn(tcx, def_id).is_some() {
-                    hir::Constness::Const
-                } else {
-                    hir::Constness::NotConst
-                };
+            let constness = if tcx.is_const_fn(def_id) {
+                hir::Constness::Const
+            } else {
+                hir::Constness::NotConst
+            };
             let asyncness = match asyncness {
                 ty::Asyncness::Yes => hir::IsAsync::Async(DUMMY_SP),
                 ty::Asyncness::No => hir::IsAsync::NotAsync,
@@ -664,9 +662,7 @@
                         safety
                     },
                     abi,
-                    constness: if tcx.is_const_fn(def_id)
-                        || is_unstable_const_fn(tcx, def_id).is_some()
-                    {
+                    constness: if tcx.is_const_fn(def_id) {
                         hir::Constness::Const
                     } else {
                         hir::Constness::NotConst
@@ -966,8 +962,8 @@
 
     fn cfg(&self, tcx: TyCtxt<'_>, hidden_cfg: &FxHashSet<Cfg>) -> Option<Arc<Cfg>> {
         let sess = tcx.sess;
-        let doc_cfg_active = tcx.features().doc_cfg;
-        let doc_auto_cfg_active = tcx.features().doc_auto_cfg;
+        let doc_cfg_active = tcx.features().doc_cfg();
+        let doc_auto_cfg_active = tcx.features().doc_auto_cfg();
 
         fn single<T: IntoIterator>(it: T) -> Option<T::Item> {
             let mut iter = it.into_iter();
@@ -1257,7 +1253,7 @@
 
 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
 pub(crate) enum GenericBound {
-    TraitBound(PolyTrait, hir::TraitBoundModifier),
+    TraitBound(PolyTrait, hir::TraitBoundModifiers),
     Outlives(Lifetime),
     /// `use<'a, T>` precise-capturing bound syntax
     Use(Vec<Symbol>),
@@ -1265,19 +1261,22 @@
 
 impl GenericBound {
     pub(crate) fn sized(cx: &mut DocContext<'_>) -> GenericBound {
-        Self::sized_with(cx, hir::TraitBoundModifier::None)
+        Self::sized_with(cx, hir::TraitBoundModifiers::NONE)
     }
 
     pub(crate) fn maybe_sized(cx: &mut DocContext<'_>) -> GenericBound {
-        Self::sized_with(cx, hir::TraitBoundModifier::Maybe)
+        Self::sized_with(cx, hir::TraitBoundModifiers {
+            polarity: hir::BoundPolarity::Maybe(DUMMY_SP),
+            constness: hir::BoundConstness::Never,
+        })
     }
 
-    fn sized_with(cx: &mut DocContext<'_>, modifier: hir::TraitBoundModifier) -> GenericBound {
+    fn sized_with(cx: &mut DocContext<'_>, modifiers: hir::TraitBoundModifiers) -> GenericBound {
         let did = cx.tcx.require_lang_item(LangItem::Sized, None);
         let empty = ty::Binder::dummy(ty::GenericArgs::empty());
         let path = clean_middle_path(cx, did, false, ThinVec::new(), empty);
         inline::record_extern_fqn(cx, did, ItemType::Trait);
-        GenericBound::TraitBound(PolyTrait { trait_: path, generic_params: Vec::new() }, modifier)
+        GenericBound::TraitBound(PolyTrait { trait_: path, generic_params: Vec::new() }, modifiers)
     }
 
     pub(crate) fn is_trait_bound(&self) -> bool {
@@ -1285,8 +1284,10 @@
     }
 
     pub(crate) fn is_sized_bound(&self, cx: &DocContext<'_>) -> bool {
-        use rustc_hir::TraitBoundModifier as TBM;
-        if let GenericBound::TraitBound(PolyTrait { ref trait_, .. }, TBM::None) = *self
+        if let GenericBound::TraitBound(
+            PolyTrait { ref trait_, .. },
+            rustc_hir::TraitBoundModifiers::NONE,
+        ) = *self
             && Some(trait_.def_id()) == cx.tcx.lang_items().sized_trait()
         {
             return true;
@@ -1361,8 +1362,7 @@
 
     pub(crate) fn is_synthetic_param(&self) -> bool {
         match self.kind {
-            GenericParamDefKind::Lifetime { .. } => false,
-            GenericParamDefKind::Const { synthetic: is_host_effect, .. } => is_host_effect,
+            GenericParamDefKind::Lifetime { .. } | GenericParamDefKind::Const { .. } => false,
             GenericParamDefKind::Type { synthetic, .. } => synthetic,
         }
     }
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index fdf628b..d3a545f 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -114,10 +114,6 @@
 
         // Elide internal host effect args.
         let param = generics.param_at(index, cx.tcx);
-        if param.is_host_effect() {
-            return None;
-        }
-
         let arg = ty::Binder::bind_with_vars(arg, bound_vars);
 
         // Elide arguments that coincide with their default.
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 9bebe1f..0f7d4d3 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -8,7 +8,7 @@
 use rustc_errors::codes::*;
 use rustc_errors::emitter::{DynEmitter, HumanEmitter, stderr_destination};
 use rustc_errors::json::JsonEmitter;
-use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed, TerminalUrl};
+use rustc_errors::{ErrorGuaranteed, TerminalUrl};
 use rustc_feature::UnstableFeatures;
 use rustc_hir::def::Res;
 use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LocalDefId};
@@ -21,8 +21,8 @@
 use rustc_session::config::{self, CrateType, ErrorOutputType, Input, ResolveDocLinks};
 pub(crate) use rustc_session::config::{Options, UnstableOptions};
 use rustc_session::{Session, lint};
+use rustc_span::source_map;
 use rustc_span::symbol::sym;
-use rustc_span::{Span, source_map};
 use tracing::{debug, info};
 
 use crate::clean::inline::build_external_trait;
@@ -381,45 +381,10 @@
         );
     }
 
-    fn report_deprecated_attr(name: &str, dcx: DiagCtxtHandle<'_>, sp: Span) {
-        let mut msg =
-            dcx.struct_span_warn(sp, format!("the `#![doc({name})]` attribute is deprecated"));
-        msg.note(
-            "see issue #44136 <https://github.com/rust-lang/rust/issues/44136> \
-            for more information",
-        );
-
-        if name == "no_default_passes" {
-            msg.help("`#![doc(no_default_passes)]` no longer functions; you may want to use `#![doc(document_private_items)]`");
-        } else if name.starts_with("passes") {
-            msg.help("`#![doc(passes = \"...\")]` no longer functions; you may want to use `#![doc(document_private_items)]`");
-        } else if name.starts_with("plugins") {
-            msg.warn("`#![doc(plugins = \"...\")]` no longer functions; see CVE-2018-1000622 <https://nvd.nist.gov/vuln/detail/CVE-2018-1000622>");
-        }
-
-        msg.emit();
-    }
-
     // Process all of the crate attributes, extracting plugin metadata along
     // with the passes which we are supposed to run.
     for attr in krate.module.attrs.lists(sym::doc) {
-        let dcx = ctxt.sess().dcx();
-
         let name = attr.name_or_empty();
-        // `plugins = "..."`, `no_default_passes`, and `passes = "..."` have no effect
-        if attr.is_word() && name == sym::no_default_passes {
-            report_deprecated_attr("no_default_passes", dcx, attr.span());
-        } else if attr.value_str().is_some() {
-            match name {
-                sym::passes => {
-                    report_deprecated_attr("passes = \"...\"", dcx, attr.span());
-                }
-                sym::plugins => {
-                    report_deprecated_attr("plugins = \"...\"", dcx, attr.span());
-                }
-                _ => (),
-            }
-        }
 
         if attr.is_word() && name == sym::document_private_items {
             ctxt.render_options.document_private = true;
diff --git a/src/librustdoc/doctest/make.rs b/src/librustdoc/doctest/make.rs
index efbb332..3ae6093 100644
--- a/src/librustdoc/doctest/make.rs
+++ b/src/librustdoc/doctest/make.rs
@@ -289,7 +289,12 @@
     // Recurse through functions body. It is necessary because the doctest source code is
     // wrapped in a function to limit the number of AST errors. If we don't recurse into
     // functions, we would thing all top-level items (so basically nothing).
-    fn check_item(item: &ast::Item, info: &mut ParseSourceInfo, crate_name: &Option<&str>) {
+    fn check_item(
+        item: &ast::Item,
+        info: &mut ParseSourceInfo,
+        crate_name: &Option<&str>,
+        is_top_level: bool,
+    ) {
         if !info.has_global_allocator
             && item.attrs.iter().any(|attr| attr.name_or_empty() == sym::global_allocator)
         {
@@ -297,13 +302,15 @@
         }
         match item.kind {
             ast::ItemKind::Fn(ref fn_item) if !info.has_main_fn => {
-                if item.ident.name == sym::main {
+                if item.ident.name == sym::main && is_top_level {
                     info.has_main_fn = true;
                 }
                 if let Some(ref body) = fn_item.body {
                     for stmt in &body.stmts {
                         match stmt.kind {
-                            ast::StmtKind::Item(ref item) => check_item(item, info, crate_name),
+                            ast::StmtKind::Item(ref item) => {
+                                check_item(item, info, crate_name, false)
+                            }
                             ast::StmtKind::MacCall(..) => info.found_macro = true,
                             _ => {}
                         }
@@ -329,7 +336,7 @@
     loop {
         match parser.parse_item(ForceCollect::No) {
             Ok(Some(item)) => {
-                check_item(&item, info, crate_name);
+                check_item(&item, info, crate_name, true);
 
                 if info.has_main_fn && info.found_extern_crate {
                     break;
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 2e70a8c..8e8e5c6 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -16,6 +16,7 @@
 use rustc_attr::{ConstStability, StabilityLevel, StableSince};
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fx::FxHashSet;
+use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
 use rustc_metadata::creader::{CStore, LoadedMacro};
@@ -25,7 +26,6 @@
 use rustc_span::{Symbol, sym};
 use rustc_target::spec::abi::Abi;
 use tracing::{debug, trace};
-use {rustc_ast as ast, rustc_hir as hir};
 
 use super::url_parts_builder::{UrlPartsBuilder, estimate_item_path_byte_length};
 use crate::clean::types::ExternalLocation;
@@ -399,13 +399,13 @@
     ) -> impl Display + 'a + Captures<'tcx> {
         display_fn(move |f| match self {
             clean::GenericBound::Outlives(lt) => write!(f, "{}", lt.print()),
-            clean::GenericBound::TraitBound(ty, modifier) => {
-                f.write_str(match modifier {
-                    hir::TraitBoundModifier::None => "",
-                    hir::TraitBoundModifier::Maybe => "?",
-                    hir::TraitBoundModifier::Negative => "!",
-                    // `const` and `~const` trait bounds are experimental; don't render them.
-                    hir::TraitBoundModifier::Const | hir::TraitBoundModifier::MaybeConst => "",
+            clean::GenericBound::TraitBound(ty, modifiers) => {
+                // `const` and `~const` trait bounds are experimental; don't render them.
+                let hir::TraitBoundModifiers { polarity, constness: _ } = modifiers;
+                f.write_str(match polarity {
+                    hir::BoundPolarity::Positive => "",
+                    hir::BoundPolarity::Maybe(_) => "?",
+                    hir::BoundPolarity::Negative(_) => "!",
                 })?;
                 ty.print(cx).fmt(f)
             }
@@ -554,10 +554,8 @@
     // Check to see if it is a macro 2.0 or built-in macro.
     // More information in <https://rust-lang.github.io/rfcs/1584-macros.html>.
     let is_macro_2 = match cstore.load_macro_untracked(def_id, tcx) {
-        LoadedMacro::MacroDef(def, _) => {
-            // If `ast_def.macro_rules` is `true`, then it's not a macro 2.0.
-            matches!(&def.kind, ast::ItemKind::MacroDef(ast_def) if !ast_def.macro_rules)
-        }
+        // If `def.macro_rules` is `true`, then it's not a macro 2.0.
+        LoadedMacro::MacroDef { def, .. } => !def.macro_rules,
         _ => false,
     };
 
@@ -1368,6 +1366,24 @@
                 write!(f, " -> ")?;
                 fmt_type(&bare_fn.decl.output, f, use_absolute, cx)?;
             }
+        } else if let clean::Type::Path { path } = type_
+            && let Some(generics) = path.generics()
+            && generics.len() == 1
+            && self.kind.is_fake_variadic()
+        {
+            let ty = generics[0];
+            let wrapper = anchor(path.def_id(), path.last(), cx);
+            if f.alternate() {
+                write!(f, "{wrapper:#}&lt;")?;
+            } else {
+                write!(f, "{wrapper}<")?;
+            }
+            self.print_type(ty, f, use_absolute, cx)?;
+            if f.alternate() {
+                write!(f, "&gt;")?;
+            } else {
+                write!(f, ">")?;
+            }
         } else {
             fmt_type(&type_, f, use_absolute, cx)?;
         }
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index 399730a..8446235 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -1010,7 +1010,9 @@
                 // don't display const unstable if entirely unstable
                 None
             } else {
-                let unstable = if let Some(n) = issue {
+                let unstable = if let Some(n) = issue
+                    && let Some(feature) = feature
+                {
                     format!(
                         "<a \
                         href=\"https://github.com/rust-lang/rust/issues/{n}\" \
@@ -2010,9 +2012,9 @@
     );
     if let Some(link) = src_href {
         if has_stability {
-            write!(rightside, " · <a class=\"src\" href=\"{link}\">source</a>")
+            write!(rightside, " · <a class=\"src\" href=\"{link}\">Source</a>")
         } else {
-            write!(rightside, "<a class=\"src rightside\" href=\"{link}\">source</a>")
+            write!(rightside, "<a class=\"src rightside\" href=\"{link}\">Source</a>")
         }
     }
     if has_stability && has_src_ref {
diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs
index c958458b..d1939ad 100644
--- a/src/librustdoc/html/render/search_index.rs
+++ b/src/librustdoc/html/render/search_index.rs
@@ -759,7 +759,10 @@
         }
     });
     let (mut inputs, mut output, where_clause) = match item.kind {
-        clean::FunctionItem(ref f) | clean::MethodItem(ref f, _) | clean::TyMethodItem(ref f) => {
+        clean::ForeignFunctionItem(ref f, _)
+        | clean::FunctionItem(ref f)
+        | clean::MethodItem(ref f, _)
+        | clean::TyMethodItem(ref f) => {
             get_fn_inputs_and_outputs(f, tcx, impl_or_trait_generics, cache)
         }
         _ => return None,
diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs
index 12b63460..c82f7e9 100644
--- a/src/librustdoc/html/render/write_shared.rs
+++ b/src/librustdoc/html/render/write_shared.rs
@@ -112,7 +112,7 @@
                 md_opts.output = cx.dst.clone();
                 md_opts.external_html = cx.shared.layout.external_html.clone();
                 try_err!(
-                    crate::markdown::render(&index_page, md_opts, cx.shared.edition()),
+                    crate::markdown::render_and_write(&index_page, md_opts, cx.shared.edition()),
                     &index_page
                 );
             }
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index 2c17fd5..97e8b8f 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -185,7 +185,7 @@
 	grid-template-columns: minmax(105px, 1fr) minmax(0, max-content);
 	grid-template-rows: minmax(25px, min-content) min-content min-content;
 	padding-bottom: 6px;
-	margin-bottom: 11px;
+	margin-bottom: 15px;
 }
 .rustdoc-breadcrumbs {
 	grid-area: main-heading-breadcrumbs;
@@ -959,7 +959,7 @@
 	background: var(--table-alt-row-background-color);
 }
 
-.docblock .stab, .docblock-short .stab {
+.docblock .stab, .docblock-short .stab, .docblock p code {
 	display: inline-block;
 }
 
@@ -1004,6 +1004,7 @@
 	display: flex;
 	height: 34px;
 	flex-grow: 1;
+	margin-bottom: 4px;
 }
 .src nav.sub {
 	margin: 0 0 -10px 0;
@@ -2253,7 +2254,12 @@
 
 	/* We don't display this button on mobile devices. */
 	#copy-path {
-		display: none;
+		/* display: none; avoided as a layout hack.
+			When there's one line, we get an effective line-height of 34px,
+			because that's how big the image is, but if the header wraps,
+			they're packed more tightly than that. */
+		width: 0;
+		visibility: hidden;
 	}
 
 	/* Text label takes up too much space at this size. */
diff --git a/src/librustdoc/html/static_files.rs b/src/librustdoc/html/static_files.rs
index 9e0803f..a4dc8cd 100644
--- a/src/librustdoc/html/static_files.rs
+++ b/src/librustdoc/html/static_files.rs
@@ -12,8 +12,8 @@
 }
 
 impl StaticFile {
-    fn new(filename: &str, bytes: &'static [u8]) -> StaticFile {
-        Self { filename: static_filename(filename, bytes), bytes }
+    fn new(filename: &str, bytes: &'static [u8], sha256: &'static str) -> StaticFile {
+        Self { filename: static_filename(filename, sha256), bytes }
     }
 
     pub(crate) fn minified(&self) -> Vec<u8> {
@@ -55,17 +55,9 @@
     filename.into()
 }
 
-pub(crate) fn static_filename(filename: &str, contents: &[u8]) -> PathBuf {
+pub(crate) fn static_filename(filename: &str, sha256: &str) -> PathBuf {
     let filename = filename.rsplit('/').next().unwrap();
-    suffix_path(filename, &static_suffix(contents))
-}
-
-fn static_suffix(bytes: &[u8]) -> String {
-    use sha2::Digest;
-    let bytes = sha2::Sha256::digest(bytes);
-    let mut digest = format!("-{bytes:x}");
-    digest.truncate(9);
-    digest
+    suffix_path(filename, &sha256)
 }
 
 macro_rules! static_files {
@@ -74,8 +66,9 @@
             $(pub $field: StaticFile,)+
         }
 
+        // sha256 files are generated in build.rs
         pub(crate) static STATIC_FILES: std::sync::LazyLock<StaticFiles> = std::sync::LazyLock::new(|| StaticFiles {
-            $($field: StaticFile::new($file_path, include_bytes!($file_path)),)+
+            $($field: StaticFile::new($file_path, include_bytes!($file_path), include_str!(concat!(env!("OUT_DIR"), "/", $file_path, ".sha256"))),)+
         });
 
         pub(crate) fn for_each<E>(f: impl Fn(&StaticFile) -> Result<(), E>) -> Result<(), E> {
diff --git a/src/librustdoc/html/templates/print_item.html b/src/librustdoc/html/templates/print_item.html
index f60720b..9fd575b 100644
--- a/src/librustdoc/html/templates/print_item.html
+++ b/src/librustdoc/html/templates/print_item.html
@@ -26,7 +26,7 @@
         {% match src_href %}
             {% when Some with (href) %}
                 {% if !stability_since_raw.is_empty() +%} · {%+ endif %}
-                <a class="src" href="{{href|safe}}">source</a> {#+ #}
+                <a class="src" href="{{href|safe}}">Source</a> {#+ #}
             {% else %}
         {% endmatch %}
     </span> {# #}
diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs
index 0130f2c..7270f17 100644
--- a/src/librustdoc/json/conversions.rs
+++ b/src/librustdoc/json/conversions.rs
@@ -552,20 +552,18 @@
 }
 
 pub(crate) fn from_trait_bound_modifier(
-    modifier: rustc_hir::TraitBoundModifier,
+    modifiers: rustc_hir::TraitBoundModifiers,
 ) -> TraitBoundModifier {
-    use rustc_hir::TraitBoundModifier::*;
-    match modifier {
-        None => TraitBoundModifier::None,
-        Maybe => TraitBoundModifier::Maybe,
-        MaybeConst => TraitBoundModifier::MaybeConst,
-        // FIXME(const_trait_impl): Create rjt::TBM::Const and map to it once always-const bounds
-        // are less experimental.
-        Const => TraitBoundModifier::None,
-        // FIXME(negative-bounds): This bound should be rendered negative, but
-        // since that's experimental, maybe let's not add it to the rustdoc json
-        // API just now...
-        Negative => TraitBoundModifier::None,
+    use rustc_hir as hir;
+    let hir::TraitBoundModifiers { constness, polarity } = modifiers;
+    match (constness, polarity) {
+        (hir::BoundConstness::Never, hir::BoundPolarity::Positive) => TraitBoundModifier::None,
+        (hir::BoundConstness::Never, hir::BoundPolarity::Maybe(_)) => TraitBoundModifier::Maybe,
+        (hir::BoundConstness::Maybe(_), hir::BoundPolarity::Positive) => {
+            TraitBoundModifier::MaybeConst
+        }
+        // FIXME: Fill out the rest of this matrix.
+        _ => TraitBoundModifier::None,
     }
 }
 
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index 10fc0ea..7c9dcd4 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -37,7 +37,6 @@
 extern crate rustc_ast;
 extern crate rustc_ast_pretty;
 extern crate rustc_attr;
-extern crate rustc_const_eval;
 extern crate rustc_data_structures;
 extern crate rustc_driver;
 extern crate rustc_errors;
@@ -817,7 +816,7 @@
             return wrap_return(
                 dcx,
                 interface::run_compiler(config, |_compiler| {
-                    markdown::render(&md_input, render_options, edition)
+                    markdown::render_and_write(&md_input, render_options, edition)
                 }),
             );
         }
diff --git a/src/librustdoc/lint.rs b/src/librustdoc/lint.rs
index bdfdeea..2afb9e5 100644
--- a/src/librustdoc/lint.rs
+++ b/src/librustdoc/lint.rs
@@ -31,9 +31,9 @@
     allowed_lints.extend(lint_opts.iter().map(|(lint, _)| lint).cloned());
 
     let lints = || {
-        lint::builtin::HardwiredLints::get_lints()
+        lint::builtin::HardwiredLints::lint_vec()
             .into_iter()
-            .chain(rustc_lint::SoftLints::get_lints())
+            .chain(rustc_lint::SoftLints::lint_vec())
     };
 
     let lint_opts = lints()
diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs
index 978f96f..76eac08 100644
--- a/src/librustdoc/markdown.rs
+++ b/src/librustdoc/markdown.rs
@@ -1,3 +1,13 @@
+//! Standalone markdown rendering.
+//!
+//! For the (much more common) case of rendering markdown in doc-comments, see
+//! [crate::html::markdown].
+//!
+//! This is used when [rendering a markdown file to an html file][docs], without processing
+//! rust source code.
+//!
+//! [docs]: https://doc.rust-lang.org/stable/rustdoc/#using-standalone-markdown-files
+
 use std::fmt::Write as _;
 use std::fs::{File, create_dir_all, read_to_string};
 use std::io::prelude::*;
@@ -33,7 +43,7 @@
 /// (e.g., output = "bar" => "bar/foo.html").
 ///
 /// Requires session globals to be available, for symbol interning.
-pub(crate) fn render<P: AsRef<Path>>(
+pub(crate) fn render_and_write<P: AsRef<Path>>(
     input: P,
     options: RenderOptions,
     edition: Edition,
diff --git a/src/librustdoc/passes/check_doc_test_visibility.rs b/src/librustdoc/passes/check_doc_test_visibility.rs
index f4579d8..484bdb5 100644
--- a/src/librustdoc/passes/check_doc_test_visibility.rs
+++ b/src/librustdoc/passes/check_doc_test_visibility.rs
@@ -116,7 +116,7 @@
 
     find_testable_code(dox, &mut tests, ErrorCodes::No, false, None);
 
-    if tests.found_tests == 0 && cx.tcx.features().rustdoc_missing_doc_code_examples {
+    if tests.found_tests == 0 && cx.tcx.features().rustdoc_missing_doc_code_examples() {
         if should_have_doc_example(cx, item) {
             debug!("reporting error for {item:?} (hir_id={hir_id:?})");
             let sp = item.attr_span(cx.tcx);
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index 2f0ea8d..140fda7 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -1419,7 +1419,7 @@
             && key.path_str.contains("::")
         // We only want to check this if this is an associated item.
         {
-            if key.item_id.is_local() && !self.cx.tcx.features().intra_doc_pointers {
+            if key.item_id.is_local() && !self.cx.tcx.features().intra_doc_pointers() {
                 self.report_rawptr_assoc_feature_gate(diag.dox, &diag.link_range, diag.item);
                 return None;
             } else {
diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs
index 62e1695..925cbfe 100644
--- a/src/tools/build-manifest/src/main.rs
+++ b/src/tools/build-manifest/src/main.rs
@@ -161,6 +161,7 @@
     "wasm32-wasip1",
     "wasm32-wasip1-threads",
     "wasm32-wasip2",
+    "wasm32v1-none",
     "x86_64-apple-darwin",
     "x86_64-apple-ios",
     "x86_64-apple-ios-macabi",
diff --git a/src/tools/cargo b/src/tools/cargo
index cf53cc5..e75214e 160000
--- a/src/tools/cargo
+++ b/src/tools/cargo
@@ -1 +1 @@
-Subproject commit cf53cc54bb593b5ec3dc2be4b1702f50c36d24d5
+Subproject commit e75214ea4936d2f2c909a71a1237042cc0e14b07
diff --git a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs
index 495d8ce..4774352 100644
--- a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs
+++ b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs
@@ -31,6 +31,7 @@
     pub COGNITIVE_COMPLEXITY,
     nursery,
     "functions that should be split up into multiple functions"
+    @eval_always = true
 }
 
 pub struct CognitiveComplexity {
diff --git a/src/tools/clippy/clippy_lints/src/ctfe.rs b/src/tools/clippy/clippy_lints/src/ctfe.rs
new file mode 100644
index 0000000..2fe37a6
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/ctfe.rs
@@ -0,0 +1,40 @@
+use rustc_hir::def_id::LocalDefId;
+use rustc_hir::intravisit::FnKind;
+use rustc_hir::{Body, FnDecl};
+use rustc_lint::Level::Deny;
+use rustc_lint::{LateContext, LateLintPass, Lint};
+use rustc_session::declare_lint_pass;
+use rustc_span::Span;
+
+/// Ensures that Constant-time Function Evaluation is being done (specifically, MIR lint passes).
+/// As Clippy deactivates codegen, this lint ensures that CTFE (used in hard errors) is still ran.
+pub static CLIPPY_CTFE: &Lint = &Lint {
+    name: &"clippy::CLIPPY_CTFE",
+    default_level: Deny,
+    desc: "Ensure CTFE is being made",
+    edition_lint_opts: None,
+    report_in_external_macro: true,
+    future_incompatible: None,
+    is_externally_loaded: true,
+    crate_level_only: false,
+    eval_always: true,
+    ..Lint::default_fields_for_macro()
+};
+
+// No static CLIPPY_CTFE_INFO because we want this lint to be invisible
+
+declare_lint_pass! { ClippyCtfe => [CLIPPY_CTFE] }
+
+impl<'tcx> LateLintPass<'tcx> for ClippyCtfe {
+    fn check_fn(
+        &mut self,
+        cx: &LateContext<'_>,
+        _: FnKind<'tcx>,
+        _: &'tcx FnDecl<'tcx>,
+        _: &'tcx Body<'tcx>,
+        _: Span,
+        defid: LocalDefId,
+    ) {
+        cx.tcx.ensure().mir_drops_elaborated_and_const_checked(defid); // Lint
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/declare_clippy_lint.rs b/src/tools/clippy/clippy_lints/src/declare_clippy_lint.rs
index b1e39c7..a785a9d 100644
--- a/src/tools/clippy/clippy_lints/src/declare_clippy_lint.rs
+++ b/src/tools/clippy/clippy_lints/src/declare_clippy_lint.rs
@@ -9,6 +9,7 @@
         $desc:literal,
         $version_expr:expr,
         $version_lit:literal
+        $(, $eval_always: literal)?
     ) => {
         rustc_session::declare_tool_lint! {
             $(#[doc = $lit])*
@@ -17,6 +18,7 @@
             $category,
             $desc,
             report_in_external_macro:true
+            $(, @eval_always = $eval_always)?
         }
 
         pub(crate) static ${concat($lint_name, _INFO)}: &'static crate::LintInfo = &crate::LintInfo {
@@ -33,11 +35,12 @@
         pub $lint_name:ident,
         restriction,
         $desc:literal
+        $(@eval_always = $eval_always: literal)?
     ) => {
         declare_clippy_lint! {@
             $(#[doc = $lit])*
             pub $lint_name, Allow, crate::LintCategory::Restriction, $desc,
-            Some($version), $version
+            Some($version), $version $(, $eval_always)?
         }
     };
     (
@@ -46,12 +49,12 @@
         pub $lint_name:ident,
         style,
         $desc:literal
+        $(@eval_always = $eval_always: literal)?
     ) => {
         declare_clippy_lint! {@
             $(#[doc = $lit])*
             pub $lint_name, Warn, crate::LintCategory::Style, $desc,
-            Some($version), $version
-
+            Some($version), $version $(, $eval_always)?
         }
     };
     (
@@ -60,11 +63,12 @@
         pub $lint_name:ident,
         correctness,
         $desc:literal
+        $(@eval_always = $eval_always: literal)?
     ) => {
         declare_clippy_lint! {@
             $(#[doc = $lit])*
             pub $lint_name, Deny, crate::LintCategory::Correctness, $desc,
-            Some($version), $version
+            Some($version), $version $(, $eval_always)?
 
         }
     };
@@ -74,11 +78,12 @@
         pub $lint_name:ident,
         perf,
         $desc:literal
+        $(@eval_always = $eval_always: literal)?
     ) => {
         declare_clippy_lint! {@
             $(#[doc = $lit])*
             pub $lint_name, Warn, crate::LintCategory::Perf, $desc,
-            Some($version), $version
+            Some($version), $version $(, $eval_always)?
         }
     };
     (
@@ -87,11 +92,12 @@
         pub $lint_name:ident,
         complexity,
         $desc:literal
+        $(@eval_always = $eval_always: literal)?
     ) => {
         declare_clippy_lint! {@
             $(#[doc = $lit])*
             pub $lint_name, Warn, crate::LintCategory::Complexity, $desc,
-            Some($version), $version
+            Some($version), $version $(, $eval_always)?
         }
     };
     (
@@ -100,11 +106,12 @@
         pub $lint_name:ident,
         suspicious,
         $desc:literal
+        $(@eval_always = $eval_always: literal)?
     ) => {
         declare_clippy_lint! {@
             $(#[doc = $lit])*
             pub $lint_name, Warn, crate::LintCategory::Suspicious, $desc,
-            Some($version), $version
+            Some($version), $version $(, $eval_always)?
         }
     };
     (
@@ -113,11 +120,12 @@
         pub $lint_name:ident,
         nursery,
         $desc:literal
+        $(@eval_always = $eval_always: literal)?
     ) => {
         declare_clippy_lint! {@
             $(#[doc = $lit])*
             pub $lint_name, Allow, crate::LintCategory::Nursery, $desc,
-            Some($version), $version
+            Some($version), $version $(, $eval_always)?
         }
     };
     (
@@ -126,11 +134,12 @@
         pub $lint_name:ident,
         pedantic,
         $desc:literal
+        $(@eval_always = $eval_always: literal)?
     ) => {
         declare_clippy_lint! {@
             $(#[doc = $lit])*
             pub $lint_name, Allow, crate::LintCategory::Pedantic, $desc,
-            Some($version), $version
+            Some($version), $version $(, $eval_always)?
         }
     };
     (
@@ -139,11 +148,12 @@
         pub $lint_name:ident,
         cargo,
         $desc:literal
+        $(@eval_always = $eval_always: literal)?
     ) => {
         declare_clippy_lint! {@
             $(#[doc = $lit])*
             pub $lint_name, Allow, crate::LintCategory::Cargo, $desc,
-            Some($version), $version
+            Some($version), $version $(, $eval_always)?
         }
     };
 
diff --git a/src/tools/clippy/clippy_lints/src/deprecated_lints.rs b/src/tools/clippy/clippy_lints/src/deprecated_lints.rs
index 0066ed6..77dbe9b 100644
--- a/src/tools/clippy/clippy_lints/src/deprecated_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/deprecated_lints.rs
@@ -166,7 +166,7 @@
     #[clippy::version = ""]
     ("clippy::positional_named_format_parameters", "named_arguments_used_positionally"),
     #[clippy::version = ""]
-    ("clippy::temporary_cstring_as_ptr", "temporary_cstring_as_ptr"),
+    ("clippy::temporary_cstring_as_ptr", "dangling_pointers_from_temporaries"),
     #[clippy::version = ""]
     ("clippy::undropped_manually_drops", "undropped_manually_drops"),
     #[clippy::version = ""]
diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs
index 82a66cc..e8e21edd 100644
--- a/src/tools/clippy/clippy_lints/src/derive.rs
+++ b/src/tools/clippy/clippy_lints/src/derive.rs
@@ -324,7 +324,7 @@
     // If the current self type doesn't implement Copy (due to generic constraints), search to see if
     // there's a Copy impl for any instance of the adt.
     if !is_copy(cx, ty) {
-        if ty_subs.non_erasable_generics(cx.tcx, ty_adt.did()).next().is_some() {
+        if ty_subs.non_erasable_generics().next().is_some() {
             let has_copy_impl = cx.tcx.all_local_trait_impls(()).get(&copy_id).map_or(false, |impls| {
                 impls.iter().any(|&id| {
                     matches!(cx.tcx.type_of(id).instantiate_identity().kind(), ty::Adt(adt, _)
diff --git a/src/tools/clippy/clippy_lints/src/empty_enum.rs b/src/tools/clippy/clippy_lints/src/empty_enum.rs
index 70eb81f..b0389fd 100644
--- a/src/tools/clippy/clippy_lints/src/empty_enum.rs
+++ b/src/tools/clippy/clippy_lints/src/empty_enum.rs
@@ -64,7 +64,7 @@
     fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
         if let ItemKind::Enum(..) = item.kind
             // Only suggest the `never_type` if the feature is enabled
-            && cx.tcx.features().never_type
+            && cx.tcx.features().never_type()
             && let Some(adt) = cx.tcx.type_of(item.owner_id).instantiate_identity().ty_adt_def()
             && adt.variants().is_empty()
         {
diff --git a/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs b/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs
index 00f8323..65fdc93 100644
--- a/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs
+++ b/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs
@@ -3,7 +3,7 @@
 use rustc_errors::{Applicability, SuggestionStyle};
 use rustc_hir::def_id::DefId;
 use rustc_hir::{
-    AssocItemConstraint, GenericArg, GenericBound, GenericBounds, PredicateOrigin, TraitBoundModifier, TyKind,
+    AssocItemConstraint, GenericArg, GenericBound, GenericBounds, PredicateOrigin, TraitBoundModifiers, TyKind,
     WherePredicate,
 };
 use rustc_hir_analysis::lower_ty;
@@ -234,7 +234,7 @@
         .iter()
         .filter_map(|bound| {
             if let GenericBound::Trait(poly_trait) = bound
-                && let TraitBoundModifier::None = poly_trait.modifiers
+                && let TraitBoundModifiers::NONE = poly_trait.modifiers
                 && let [.., path] = poly_trait.trait_ref.path.segments
                 && poly_trait.bound_generic_params.is_empty()
                 && let Some(trait_def_id) = path.res.opt_def_id()
@@ -300,7 +300,7 @@
     // simply comparing trait `DefId`s won't be enough. We also need to compare the generics.
     for (index, bound) in bounds.iter().enumerate() {
         if let GenericBound::Trait(poly_trait) = bound
-            && let TraitBoundModifier::None = poly_trait.modifiers
+            && let TraitBoundModifiers::NONE = poly_trait.modifiers
             && let [.., path] = poly_trait.trait_ref.path.segments
             && let implied_args = path.args.map_or([].as_slice(), |a| a.args)
             && let implied_constraints = path.args.map_or([].as_slice(), |a| a.constraints)
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index 6e29dde..1411053 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -65,6 +65,7 @@
 #[cfg_attr(feature = "internal", allow(clippy::missing_clippy_version_attribute))]
 mod utils;
 
+pub mod ctfe; // Very important lint, do not remove (rust#125116)
 pub mod declared_lints;
 pub mod deprecated_lints;
 
@@ -605,6 +606,8 @@
         });
     }
 
+    store.register_late_pass(|_| Box::new(ctfe::ClippyCtfe));
+
     store.register_late_pass(move |_| Box::new(operators::arithmetic_side_effects::ArithmeticSideEffects::new(conf)));
     store.register_late_pass(|_| Box::new(utils::dump_hir::DumpHir));
     store.register_late_pass(|_| Box::new(utils::author::Author));
diff --git a/src/tools/clippy/clippy_lints/src/manual_div_ceil.rs b/src/tools/clippy/clippy_lints/src/manual_div_ceil.rs
index 00e02e2..4c171e6 100644
--- a/src/tools/clippy/clippy_lints/src/manual_div_ceil.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_div_ceil.rs
@@ -111,11 +111,7 @@
     let expr_ty = cx.typeck_results().expr_ty(expr);
     match expr_ty.peel_refs().kind() {
         ty::Uint(_) => true,
-        ty::Int(_) => cx
-            .tcx
-            .features()
-            .declared_features
-            .contains(&Symbol::intern("int_roundings")),
+        ty::Int(_) => cx.tcx.features().enabled(Symbol::intern("int_roundings")),
 
         _ => false,
     }
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
index f9ffbc5..20984bc 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
@@ -114,7 +114,7 @@
     let indexed_arms: Vec<(usize, &Arm<'_>)> = arms.iter().enumerate().collect();
     for (&(i, arm1), &(j, arm2)) in search_same(&indexed_arms, hash, eq) {
         if matches!(arm2.pat.kind, PatKind::Wild) {
-            if !cx.tcx.features().non_exhaustive_omitted_patterns_lint
+            if !cx.tcx.features().non_exhaustive_omitted_patterns_lint()
                 || is_lint_allowed(cx, NON_EXHAUSTIVE_OMITTED_PATTERNS, arm2.hir_id)
             {
                 let arm_span = adjusted_arm_span(cx, arm1.span);
diff --git a/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs b/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs
index 564c598..42d9efe 100644
--- a/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs
@@ -251,7 +251,7 @@
 fn expr_can_be_pat(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     for_each_expr_without_closures(expr, |expr| {
         if match expr.kind {
-            ExprKind::ConstBlock(..) => cx.tcx.features().inline_const_pat,
+            ExprKind::ConstBlock(..) => cx.tcx.features().inline_const_pat(),
             ExprKind::Call(c, ..) if let ExprKind::Path(qpath) = c.kind => {
                 // Allow ctors
                 matches!(cx.qpath_res(&qpath, c.hir_id), Res::Def(DefKind::Ctor(..), ..))
diff --git a/src/tools/clippy/clippy_lints/src/needless_maybe_sized.rs b/src/tools/clippy/clippy_lints/src/needless_maybe_sized.rs
index 68c9af0..9a1c397 100644
--- a/src/tools/clippy/clippy_lints/src/needless_maybe_sized.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_maybe_sized.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use rustc_errors::Applicability;
 use rustc_hir::def_id::{DefId, DefIdMap};
-use rustc_hir::{GenericBound, Generics, PolyTraitRef, TraitBoundModifier, WherePredicate};
+use rustc_hir::{GenericBound, Generics, PolyTraitRef, TraitBoundModifiers, BoundPolarity, WherePredicate};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::{ClauseKind, PredicatePolarity};
 use rustc_session::declare_lint_pass;
@@ -118,13 +118,13 @@
         let maybe_sized_params: DefIdMap<_> = type_param_bounds(generics)
             .filter(|bound| {
                 bound.trait_bound.trait_ref.trait_def_id() == Some(sized_trait)
-                    && bound.trait_bound.modifiers == TraitBoundModifier::Maybe
+                    && matches!(bound.trait_bound.modifiers.polarity, BoundPolarity::Maybe(_))
             })
             .map(|bound| (bound.param, bound))
             .collect();
 
         for bound in type_param_bounds(generics) {
-            if bound.trait_bound.modifiers == TraitBoundModifier::None
+            if bound.trait_bound.modifiers == TraitBoundModifiers::NONE
                 && let Some(sized_bound) = maybe_sized_params.get(&bound.param)
                 && let Some(path) = path_to_sized_bound(cx, bound.trait_bound)
             {
diff --git a/src/tools/clippy/clippy_lints/src/trait_bounds.rs b/src/tools/clippy/clippy_lints/src/trait_bounds.rs
index 7f528b9..3da4bf6 100644
--- a/src/tools/clippy/clippy_lints/src/trait_bounds.rs
+++ b/src/tools/clippy/clippy_lints/src/trait_bounds.rs
@@ -11,7 +11,7 @@
 use rustc_hir::def::Res;
 use rustc_hir::{
     GenericBound, Generics, Item, ItemKind, LangItem, Node, Path, PathSegment, PredicateOrigin, QPath,
-    TraitBoundModifier, TraitItem, TraitRef, Ty, TyKind, WherePredicate,
+    TraitBoundModifiers, TraitItem, TraitRef, Ty, TyKind, WherePredicate, BoundPolarity,
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::impl_lint_pass;
@@ -233,7 +233,7 @@
     fn cannot_combine_maybe_bound(&self, cx: &LateContext<'_>, bound: &GenericBound<'_>) -> bool {
         if !self.msrv.meets(msrvs::MAYBE_BOUND_IN_WHERE)
             && let GenericBound::Trait(tr) = bound
-            && let TraitBoundModifier::Maybe = tr.modifiers
+            && let BoundPolarity::Maybe(_) = tr.modifiers.polarity
         {
             cx.tcx.lang_items().get(LangItem::Sized) == tr.trait_ref.path.res.opt_def_id()
         } else {
@@ -374,12 +374,12 @@
 struct ComparableTraitRef<'a, 'tcx> {
     cx: &'a LateContext<'tcx>,
     trait_ref: &'tcx TraitRef<'tcx>,
-    modifier: TraitBoundModifier,
+    modifiers: TraitBoundModifiers,
 }
 
 impl PartialEq for ComparableTraitRef<'_, '_> {
     fn eq(&self, other: &Self) -> bool {
-        self.modifier == other.modifier
+        SpanlessEq::new(self.cx).eq_modifiers(self.modifiers, other.modifiers)
             && SpanlessEq::new(self.cx)
                 .paths_by_resolution()
                 .eq_path(self.trait_ref.path, other.trait_ref.path)
@@ -390,8 +390,8 @@
     fn hash<H: Hasher>(&self, state: &mut H) {
         let mut s = SpanlessHash::new(self.cx).paths_by_resolution();
         s.hash_path(self.trait_ref.path);
+        s.hash_modifiers(self.modifiers);
         state.write_u64(s.finish());
-        self.modifier.hash(state);
     }
 }
 
@@ -400,7 +400,7 @@
         let trait_path = t.trait_ref.path;
         let trait_span = {
             let path_span = trait_path.span;
-            if let TraitBoundModifier::Maybe = t.modifiers {
+            if let BoundPolarity::Maybe(_) = t.modifiers.polarity {
                 path_span.with_lo(path_span.lo() - BytePos(1)) // include the `?`
             } else {
                 path_span
@@ -427,7 +427,7 @@
                 ComparableTraitRef {
                     cx,
                     trait_ref: &t.trait_ref,
-                    modifier: t.modifiers,
+                    modifiers: t.modifiers,
                 },
                 t.span,
             ))
diff --git a/src/tools/clippy/clippy_utils/src/ast_utils/ident_iter.rs b/src/tools/clippy/clippy_utils/src/ast_utils/ident_iter.rs
index 032cd3e..22b2c89 100644
--- a/src/tools/clippy/clippy_utils/src/ast_utils/ident_iter.rs
+++ b/src/tools/clippy/clippy_utils/src/ast_utils/ident_iter.rs
@@ -39,7 +39,7 @@
 struct IdentCollector(Vec<Ident>);
 
 impl Visitor<'_> for IdentCollector {
-    fn visit_ident(&mut self, ident: Ident) {
-        self.0.push(ident);
+    fn visit_ident(&mut self, ident: &Ident) {
+        self.0.push(*ident);
     }
 }
diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs
index 27c5780..181d414 100644
--- a/src/tools/clippy/clippy_utils/src/hir_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs
@@ -9,7 +9,8 @@
 use rustc_hir::{
     ArrayLen, AssocItemConstraint, BinOpKind, BindingMode, Block, BodyId, Closure, ConstArg, ConstArgKind, Expr,
     ExprField, ExprKind, FnRetTy, GenericArg, GenericArgs, HirId, HirIdMap, InlineAsmOperand, LetExpr, Lifetime,
-    LifetimeName, Pat, PatField, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, Ty, TyKind,
+    LifetimeName, Pat, PatField, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitBoundModifiers, Ty,
+    TyKind,
 };
 use rustc_lexer::{TokenKind, tokenize};
 use rustc_lint::LateContext;
@@ -126,6 +127,11 @@
     pub fn eq_path_segments(&mut self, left: &[PathSegment<'_>], right: &[PathSegment<'_>]) -> bool {
         self.inter_expr().eq_path_segments(left, right)
     }
+
+    pub fn eq_modifiers(&mut self, left: TraitBoundModifiers, right: TraitBoundModifiers) -> bool {
+        std::mem::discriminant(&left.constness) == std::mem::discriminant(&right.constness)
+            && std::mem::discriminant(&left.polarity) == std::mem::discriminant(&right.polarity)
+    }
 }
 
 pub struct HirEqInterExpr<'a, 'b, 'tcx> {
@@ -1143,6 +1149,12 @@
         }
     }
 
+    pub fn hash_modifiers(&mut self, modifiers: TraitBoundModifiers) {
+        let TraitBoundModifiers { constness, polarity } = modifiers;
+        std::mem::discriminant(&polarity).hash(&mut self.s);
+        std::mem::discriminant(&constness).hash(&mut self.s);
+    }
+
     pub fn hash_stmt(&mut self, b: &Stmt<'_>) {
         std::mem::discriminant(&b.kind).hash(&mut self.s);
 
diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
index 5f12b6b..4673986 100644
--- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
+++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
@@ -334,7 +334,7 @@
         | TerminatorKind::TailCall { func, args, fn_span: _ } => {
             let fn_ty = func.ty(body, tcx);
             if let ty::FnDef(fn_def_id, _) = *fn_ty.kind() {
-                if !is_const_fn(tcx, fn_def_id, msrv) {
+                if !is_stable_const_fn(tcx, fn_def_id, msrv) {
                     return Err((
                         span,
                         format!(
@@ -377,12 +377,12 @@
     }
 }
 
-fn is_const_fn(tcx: TyCtxt<'_>, def_id: DefId, msrv: &Msrv) -> bool {
+fn is_stable_const_fn(tcx: TyCtxt<'_>, def_id: DefId, msrv: &Msrv) -> bool {
     tcx.is_const_fn(def_id)
-        && tcx.lookup_const_stability(def_id).map_or(true, |const_stab| {
+        && tcx.lookup_const_stability(def_id).is_none_or(|const_stab| {
             if let rustc_attr::StabilityLevel::Stable { since, .. } = const_stab.level {
                 // Checking MSRV is manually necessary because `rustc` has no such concept. This entire
-                // function could be removed if `rustc` provided a MSRV-aware version of `is_const_fn`.
+                // function could be removed if `rustc` provided a MSRV-aware version of `is_stable_const_fn`.
                 // as a part of an unimplemented MSRV check https://github.com/rust-lang/rust/issues/65262.
 
                 let const_stab_rust_version = match since {
@@ -393,8 +393,12 @@
 
                 msrv.meets(const_stab_rust_version)
             } else {
-                // Unstable const fn with the feature enabled.
-                msrv.current().is_none()
+                // Unstable const fn, check if the feature is enabled. We need both the regular stability
+                // feature and (if set) the const stability feature to const-call this function.
+                let stab = tcx.lookup_stability(def_id);
+                let is_enabled = stab.is_some_and(|s| s.is_stable() || tcx.features().enabled(s.feature))
+                    && const_stab.feature.is_none_or(|f| tcx.features().enabled(f));
+                is_enabled && msrv.current().is_none()
             }
         })
 }
diff --git a/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs
index 91ec120..3021f21 100644
--- a/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs
+++ b/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs
@@ -207,16 +207,7 @@
             if cx.tcx.res_generics_def_id(path_segment.res).is_some() {
                 let generics = cx.tcx.generics_of(def_id);
 
-                let own_count = generics.own_params.len()
-                    - usize::from(generics.host_effect_index.is_some_and(|index| {
-                        // Check that the host index actually belongs to this resolution.
-                        // E.g. for `Add::add`, host_effect_index is `Some(2)`, but it's part of the parent `Add`
-                        // trait's generics.
-                        // Add params:      [Self#0, Rhs#1, host#2]   parent_count=0, count=3
-                        // Add::add params: []                        parent_count=3, count=3
-                        // (3..3).contains(&host_effect_index) => false
-                        (generics.parent_count..generics.count()).contains(&index)
-                    }));
+                let own_count = generics.own_params.len();
                 let lhs = if (parent_certainty.is_certain() || generics.parent_count == 0) && own_count == 0 {
                     Certainty::Certain(None)
                 } else {
@@ -310,8 +301,7 @@
 
     // Check that all type parameters appear in the functions input types.
     (0..(generics.parent_count + generics.own_params.len()) as u32).all(|index| {
-        Some(index as usize) == generics.host_effect_index
-            || fn_sig
+        fn_sig
                 .inputs()
                 .iter()
                 .any(|input_ty| contains_param(*input_ty.skip_binder(), index))
diff --git a/src/tools/clippy/clippy_utils/src/visitors.rs b/src/tools/clippy/clippy_utils/src/visitors.rs
index 0293130..8db6502 100644
--- a/src/tools/clippy/clippy_utils/src/visitors.rs
+++ b/src/tools/clippy/clippy_utils/src/visitors.rs
@@ -346,13 +346,13 @@
                     .cx
                     .qpath_res(p, hir_id)
                     .opt_def_id()
-                    .map_or(false, |id| self.cx.tcx.is_const_fn_raw(id)) => {},
+                    .map_or(false, |id| self.cx.tcx.is_const_fn(id)) => {},
                 ExprKind::MethodCall(..)
                     if self
                         .cx
                         .typeck_results()
                         .type_dependent_def_id(e.hir_id)
-                        .map_or(false, |id| self.cx.tcx.is_const_fn_raw(id)) => {},
+                        .map_or(false, |id| self.cx.tcx.is_const_fn(id)) => {},
                 ExprKind::Binary(_, lhs, rhs)
                     if self.cx.typeck_results().expr_ty(lhs).peel_refs().is_primitive_ty()
                         && self.cx.typeck_results().expr_ty(rhs).peel_refs().is_primitive_ty() => {},
diff --git a/src/tools/clippy/tests/ui/author.rs b/src/tools/clippy/tests/ui-internal/author.rs
similarity index 72%
rename from src/tools/clippy/tests/ui/author.rs
rename to src/tools/clippy/tests/ui-internal/author.rs
index 0a1be35..eb1f3e3 100644
--- a/src/tools/clippy/tests/ui/author.rs
+++ b/src/tools/clippy/tests/ui-internal/author.rs
@@ -1,3 +1,5 @@
+#![warn(clippy::author)]
+
 fn main() {
     #[clippy::author]
     let x: char = 0x45 as char;
diff --git a/src/tools/clippy/tests/ui/author.stdout b/src/tools/clippy/tests/ui-internal/author.stdout
similarity index 100%
rename from src/tools/clippy/tests/ui/author.stdout
rename to src/tools/clippy/tests/ui-internal/author.stdout
diff --git a/src/tools/clippy/tests/ui/author/blocks.rs b/src/tools/clippy/tests/ui-internal/author/blocks.rs
similarity index 100%
rename from src/tools/clippy/tests/ui/author/blocks.rs
rename to src/tools/clippy/tests/ui-internal/author/blocks.rs
diff --git a/src/tools/clippy/tests/ui/author/blocks.stdout b/src/tools/clippy/tests/ui-internal/author/blocks.stdout
similarity index 100%
rename from src/tools/clippy/tests/ui/author/blocks.stdout
rename to src/tools/clippy/tests/ui-internal/author/blocks.stdout
diff --git a/src/tools/clippy/tests/ui/author/call.rs b/src/tools/clippy/tests/ui-internal/author/call.rs
similarity index 100%
rename from src/tools/clippy/tests/ui/author/call.rs
rename to src/tools/clippy/tests/ui-internal/author/call.rs
diff --git a/src/tools/clippy/tests/ui/author/call.stdout b/src/tools/clippy/tests/ui-internal/author/call.stdout
similarity index 100%
rename from src/tools/clippy/tests/ui/author/call.stdout
rename to src/tools/clippy/tests/ui-internal/author/call.stdout
diff --git a/src/tools/clippy/tests/ui/author/if.rs b/src/tools/clippy/tests/ui-internal/author/if.rs
similarity index 100%
rename from src/tools/clippy/tests/ui/author/if.rs
rename to src/tools/clippy/tests/ui-internal/author/if.rs
diff --git a/src/tools/clippy/tests/ui/author/if.stdout b/src/tools/clippy/tests/ui-internal/author/if.stdout
similarity index 100%
rename from src/tools/clippy/tests/ui/author/if.stdout
rename to src/tools/clippy/tests/ui-internal/author/if.stdout
diff --git a/src/tools/clippy/tests/ui/author/issue_3849.rs b/src/tools/clippy/tests/ui-internal/author/issue_3849.rs
similarity index 100%
rename from src/tools/clippy/tests/ui/author/issue_3849.rs
rename to src/tools/clippy/tests/ui-internal/author/issue_3849.rs
diff --git a/src/tools/clippy/tests/ui/author/issue_3849.stdout b/src/tools/clippy/tests/ui-internal/author/issue_3849.stdout
similarity index 100%
rename from src/tools/clippy/tests/ui/author/issue_3849.stdout
rename to src/tools/clippy/tests/ui-internal/author/issue_3849.stdout
diff --git a/src/tools/clippy/tests/ui/author/loop.rs b/src/tools/clippy/tests/ui-internal/author/loop.rs
similarity index 100%
rename from src/tools/clippy/tests/ui/author/loop.rs
rename to src/tools/clippy/tests/ui-internal/author/loop.rs
diff --git a/src/tools/clippy/tests/ui/author/loop.stdout b/src/tools/clippy/tests/ui-internal/author/loop.stdout
similarity index 100%
rename from src/tools/clippy/tests/ui/author/loop.stdout
rename to src/tools/clippy/tests/ui-internal/author/loop.stdout
diff --git a/src/tools/clippy/tests/ui/author/macro_in_closure.rs b/src/tools/clippy/tests/ui-internal/author/macro_in_closure.rs
similarity index 100%
rename from src/tools/clippy/tests/ui/author/macro_in_closure.rs
rename to src/tools/clippy/tests/ui-internal/author/macro_in_closure.rs
diff --git a/src/tools/clippy/tests/ui/author/macro_in_closure.stdout b/src/tools/clippy/tests/ui-internal/author/macro_in_closure.stdout
similarity index 100%
rename from src/tools/clippy/tests/ui/author/macro_in_closure.stdout
rename to src/tools/clippy/tests/ui-internal/author/macro_in_closure.stdout
diff --git a/src/tools/clippy/tests/ui/author/macro_in_loop.rs b/src/tools/clippy/tests/ui-internal/author/macro_in_loop.rs
similarity index 100%
rename from src/tools/clippy/tests/ui/author/macro_in_loop.rs
rename to src/tools/clippy/tests/ui-internal/author/macro_in_loop.rs
diff --git a/src/tools/clippy/tests/ui/author/macro_in_loop.stdout b/src/tools/clippy/tests/ui-internal/author/macro_in_loop.stdout
similarity index 100%
rename from src/tools/clippy/tests/ui/author/macro_in_loop.stdout
rename to src/tools/clippy/tests/ui-internal/author/macro_in_loop.stdout
diff --git a/src/tools/clippy/tests/ui/author/matches.rs b/src/tools/clippy/tests/ui-internal/author/matches.rs
similarity index 100%
rename from src/tools/clippy/tests/ui/author/matches.rs
rename to src/tools/clippy/tests/ui-internal/author/matches.rs
diff --git a/src/tools/clippy/tests/ui/author/matches.stdout b/src/tools/clippy/tests/ui-internal/author/matches.stdout
similarity index 100%
rename from src/tools/clippy/tests/ui/author/matches.stdout
rename to src/tools/clippy/tests/ui-internal/author/matches.stdout
diff --git a/src/tools/clippy/tests/ui/author/repeat.rs b/src/tools/clippy/tests/ui-internal/author/repeat.rs
similarity index 100%
rename from src/tools/clippy/tests/ui/author/repeat.rs
rename to src/tools/clippy/tests/ui-internal/author/repeat.rs
diff --git a/src/tools/clippy/tests/ui/author/repeat.stdout b/src/tools/clippy/tests/ui-internal/author/repeat.stdout
similarity index 100%
rename from src/tools/clippy/tests/ui/author/repeat.stdout
rename to src/tools/clippy/tests/ui-internal/author/repeat.stdout
diff --git a/src/tools/clippy/tests/ui/author/struct.rs b/src/tools/clippy/tests/ui-internal/author/struct.rs
similarity index 100%
rename from src/tools/clippy/tests/ui/author/struct.rs
rename to src/tools/clippy/tests/ui-internal/author/struct.rs
diff --git a/src/tools/clippy/tests/ui/author/struct.stdout b/src/tools/clippy/tests/ui-internal/author/struct.stdout
similarity index 100%
rename from src/tools/clippy/tests/ui/author/struct.stdout
rename to src/tools/clippy/tests/ui-internal/author/struct.stdout
diff --git a/src/tools/clippy/tests/ui/cast.rs b/src/tools/clippy/tests/ui/cast.rs
index 146b04a..0de53a7 100644
--- a/src/tools/clippy/tests/ui/cast.rs
+++ b/src/tools/clippy/tests/ui/cast.rs
@@ -1,7 +1,6 @@
 //@no-rustfix
 
 #![feature(repr128)]
-#![feature(isqrt)]
 #![allow(incomplete_features)]
 #![warn(
     clippy::cast_precision_loss,
diff --git a/src/tools/clippy/tests/ui/cast.stderr b/src/tools/clippy/tests/ui/cast.stderr
index 7824bdf..452482f 100644
--- a/src/tools/clippy/tests/ui/cast.stderr
+++ b/src/tools/clippy/tests/ui/cast.stderr
@@ -1,5 +1,5 @@
 error: casting `i32` to `f32` causes a loss of precision (`i32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide)
-  --> tests/ui/cast.rs:26:5
+  --> tests/ui/cast.rs:25:5
    |
 LL |     x0 as f32;
    |     ^^^^^^^^^
@@ -8,37 +8,37 @@
    = help: to override `-D warnings` add `#[allow(clippy::cast_precision_loss)]`
 
 error: casting `i64` to `f32` causes a loss of precision (`i64` is 64 bits wide, but `f32`'s mantissa is only 23 bits wide)
-  --> tests/ui/cast.rs:30:5
+  --> tests/ui/cast.rs:29:5
    |
 LL |     x1 as f32;
    |     ^^^^^^^^^
 
 error: casting `i64` to `f64` causes a loss of precision (`i64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)
-  --> tests/ui/cast.rs:32:5
+  --> tests/ui/cast.rs:31:5
    |
 LL |     x1 as f64;
    |     ^^^^^^^^^
 
 error: casting `u32` to `f32` causes a loss of precision (`u32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide)
-  --> tests/ui/cast.rs:35:5
+  --> tests/ui/cast.rs:34:5
    |
 LL |     x2 as f32;
    |     ^^^^^^^^^
 
 error: casting `u64` to `f32` causes a loss of precision (`u64` is 64 bits wide, but `f32`'s mantissa is only 23 bits wide)
-  --> tests/ui/cast.rs:38:5
+  --> tests/ui/cast.rs:37:5
    |
 LL |     x3 as f32;
    |     ^^^^^^^^^
 
 error: casting `u64` to `f64` causes a loss of precision (`u64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)
-  --> tests/ui/cast.rs:40:5
+  --> tests/ui/cast.rs:39:5
    |
 LL |     x3 as f64;
    |     ^^^^^^^^^
 
 error: casting `f32` to `i32` may truncate the value
-  --> tests/ui/cast.rs:43:5
+  --> tests/ui/cast.rs:42:5
    |
 LL |     1f32 as i32;
    |     ^^^^^^^^^^^
@@ -48,7 +48,7 @@
    = help: to override `-D warnings` add `#[allow(clippy::cast_possible_truncation)]`
 
 error: casting `f32` to `u32` may truncate the value
-  --> tests/ui/cast.rs:45:5
+  --> tests/ui/cast.rs:44:5
    |
 LL |     1f32 as u32;
    |     ^^^^^^^^^^^
@@ -56,7 +56,7 @@
    = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 
 error: casting `f32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:45:5
+  --> tests/ui/cast.rs:44:5
    |
 LL |     1f32 as u32;
    |     ^^^^^^^^^^^
@@ -65,7 +65,7 @@
    = help: to override `-D warnings` add `#[allow(clippy::cast_sign_loss)]`
 
 error: casting `f64` to `f32` may truncate the value
-  --> tests/ui/cast.rs:49:5
+  --> tests/ui/cast.rs:48:5
    |
 LL |     1f64 as f32;
    |     ^^^^^^^^^^^
@@ -73,7 +73,7 @@
    = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 
 error: casting `i32` to `i8` may truncate the value
-  --> tests/ui/cast.rs:51:5
+  --> tests/ui/cast.rs:50:5
    |
 LL |     1i32 as i8;
    |     ^^^^^^^^^^
@@ -85,7 +85,7 @@
    |     ~~~~~~~~~~~~~~~~~~
 
 error: casting `i32` to `u8` may truncate the value
-  --> tests/ui/cast.rs:53:5
+  --> tests/ui/cast.rs:52:5
    |
 LL |     1i32 as u8;
    |     ^^^^^^^^^^
@@ -97,7 +97,7 @@
    |     ~~~~~~~~~~~~~~~~~~
 
 error: casting `f64` to `isize` may truncate the value
-  --> tests/ui/cast.rs:55:5
+  --> tests/ui/cast.rs:54:5
    |
 LL |     1f64 as isize;
    |     ^^^^^^^^^^^^^
@@ -105,7 +105,7 @@
    = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 
 error: casting `f64` to `usize` may truncate the value
-  --> tests/ui/cast.rs:57:5
+  --> tests/ui/cast.rs:56:5
    |
 LL |     1f64 as usize;
    |     ^^^^^^^^^^^^^
@@ -113,13 +113,13 @@
    = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 
 error: casting `f64` to `usize` may lose the sign of the value
-  --> tests/ui/cast.rs:57:5
+  --> tests/ui/cast.rs:56:5
    |
 LL |     1f64 as usize;
    |     ^^^^^^^^^^^^^
 
 error: casting `u32` to `u16` may truncate the value
-  --> tests/ui/cast.rs:60:5
+  --> tests/ui/cast.rs:59:5
    |
 LL |     1f32 as u32 as u16;
    |     ^^^^^^^^^^^^^^^^^^
@@ -131,7 +131,7 @@
    |     ~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `f32` to `u32` may truncate the value
-  --> tests/ui/cast.rs:60:5
+  --> tests/ui/cast.rs:59:5
    |
 LL |     1f32 as u32 as u16;
    |     ^^^^^^^^^^^
@@ -139,13 +139,13 @@
    = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 
 error: casting `f32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:60:5
+  --> tests/ui/cast.rs:59:5
    |
 LL |     1f32 as u32 as u16;
    |     ^^^^^^^^^^^
 
 error: casting `i32` to `i8` may truncate the value
-  --> tests/ui/cast.rs:65:22
+  --> tests/ui/cast.rs:64:22
    |
 LL |         let _x: i8 = 1i32 as _;
    |                      ^^^^^^^^^
@@ -157,7 +157,7 @@
    |                      ~~~~~~~~~~~~~~~
 
 error: casting `f32` to `i32` may truncate the value
-  --> tests/ui/cast.rs:67:9
+  --> tests/ui/cast.rs:66:9
    |
 LL |         1f32 as i32;
    |         ^^^^^^^^^^^
@@ -165,7 +165,7 @@
    = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 
 error: casting `f64` to `i32` may truncate the value
-  --> tests/ui/cast.rs:69:9
+  --> tests/ui/cast.rs:68:9
    |
 LL |         1f64 as i32;
    |         ^^^^^^^^^^^
@@ -173,7 +173,7 @@
    = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 
 error: casting `f32` to `u8` may truncate the value
-  --> tests/ui/cast.rs:71:9
+  --> tests/ui/cast.rs:70:9
    |
 LL |         1f32 as u8;
    |         ^^^^^^^^^^
@@ -181,13 +181,13 @@
    = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 
 error: casting `f32` to `u8` may lose the sign of the value
-  --> tests/ui/cast.rs:71:9
+  --> tests/ui/cast.rs:70:9
    |
 LL |         1f32 as u8;
    |         ^^^^^^^^^^
 
 error: casting `u8` to `i8` may wrap around the value
-  --> tests/ui/cast.rs:76:5
+  --> tests/ui/cast.rs:75:5
    |
 LL |     1u8 as i8;
    |     ^^^^^^^^^
@@ -196,31 +196,31 @@
    = help: to override `-D warnings` add `#[allow(clippy::cast_possible_wrap)]`
 
 error: casting `u16` to `i16` may wrap around the value
-  --> tests/ui/cast.rs:79:5
+  --> tests/ui/cast.rs:78:5
    |
 LL |     1u16 as i16;
    |     ^^^^^^^^^^^
 
 error: casting `u32` to `i32` may wrap around the value
-  --> tests/ui/cast.rs:81:5
+  --> tests/ui/cast.rs:80:5
    |
 LL |     1u32 as i32;
    |     ^^^^^^^^^^^
 
 error: casting `u64` to `i64` may wrap around the value
-  --> tests/ui/cast.rs:83:5
+  --> tests/ui/cast.rs:82:5
    |
 LL |     1u64 as i64;
    |     ^^^^^^^^^^^
 
 error: casting `usize` to `isize` may wrap around the value
-  --> tests/ui/cast.rs:85:5
+  --> tests/ui/cast.rs:84:5
    |
 LL |     1usize as isize;
    |     ^^^^^^^^^^^^^^^
 
 error: casting `usize` to `i8` may truncate the value
-  --> tests/ui/cast.rs:88:5
+  --> tests/ui/cast.rs:87:5
    |
 LL |     1usize as i8;
    |     ^^^^^^^^^^^^
@@ -232,7 +232,7 @@
    |     ~~~~~~~~~~~~~~~~~~~~
 
 error: casting `usize` to `i16` may truncate the value
-  --> tests/ui/cast.rs:91:5
+  --> tests/ui/cast.rs:90:5
    |
 LL |     1usize as i16;
    |     ^^^^^^^^^^^^^
@@ -244,7 +244,7 @@
    |     ~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `usize` to `i16` may wrap around the value on targets with 16-bit wide pointers
-  --> tests/ui/cast.rs:91:5
+  --> tests/ui/cast.rs:90:5
    |
 LL |     1usize as i16;
    |     ^^^^^^^^^^^^^
@@ -253,7 +253,7 @@
    = note: for more information see https://doc.rust-lang.org/reference/types/numeric.html#machine-dependent-integer-types
 
 error: casting `usize` to `i32` may truncate the value on targets with 64-bit wide pointers
-  --> tests/ui/cast.rs:96:5
+  --> tests/ui/cast.rs:95:5
    |
 LL |     1usize as i32;
    |     ^^^^^^^^^^^^^
@@ -265,19 +265,19 @@
    |     ~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `usize` to `i32` may wrap around the value on targets with 32-bit wide pointers
-  --> tests/ui/cast.rs:96:5
+  --> tests/ui/cast.rs:95:5
    |
 LL |     1usize as i32;
    |     ^^^^^^^^^^^^^
 
 error: casting `usize` to `i64` may wrap around the value on targets with 64-bit wide pointers
-  --> tests/ui/cast.rs:100:5
+  --> tests/ui/cast.rs:99:5
    |
 LL |     1usize as i64;
    |     ^^^^^^^^^^^^^
 
 error: casting `u16` to `isize` may wrap around the value on targets with 16-bit wide pointers
-  --> tests/ui/cast.rs:105:5
+  --> tests/ui/cast.rs:104:5
    |
 LL |     1u16 as isize;
    |     ^^^^^^^^^^^^^
@@ -286,13 +286,13 @@
    = note: for more information see https://doc.rust-lang.org/reference/types/numeric.html#machine-dependent-integer-types
 
 error: casting `u32` to `isize` may wrap around the value on targets with 32-bit wide pointers
-  --> tests/ui/cast.rs:109:5
+  --> tests/ui/cast.rs:108:5
    |
 LL |     1u32 as isize;
    |     ^^^^^^^^^^^^^
 
 error: casting `u64` to `isize` may truncate the value on targets with 32-bit wide pointers
-  --> tests/ui/cast.rs:112:5
+  --> tests/ui/cast.rs:111:5
    |
 LL |     1u64 as isize;
    |     ^^^^^^^^^^^^^
@@ -304,55 +304,55 @@
    |     ~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `u64` to `isize` may wrap around the value on targets with 64-bit wide pointers
-  --> tests/ui/cast.rs:112:5
+  --> tests/ui/cast.rs:111:5
    |
 LL |     1u64 as isize;
    |     ^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:117:5
+  --> tests/ui/cast.rs:116:5
    |
 LL |     -1i32 as u32;
    |     ^^^^^^^^^^^^
 
 error: casting `isize` to `usize` may lose the sign of the value
-  --> tests/ui/cast.rs:120:5
+  --> tests/ui/cast.rs:119:5
    |
 LL |     -1isize as usize;
    |     ^^^^^^^^^^^^^^^^
 
 error: casting `i8` to `u8` may lose the sign of the value
-  --> tests/ui/cast.rs:131:5
+  --> tests/ui/cast.rs:130:5
    |
 LL |     (i8::MIN).abs() as u8;
    |     ^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i64` to `u64` may lose the sign of the value
-  --> tests/ui/cast.rs:135:5
+  --> tests/ui/cast.rs:134:5
    |
 LL |     (-1i64).abs() as u64;
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: casting `isize` to `usize` may lose the sign of the value
-  --> tests/ui/cast.rs:136:5
+  --> tests/ui/cast.rs:135:5
    |
 LL |     (-1isize).abs() as usize;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i64` to `u64` may lose the sign of the value
-  --> tests/ui/cast.rs:143:5
+  --> tests/ui/cast.rs:142:5
    |
 LL |     (unsafe { (-1i64).checked_abs().unwrap_unchecked() }) as u64;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i64` to `u64` may lose the sign of the value
-  --> tests/ui/cast.rs:158:5
+  --> tests/ui/cast.rs:157:5
    |
 LL |     (unsafe { (-1i64).checked_isqrt().unwrap_unchecked() }) as u64;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i64` to `i8` may truncate the value
-  --> tests/ui/cast.rs:209:5
+  --> tests/ui/cast.rs:208:5
    |
 LL |     (-99999999999i64).min(1) as i8;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -364,7 +364,7 @@
    |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `u64` to `u8` may truncate the value
-  --> tests/ui/cast.rs:223:5
+  --> tests/ui/cast.rs:222:5
    |
 LL |     999999u64.clamp(0, 256) as u8;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -376,7 +376,7 @@
    |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `main::E2` to `u8` may truncate the value
-  --> tests/ui/cast.rs:246:21
+  --> tests/ui/cast.rs:245:21
    |
 LL |             let _ = self as u8;
    |                     ^^^^^^^^^^
@@ -388,7 +388,7 @@
    |                     ~~~~~~~~~~~~~~~~~~
 
 error: casting `main::E2::B` to `u8` will truncate the value
-  --> tests/ui/cast.rs:248:21
+  --> tests/ui/cast.rs:247:21
    |
 LL |             let _ = Self::B as u8;
    |                     ^^^^^^^^^^^^^
@@ -397,7 +397,7 @@
    = help: to override `-D warnings` add `#[allow(clippy::cast_enum_truncation)]`
 
 error: casting `main::E5` to `i8` may truncate the value
-  --> tests/ui/cast.rs:290:21
+  --> tests/ui/cast.rs:289:21
    |
 LL |             let _ = self as i8;
    |                     ^^^^^^^^^^
@@ -409,13 +409,13 @@
    |                     ~~~~~~~~~~~~~~~~~~
 
 error: casting `main::E5::A` to `i8` will truncate the value
-  --> tests/ui/cast.rs:292:21
+  --> tests/ui/cast.rs:291:21
    |
 LL |             let _ = Self::A as i8;
    |                     ^^^^^^^^^^^^^
 
 error: casting `main::E6` to `i16` may truncate the value
-  --> tests/ui/cast.rs:309:21
+  --> tests/ui/cast.rs:308:21
    |
 LL |             let _ = self as i16;
    |                     ^^^^^^^^^^^
@@ -427,7 +427,7 @@
    |                     ~~~~~~~~~~~~~~~~~~~
 
 error: casting `main::E7` to `usize` may truncate the value on targets with 32-bit wide pointers
-  --> tests/ui/cast.rs:328:21
+  --> tests/ui/cast.rs:327:21
    |
 LL |             let _ = self as usize;
    |                     ^^^^^^^^^^^^^
@@ -439,7 +439,7 @@
    |                     ~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `main::E10` to `u16` may truncate the value
-  --> tests/ui/cast.rs:375:21
+  --> tests/ui/cast.rs:374:21
    |
 LL |             let _ = self as u16;
    |                     ^^^^^^^^^^^
@@ -451,7 +451,7 @@
    |                     ~~~~~~~~~~~~~~~~~~~
 
 error: casting `u32` to `u8` may truncate the value
-  --> tests/ui/cast.rs:386:13
+  --> tests/ui/cast.rs:385:13
    |
 LL |     let c = (q >> 16) as u8;
    |             ^^^^^^^^^^^^^^^
@@ -463,7 +463,7 @@
    |             ~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `u32` to `u8` may truncate the value
-  --> tests/ui/cast.rs:390:13
+  --> tests/ui/cast.rs:389:13
    |
 LL |     let c = (q / 1000) as u8;
    |             ^^^^^^^^^^^^^^^^
@@ -475,85 +475,85 @@
    |             ~~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:402:9
+  --> tests/ui/cast.rs:401:9
    |
 LL |         (x * x) as u32;
    |         ^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:407:32
+  --> tests/ui/cast.rs:406:32
    |
 LL |     let _a = |x: i32| -> u32 { (x * x * x * x) as u32 };
    |                                ^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:409:5
+  --> tests/ui/cast.rs:408:5
    |
 LL |     (2_i32).checked_pow(3).unwrap() as u32;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:410:5
+  --> tests/ui/cast.rs:409:5
    |
 LL |     (-2_i32).pow(3) as u32;
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:415:5
+  --> tests/ui/cast.rs:414:5
    |
 LL |     (-5_i32 % 2) as u32;
    |     ^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:417:5
+  --> tests/ui/cast.rs:416:5
    |
 LL |     (-5_i32 % -2) as u32;
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:420:5
+  --> tests/ui/cast.rs:419:5
    |
 LL |     (-2_i32 >> 1) as u32;
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:424:5
+  --> tests/ui/cast.rs:423:5
    |
 LL |     (x * x) as u32;
    |     ^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:425:5
+  --> tests/ui/cast.rs:424:5
    |
 LL |     (x * x * x) as u32;
    |     ^^^^^^^^^^^^^^^^^^
 
 error: casting `i16` to `u16` may lose the sign of the value
-  --> tests/ui/cast.rs:429:5
+  --> tests/ui/cast.rs:428:5
    |
 LL |     (y * y * y * y * -2) as u16;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i16` to `u16` may lose the sign of the value
-  --> tests/ui/cast.rs:431:5
+  --> tests/ui/cast.rs:430:5
    |
 LL |     (y * y * y / y * 2) as u16;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i16` to `u16` may lose the sign of the value
-  --> tests/ui/cast.rs:432:5
+  --> tests/ui/cast.rs:431:5
    |
 LL |     (y * y / y * 2) as u16;
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i16` to `u16` may lose the sign of the value
-  --> tests/ui/cast.rs:434:5
+  --> tests/ui/cast.rs:433:5
    |
 LL |     (y / y * y * -2) as u16;
    |     ^^^^^^^^^^^^^^^^^^^^^^^
 
 error: equal expressions as operands to `/`
-  --> tests/ui/cast.rs:434:6
+  --> tests/ui/cast.rs:433:6
    |
 LL |     (y / y * y * -2) as u16;
    |      ^^^^^
@@ -561,97 +561,97 @@
    = note: `#[deny(clippy::eq_op)]` on by default
 
 error: casting `i16` to `u16` may lose the sign of the value
-  --> tests/ui/cast.rs:437:5
+  --> tests/ui/cast.rs:436:5
    |
 LL |     (y + y + y + -2) as u16;
    |     ^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i16` to `u16` may lose the sign of the value
-  --> tests/ui/cast.rs:439:5
+  --> tests/ui/cast.rs:438:5
    |
 LL |     (y + y + y + 2) as u16;
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i16` to `u16` may lose the sign of the value
-  --> tests/ui/cast.rs:443:5
+  --> tests/ui/cast.rs:442:5
    |
 LL |     (z + -2) as u16;
    |     ^^^^^^^^^^^^^^^
 
 error: casting `i16` to `u16` may lose the sign of the value
-  --> tests/ui/cast.rs:445:5
+  --> tests/ui/cast.rs:444:5
    |
 LL |     (z + z + 2) as u16;
    |     ^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:448:9
+  --> tests/ui/cast.rs:447:9
    |
 LL |         (a * a * b * b * c * c) as u32;
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:449:9
+  --> tests/ui/cast.rs:448:9
    |
 LL |         (a * b * c) as u32;
    |         ^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:451:9
+  --> tests/ui/cast.rs:450:9
    |
 LL |         (a * -b * c) as u32;
    |         ^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:453:9
+  --> tests/ui/cast.rs:452:9
    |
 LL |         (a * b * c * c) as u32;
    |         ^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:454:9
+  --> tests/ui/cast.rs:453:9
    |
 LL |         (a * -2) as u32;
    |         ^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:456:9
+  --> tests/ui/cast.rs:455:9
    |
 LL |         (a * b * c * -2) as u32;
    |         ^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:458:9
+  --> tests/ui/cast.rs:457:9
    |
 LL |         (a / b) as u32;
    |         ^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:459:9
+  --> tests/ui/cast.rs:458:9
    |
 LL |         (a / b * c) as u32;
    |         ^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:461:9
+  --> tests/ui/cast.rs:460:9
    |
 LL |         (a / b + b * c) as u32;
    |         ^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:463:9
+  --> tests/ui/cast.rs:462:9
    |
 LL |         a.saturating_pow(3) as u32;
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:465:9
+  --> tests/ui/cast.rs:464:9
    |
 LL |         (a.abs() * b.pow(2) / c.abs()) as u32
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:473:21
+  --> tests/ui/cast.rs:472:21
    |
 LL |             let _ = i32::MIN as u32; // cast_sign_loss
    |                     ^^^^^^^^^^^^^^^
@@ -662,7 +662,7 @@
    = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: casting `u32` to `u8` may truncate the value
-  --> tests/ui/cast.rs:474:21
+  --> tests/ui/cast.rs:473:21
    |
 LL |             let _ = u32::MAX as u8; // cast_possible_truncation
    |                     ^^^^^^^^^^^^^^
@@ -678,7 +678,7 @@
    |                     ~~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `f64` to `f32` may truncate the value
-  --> tests/ui/cast.rs:475:21
+  --> tests/ui/cast.rs:474:21
    |
 LL |             let _ = std::f64::consts::PI as f32; // cast_possible_truncation
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -690,7 +690,7 @@
    = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: casting `i64` to `usize` may truncate the value on targets with 32-bit wide pointers
-  --> tests/ui/cast.rs:484:5
+  --> tests/ui/cast.rs:483:5
    |
 LL |     bar.unwrap().unwrap() as usize
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -702,13 +702,13 @@
    |
 
 error: casting `i64` to `usize` may lose the sign of the value
-  --> tests/ui/cast.rs:484:5
+  --> tests/ui/cast.rs:483:5
    |
 LL |     bar.unwrap().unwrap() as usize
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `u64` to `u8` may truncate the value
-  --> tests/ui/cast.rs:499:5
+  --> tests/ui/cast.rs:498:5
    |
 LL |     (256 & 999999u64) as u8;
    |     ^^^^^^^^^^^^^^^^^^^^^^^
@@ -720,7 +720,7 @@
    |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `u64` to `u8` may truncate the value
-  --> tests/ui/cast.rs:501:5
+  --> tests/ui/cast.rs:500:5
    |
 LL |     (255 % 999999u64) as u8;
    |     ^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/no_lints.rs b/src/tools/clippy/tests/ui/no_lints.rs
new file mode 100644
index 0000000..a8467bb
--- /dev/null
+++ b/src/tools/clippy/tests/ui/no_lints.rs
@@ -0,0 +1,3 @@
+#![deny(clippy::all)]
+
+fn main() {}
\ No newline at end of file
diff --git a/src/tools/clippy/tests/ui/rename.fixed b/src/tools/clippy/tests/ui/rename.fixed
index b810fd8..0d6e07a 100644
--- a/src/tools/clippy/tests/ui/rename.fixed
+++ b/src/tools/clippy/tests/ui/rename.fixed
@@ -54,7 +54,7 @@
 #![allow(enum_intrinsics_non_enums)]
 #![allow(non_fmt_panics)]
 #![allow(named_arguments_used_positionally)]
-#![allow(temporary_cstring_as_ptr)]
+#![allow(dangling_pointers_from_temporaries)]
 #![allow(undropped_manually_drops)]
 #![allow(unknown_lints)]
 #![allow(unused_labels)]
@@ -120,7 +120,7 @@
 #![warn(unexpected_cfgs)] //~ ERROR: lint `clippy::mismatched_target_os`
 #![warn(non_fmt_panics)] //~ ERROR: lint `clippy::panic_params`
 #![warn(named_arguments_used_positionally)] //~ ERROR: lint `clippy::positional_named_format_parameters`
-#![warn(temporary_cstring_as_ptr)] //~ ERROR: lint `clippy::temporary_cstring_as_ptr`
+#![warn(dangling_pointers_from_temporaries)] //~ ERROR: lint `clippy::temporary_cstring_as_ptr`
 #![warn(undropped_manually_drops)] //~ ERROR: lint `clippy::undropped_manually_drops`
 #![warn(unknown_lints)] //~ ERROR: lint `clippy::unknown_clippy_lints`
 #![warn(unused_labels)] //~ ERROR: lint `clippy::unused_label`
diff --git a/src/tools/clippy/tests/ui/rename.stderr b/src/tools/clippy/tests/ui/rename.stderr
index 46d9f0f..b906079 100644
--- a/src/tools/clippy/tests/ui/rename.stderr
+++ b/src/tools/clippy/tests/ui/rename.stderr
@@ -1,11 +1,17 @@
+error: lint `temporary_cstring_as_ptr` has been renamed to `dangling_pointers_from_temporaries`
+  --> tests/ui/rename.rs:57:10
+   |
+LL | #![allow(temporary_cstring_as_ptr)]
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `dangling_pointers_from_temporaries`
+   |
+   = note: `-D renamed-and-removed-lints` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(renamed_and_removed_lints)]`
+
 error: lint `clippy::almost_complete_letter_range` has been renamed to `clippy::almost_complete_range`
   --> tests/ui/rename.rs:63:9
    |
 LL | #![warn(clippy::almost_complete_letter_range)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::almost_complete_range`
-   |
-   = note: `-D renamed-and-removed-lints` implied by `-D warnings`
-   = help: to override `-D warnings` add `#[allow(renamed_and_removed_lints)]`
 
 error: lint `clippy::blacklisted_name` has been renamed to `clippy::disallowed_names`
   --> tests/ui/rename.rs:64:9
@@ -361,11 +367,11 @@
 LL | #![warn(clippy::positional_named_format_parameters)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `named_arguments_used_positionally`
 
-error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr`
+error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `dangling_pointers_from_temporaries`
   --> tests/ui/rename.rs:123:9
    |
 LL | #![warn(clippy::temporary_cstring_as_ptr)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `dangling_pointers_from_temporaries`
 
 error: lint `clippy::undropped_manually_drops` has been renamed to `undropped_manually_drops`
   --> tests/ui/rename.rs:124:9
@@ -397,5 +403,5 @@
 LL | #![warn(clippy::reverse_range_loop)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::reversed_empty_ranges`
 
-error: aborting due to 66 previous errors
+error: aborting due to 67 previous errors
 
diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs
index ff05994..69ac464 100644
--- a/src/tools/compiletest/src/common.rs
+++ b/src/tools/compiletest/src/common.rs
@@ -376,6 +376,7 @@
     pub only_modified: bool,
 
     pub target_cfgs: OnceLock<TargetCfgs>,
+    pub builtin_cfg_names: OnceLock<HashSet<String>>,
 
     pub nocapture: bool,
 
@@ -387,6 +388,9 @@
     /// True if the profiler runtime is enabled for this target.
     /// Used by the "needs-profiler-runtime" directive in test files.
     pub profiler_runtime: bool,
+
+    /// Command for visual diff display, e.g. `diff-tool --color=always`.
+    pub diff_command: Option<String>,
 }
 
 impl Config {
@@ -440,6 +444,11 @@
         self.target_cfg().panic == PanicStrategy::Unwind
     }
 
+    /// Get the list of builtin, 'well known' cfg names
+    pub fn builtin_cfg_names(&self) -> &HashSet<String> {
+        self.builtin_cfg_names.get_or_init(|| builtin_cfg_names(self))
+    }
+
     pub fn has_threads(&self) -> bool {
         // Wasm targets don't have threads unless `-threads` is in the target
         // name, such as `wasm32-wasip1-threads`.
@@ -651,6 +660,18 @@
     Big,
 }
 
+fn builtin_cfg_names(config: &Config) -> HashSet<String> {
+    rustc_output(
+        config,
+        &["--print=check-cfg", "-Zunstable-options", "--check-cfg=cfg()"],
+        Default::default(),
+    )
+    .lines()
+    .map(|l| if let Some((name, _)) = l.split_once('=') { name.to_string() } else { l.to_string() })
+    .chain(std::iter::once(String::from("test")))
+    .collect()
+}
+
 fn rustc_output(config: &Config, args: &[&str], envs: HashMap<String, String>) -> String {
     let mut command = Command::new(&config.rustc_path);
     add_dylib_path(&mut command, iter::once(&config.compile_lib_path));
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
index 099e620..d75cdef 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -57,7 +57,7 @@
             &mut poisoned,
             testfile,
             rdr,
-            &mut |DirectiveLine { directive: ln, .. }| {
+            &mut |DirectiveLine { raw_directive: ln, .. }| {
                 parse_and_update_aux(config, ln, &mut props.aux);
                 config.parse_and_update_revisions(testfile, ln, &mut props.revisions);
             },
@@ -344,8 +344,8 @@
                 &mut poisoned,
                 testfile,
                 file,
-                &mut |DirectiveLine { header_revision, directive: ln, .. }| {
-                    if header_revision.is_some() && header_revision != test_revision {
+                &mut |directive @ DirectiveLine { raw_directive: ln, .. }| {
+                    if !directive.applies_to_test_revision(test_revision) {
                         return;
                     }
 
@@ -678,28 +678,35 @@
     }
 }
 
-/// Extract an `(Option<line_revision>, directive)` directive from a line if comment is present.
-///
-/// See [`DirectiveLine`] for a diagram.
-pub fn line_directive<'line>(
+/// If the given line begins with the appropriate comment prefix for a directive,
+/// returns a struct containing various parts of the directive.
+fn line_directive<'line>(
+    line_number: usize,
     comment: &str,
     original_line: &'line str,
-) -> Option<(Option<&'line str>, &'line str)> {
+) -> Option<DirectiveLine<'line>> {
     // Ignore lines that don't start with the comment prefix.
     let after_comment = original_line.trim_start().strip_prefix(comment)?.trim_start();
 
+    let revision;
+    let raw_directive;
+
     if let Some(after_open_bracket) = after_comment.strip_prefix('[') {
         // A comment like `//@[foo]` only applies to revision `foo`.
-        let Some((line_revision, directive)) = after_open_bracket.split_once(']') else {
+        let Some((line_revision, after_close_bracket)) = after_open_bracket.split_once(']') else {
             panic!(
                 "malformed condition directive: expected `{comment}[foo]`, found `{original_line}`"
             )
         };
 
-        Some((Some(line_revision), directive.trim_start()))
+        revision = Some(line_revision);
+        raw_directive = after_close_bracket.trim_start();
     } else {
-        Some((None, after_comment))
-    }
+        revision = None;
+        raw_directive = after_comment;
+    };
+
+    Some(DirectiveLine { line_number, revision, raw_directive })
 }
 
 // To prevent duplicating the list of commmands between `compiletest`,`htmldocck` and `jsondocck`,
@@ -730,28 +737,37 @@
 const KNOWN_JSONDOCCK_DIRECTIVE_NAMES: &[&str] =
     &["count", "!count", "has", "!has", "is", "!is", "ismany", "!ismany", "set", "!set"];
 
-/// The broken-down contents of a line containing a test header directive,
+/// The (partly) broken-down contents of a line containing a test directive,
 /// which [`iter_header`] passes to its callback function.
 ///
 /// For example:
 ///
 /// ```text
 /// //@ compile-flags: -O
-///     ^^^^^^^^^^^^^^^^^ directive
+///     ^^^^^^^^^^^^^^^^^ raw_directive
 ///
 /// //@ [foo] compile-flags: -O
-///      ^^^                    header_revision
-///           ^^^^^^^^^^^^^^^^^ directive
+///      ^^^                    revision
+///           ^^^^^^^^^^^^^^^^^ raw_directive
 /// ```
 struct DirectiveLine<'ln> {
     line_number: usize,
-    /// Some header directives start with a revision name in square brackets
+    /// Some test directives start with a revision name in square brackets
     /// (e.g. `[foo]`), and only apply to that revision of the test.
     /// If present, this field contains the revision name (e.g. `foo`).
-    header_revision: Option<&'ln str>,
-    /// The main part of the header directive, after removing the comment prefix
+    revision: Option<&'ln str>,
+    /// The main part of the directive, after removing the comment prefix
     /// and the optional revision specifier.
-    directive: &'ln str,
+    ///
+    /// This is "raw" because the directive's name and colon-separated value
+    /// (if present) have not yet been extracted or checked.
+    raw_directive: &'ln str,
+}
+
+impl<'ln> DirectiveLine<'ln> {
+    fn applies_to_test_revision(&self, test_revision: Option<&str>) -> bool {
+        self.revision.is_none() || self.revision == test_revision
+    }
 }
 
 pub(crate) struct CheckDirectiveResult<'ln> {
@@ -819,8 +835,8 @@
             "ignore-cross-compile",
         ];
         // Process the extra implied directives, with a dummy line number of 0.
-        for directive in extra_directives {
-            it(DirectiveLine { line_number: 0, header_revision: None, directive });
+        for raw_directive in extra_directives {
+            it(DirectiveLine { line_number: 0, revision: None, raw_directive });
         }
     }
 
@@ -847,24 +863,21 @@
             return;
         }
 
-        let Some((header_revision, non_revisioned_directive_line)) = line_directive(comment, ln)
-        else {
+        let Some(directive_line) = line_directive(line_number, comment, ln) else {
             continue;
         };
 
         // Perform unknown directive check on Rust files.
         if testfile.extension().map(|e| e == "rs").unwrap_or(false) {
-            let directive_ln = non_revisioned_directive_line.trim();
-
             let CheckDirectiveResult { is_known_directive, trailing_directive } =
-                check_directive(directive_ln, mode, ln);
+                check_directive(directive_line.raw_directive, mode, ln);
 
             if !is_known_directive {
                 *poisoned = true;
 
                 eprintln!(
                     "error: detected unknown compiletest test directive `{}` in {}:{}",
-                    directive_ln,
+                    directive_line.raw_directive,
                     testfile.display(),
                     line_number,
                 );
@@ -888,11 +901,7 @@
             }
         }
 
-        it(DirectiveLine {
-            line_number,
-            header_revision,
-            directive: non_revisioned_directive_line,
-        });
+        it(directive_line);
     }
 }
 
@@ -1292,8 +1301,8 @@
         &mut local_poisoned,
         path,
         src,
-        &mut |DirectiveLine { header_revision, directive: ln, line_number }| {
-            if header_revision.is_some() && header_revision != test_revision {
+        &mut |directive @ DirectiveLine { line_number, raw_directive: ln, .. }| {
+            if !directive.applies_to_test_revision(test_revision) {
                 return;
             }
 
diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs
index 7d6ede9..490df31 100644
--- a/src/tools/compiletest/src/lib.rs
+++ b/src/tools/compiletest/src/lib.rs
@@ -175,6 +175,12 @@
             "git-merge-commit-email",
             "email address used for finding merge commits",
             "EMAIL",
+        )
+        .optopt(
+            "",
+            "compiletest-diff-tool",
+            "What custom diff tool to use for displaying compiletest tests.",
+            "COMMAND",
         );
 
     let (argv0, args_) = args.split_first().unwrap();
@@ -356,6 +362,7 @@
         force_rerun: matches.opt_present("force-rerun"),
 
         target_cfgs: OnceLock::new(),
+        builtin_cfg_names: OnceLock::new(),
 
         nocapture: matches.opt_present("nocapture"),
 
@@ -364,6 +371,7 @@
         git_merge_commit_email: matches.opt_str("git-merge-commit-email").unwrap(),
 
         profiler_runtime: matches.opt_present("profiler-runtime"),
+        diff_command: matches.opt_str("compiletest-diff-tool"),
     }
 }
 
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 36c5106..a8a71c1 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -59,7 +59,7 @@
     use std::sync::Mutex;
 
     use windows::Win32::System::Diagnostics::Debug::{
-        SEM_NOGPFAULTERRORBOX, SetErrorMode, THREAD_ERROR_MODE,
+        SEM_FAILCRITICALERRORS, SEM_NOGPFAULTERRORBOX, SetErrorMode, THREAD_ERROR_MODE,
     };
 
     static LOCK: Mutex<()> = Mutex::new(());
@@ -67,13 +67,21 @@
     // Error mode is a global variable, so lock it so only one thread will change it
     let _lock = LOCK.lock().unwrap();
 
-    // Tell Windows to not show any UI on errors (such as terminating abnormally).
-    // This is important for running tests, since some of them use abnormal
-    // termination by design. This mode is inherited by all child processes.
+    // Tell Windows to not show any UI on errors (such as terminating abnormally). This is important
+    // for running tests, since some of them use abnormal termination by design. This mode is
+    // inherited by all child processes.
+    //
+    // Note that `run-make` tests require `SEM_FAILCRITICALERRORS` in addition to suppress Windows
+    // Error Reporting (WER) error dialogues that come from "critical failures" such as missing
+    // DLLs.
+    //
+    // See <https://github.com/rust-lang/rust/issues/132092> and
+    // <https://learn.microsoft.com/en-us/windows/win32/api/errhandlingapi/nf-errhandlingapi-seterrormode?redirectedfrom=MSDN>.
     unsafe {
-        let old_mode = SetErrorMode(SEM_NOGPFAULTERRORBOX); // read inherited flags
+        // read inherited flags
+        let old_mode = SetErrorMode(SEM_NOGPFAULTERRORBOX | SEM_FAILCRITICALERRORS);
         let old_mode = THREAD_ERROR_MODE(old_mode);
-        SetErrorMode(old_mode | SEM_NOGPFAULTERRORBOX);
+        SetErrorMode(old_mode | SEM_NOGPFAULTERRORBOX | SEM_FAILCRITICALERRORS);
         let r = f();
         SetErrorMode(old_mode);
         r
@@ -478,6 +486,9 @@
                     "error: redundant cfg argument `{normalized_revision}` is already created by the revision"
                 );
             }
+            if self.config.builtin_cfg_names().contains(&normalized_revision) {
+                panic!("error: revision `{normalized_revision}` collides with a builtin cfg");
+            }
             cmd.args(cfg_arg);
         }
 
@@ -1085,6 +1096,10 @@
         self.config.target.contains("vxworks") && !self.is_vxworks_pure_static()
     }
 
+    fn has_aux_dir(&self) -> bool {
+        !self.props.aux.builds.is_empty() || !self.props.aux.crates.is_empty()
+    }
+
     fn aux_output_dir(&self) -> PathBuf {
         let aux_dir = self.aux_output_dir_name();
 
@@ -1638,7 +1653,11 @@
         }
 
         if let LinkToAux::Yes = link_to_aux {
-            rustc.arg("-L").arg(self.aux_output_dir_name());
+            // if we pass an `-L` argument to a directory that doesn't exist,
+            // macOS ld emits warnings which disrupt the .stderr files
+            if self.has_aux_dir() {
+                rustc.arg("-L").arg(self.aux_output_dir_name());
+            }
         }
 
         rustc.args(&self.props.compile_flags);
@@ -2459,7 +2478,7 @@
         }
     }
 
-    fn compare_output(&self, kind: &str, actual: &str, expected: &str) -> usize {
+    fn compare_output(&self, stream: &str, actual: &str, expected: &str) -> usize {
         let are_different = match (self.force_color_svg(), expected.find('\n'), actual.find('\n')) {
             // FIXME: We ignore the first line of SVG files
             // because the width parameter is non-deterministic.
@@ -2499,56 +2518,66 @@
             (expected, actual)
         };
 
-        if !self.config.bless {
-            if expected.is_empty() {
-                println!("normalized {}:\n{}\n", kind, actual);
-            } else {
-                println!("diff of {}:\n", kind);
-                print!("{}", write_diff(expected, actual, 3));
-            }
-        }
-
-        let mode = self.config.compare_mode.as_ref().map_or("", |m| m.to_str());
-        let output_file = self
+        // Write the actual output to a file in build/
+        let test_name = self.config.compare_mode.as_ref().map_or("", |m| m.to_str());
+        let actual_path = self
             .output_base_name()
             .with_extra_extension(self.revision.unwrap_or(""))
-            .with_extra_extension(mode)
-            .with_extra_extension(kind);
+            .with_extra_extension(test_name)
+            .with_extra_extension(stream);
 
-        let mut files = vec![output_file];
-        if self.config.bless {
+        if let Err(err) = fs::write(&actual_path, &actual) {
+            self.fatal(&format!("failed to write {stream} to `{actual_path:?}`: {err}",));
+        }
+        println!("Saved the actual {stream} to {actual_path:?}");
+
+        let expected_path =
+            expected_output_path(self.testpaths, self.revision, &self.config.compare_mode, stream);
+
+        if !self.config.bless {
+            if expected.is_empty() {
+                println!("normalized {}:\n{}\n", stream, actual);
+            } else {
+                println!("diff of {stream}:\n");
+                if let Some(diff_command) = self.config.diff_command.as_deref() {
+                    let mut args = diff_command.split_whitespace();
+                    let name = args.next().unwrap();
+                    match Command::new(name)
+                        .args(args)
+                        .args([&expected_path, &actual_path])
+                        .output()
+                    {
+                        Err(err) => {
+                            self.fatal(&format!(
+                                "failed to call custom diff command `{diff_command}`: {err}"
+                            ));
+                        }
+                        Ok(output) => {
+                            let output = String::from_utf8_lossy(&output.stdout);
+                            print!("{output}");
+                        }
+                    }
+                } else {
+                    print!("{}", write_diff(expected, actual, 3));
+                }
+            }
+        } else {
             // Delete non-revision .stderr/.stdout file if revisions are used.
             // Without this, we'd just generate the new files and leave the old files around.
             if self.revision.is_some() {
                 let old =
-                    expected_output_path(self.testpaths, None, &self.config.compare_mode, kind);
+                    expected_output_path(self.testpaths, None, &self.config.compare_mode, stream);
                 self.delete_file(&old);
             }
-            files.push(expected_output_path(
-                self.testpaths,
-                self.revision,
-                &self.config.compare_mode,
-                kind,
-            ));
-        }
 
-        for output_file in &files {
-            if actual.is_empty() {
-                self.delete_file(output_file);
-            } else if let Err(err) = fs::write(&output_file, &actual) {
-                self.fatal(&format!(
-                    "failed to write {} to `{}`: {}",
-                    kind,
-                    output_file.display(),
-                    err,
-                ));
+            if let Err(err) = fs::write(&expected_path, &actual) {
+                self.fatal(&format!("failed to write {stream} to `{expected_path:?}`: {err}"));
             }
+            println!("Blessing the {stream} of {test_name} in {expected_path:?}");
         }
 
-        println!("\nThe actual {0} differed from the expected {0}.", kind);
-        for output_file in files {
-            println!("Actual {} saved to {}", kind, output_file.display());
-        }
+        println!("\nThe actual {0} differed from the expected {0}.", stream);
+
         if self.config.bless { 0 } else { 1 }
     }
 
diff --git a/src/tools/compiletest/src/runtest/debugger.rs b/src/tools/compiletest/src/runtest/debugger.rs
index 985fe63..c15422f 100644
--- a/src/tools/compiletest/src/runtest/debugger.rs
+++ b/src/tools/compiletest/src/runtest/debugger.rs
@@ -4,7 +4,6 @@
 use std::path::{Path, PathBuf};
 
 use crate::common::Config;
-use crate::header::line_directive;
 use crate::runtest::ProcRes;
 
 /// Representation of information to invoke a debugger and check its output
@@ -24,7 +23,6 @@
         file: &Path,
         config: &Config,
         debugger_prefixes: &[&str],
-        rev: Option<&str>,
     ) -> Result<Self, String> {
         let directives = debugger_prefixes
             .iter()
@@ -39,17 +37,16 @@
         for (line_no, line) in reader.lines().enumerate() {
             counter += 1;
             let line = line.map_err(|e| format!("Error while parsing debugger commands: {}", e))?;
-            let (lnrev, line) = line_directive("//", &line).unwrap_or((None, &line));
 
-            // Skip any revision specific directive that doesn't match the current
-            // revision being tested
-            if lnrev.is_some() && lnrev != rev {
+            // Breakpoints appear on lines with actual code, typically at the end of the line.
+            if line.contains("#break") {
+                breakpoint_lines.push(counter);
                 continue;
             }
 
-            if line.contains("#break") {
-                breakpoint_lines.push(counter);
-            }
+            let Some(line) = line.trim_start().strip_prefix("//").map(str::trim_start) else {
+                continue;
+            };
 
             for &(ref command_directive, ref check_directive) in &directives {
                 config
diff --git a/src/tools/compiletest/src/runtest/debuginfo.rs b/src/tools/compiletest/src/runtest/debuginfo.rs
index bd0845b..c621c22 100644
--- a/src/tools/compiletest/src/runtest/debuginfo.rs
+++ b/src/tools/compiletest/src/runtest/debuginfo.rs
@@ -66,13 +66,8 @@
         };
 
         // Parse debugger commands etc from test files
-        let dbg_cmds = DebuggerCommands::parse_from(
-            &self.testpaths.file,
-            self.config,
-            prefixes,
-            self.revision,
-        )
-        .unwrap_or_else(|e| self.fatal(&e));
+        let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, self.config, prefixes)
+            .unwrap_or_else(|e| self.fatal(&e));
 
         // https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/debugger-commands
         let mut script_str = String::with_capacity(2048);
@@ -142,13 +137,8 @@
     }
 
     fn run_debuginfo_gdb_test_no_opt(&self) {
-        let dbg_cmds = DebuggerCommands::parse_from(
-            &self.testpaths.file,
-            self.config,
-            &["gdb"],
-            self.revision,
-        )
-        .unwrap_or_else(|e| self.fatal(&e));
+        let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, self.config, &["gdb"])
+            .unwrap_or_else(|e| self.fatal(&e));
         let mut cmds = dbg_cmds.commands.join("\n");
 
         // compile test file (it should have 'compile-flags:-g' in the header)
@@ -413,13 +403,8 @@
         }
 
         // Parse debugger commands etc from test files
-        let dbg_cmds = DebuggerCommands::parse_from(
-            &self.testpaths.file,
-            self.config,
-            &["lldb"],
-            self.revision,
-        )
-        .unwrap_or_else(|e| self.fatal(&e));
+        let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, self.config, &["lldb"])
+            .unwrap_or_else(|e| self.fatal(&e));
 
         // Write debugger script:
         // We don't want to hang when calling `quit` while the process is still running
diff --git a/src/tools/compiletest/src/runtest/run_make.rs b/src/tools/compiletest/src/runtest/run_make.rs
index f8ffd0f..04bc2d7 100644
--- a/src/tools/compiletest/src/runtest/run_make.rs
+++ b/src/tools/compiletest/src/runtest/run_make.rs
@@ -2,7 +2,7 @@
 use std::process::{Command, Output, Stdio};
 use std::{env, fs};
 
-use super::{ProcRes, TestCx};
+use super::{ProcRes, TestCx, disable_error_reporting};
 use crate::util::{copy_dir_all, dylib_env_var};
 
 impl TestCx<'_> {
@@ -329,6 +329,7 @@
             .arg(format!("run_make_support={}", &support_lib_path.to_string_lossy()))
             .arg("--edition=2021")
             .arg(&self.testpaths.file.join("rmake.rs"))
+            .arg("-Cprefer-dynamic")
             // Provide necessary library search paths for rustc.
             .env(dylib_env_var(), &env::join_paths(host_dylib_search_paths).unwrap());
 
@@ -514,8 +515,8 @@
             }
         }
 
-        let (Output { stdout, stderr, status }, truncated) =
-            self.read2_abbreviated(cmd.spawn().expect("failed to spawn `rmake`"));
+        let proc = disable_error_reporting(|| cmd.spawn().expect("failed to spawn `rmake`"));
+        let (Output { stdout, stderr, status }, truncated) = self.read2_abbreviated(proc);
         if !status.success() {
             let res = ProcRes {
                 status,
diff --git a/src/tools/miri/.github/workflows/ci.yml b/src/tools/miri/.github/workflows/ci.yml
index 8b0916f..2e49131 100644
--- a/src/tools/miri/.github/workflows/ci.yml
+++ b/src/tools/miri/.github/workflows/ci.yml
@@ -1,11 +1,7 @@
 name: CI
 
 on:
-  push:
-    # Run in PRs and for bors, but not on master.
-    branches:
-      - 'auto'
-      - 'try'
+  merge_group:
   pull_request:
     branches:
       - 'master'
@@ -38,7 +34,7 @@
       # The `style` job only runs on Linux; this makes sure the Windows-host-specific
       # code is also covered by clippy.
       - name: Check clippy
-        if: matrix.os == 'windows-latest'
+        if: ${{ matrix.os == 'windows-latest' }}
         run: ./miri clippy -- -D warnings
 
       - name: Test Miri
@@ -62,27 +58,25 @@
       - name: rustdoc
         run: RUSTDOCFLAGS="-Dwarnings" ./miri doc --document-private-items
 
-  # These jobs doesn't actually test anything, but they're only used to tell
-  # bors the build completed, as there is no practical way to detect when a
-  # workflow is successful listening to webhooks only.
-  #
+  # Summary job for the merge queue.
   # ALL THE PREVIOUS JOBS NEED TO BE ADDED TO THE `needs` SECTION OF THIS JOB!
-  end-success:
-    name: bors build finished
-    runs-on: ubuntu-latest
+  # And they should be added below in `cron-fail-notify` as well.
+  conclusion:
     needs: [build, style]
-    if: github.event.pusher.name == 'bors' && success()
-    steps:
-      - name: mark the job as a success
-        run: exit 0
-  end-failure:
-    name: bors build finished
+    # We need to ensure this job does *not* get skipped if its dependencies fail,
+    # because a skipped job is considered a success by GitHub. So we have to
+    # overwrite `if:`. We use `!cancelled()` to ensure the job does still not get run
+    # when the workflow is canceled manually.
+    if: ${{ !cancelled() }}
     runs-on: ubuntu-latest
-    needs: [build, style]
-    if: github.event.pusher.name == 'bors' && (failure() || cancelled())
     steps:
-      - name: mark the job as a failure
-        run: exit 1
+      # Manually check the status of all dependencies. `if: failure()` does not work.
+      - name: Conclusion
+        run: |
+            # Print the dependent jobs to see them in the CI log
+            jq -C <<< '${{ toJson(needs) }}'
+            # Check if all jobs that we depend on (in the needs array) were successful.
+            jq --exit-status 'all(.result == "success")' <<< '${{ toJson(needs) }}'
 
   cron-fail-notify:
     name: cronjob failure notification
@@ -93,7 +87,7 @@
         # ... and create a PR.
         pull-requests: write
     needs: [build, style]
-    if: github.event_name == 'schedule' && failure()
+    if: ${{ github.event_name == 'schedule' && failure() }}
     steps:
       # Send a Zulip notification
       - name: Install zulip-send
@@ -145,7 +139,7 @@
           git push -u origin $BRANCH
       - name: Create Pull Request
         run: |
-          PR=$(gh pr create -B master --title 'Automatic Rustup' --body '')
+          PR=$(gh pr create -B master --title 'Automatic Rustup' --body 'Please close and re-open this PR to trigger CI, then enable auto-merge.')
           ~/.local/bin/zulip-send --user $ZULIP_BOT_EMAIL --api-key $ZULIP_API_TOKEN --site https://rust-lang.zulipchat.com \
             --stream miri --subject "Miri Build Failure ($(date -u +%Y-%m))" \
             --message "A PR doing a rustc-pull [has been automatically created]($PR) for your convenience."
diff --git a/src/tools/miri/ci/ci.sh b/src/tools/miri/ci/ci.sh
index ad1b2f4..4e7cbc5 100755
--- a/src/tools/miri/ci/ci.sh
+++ b/src/tools/miri/ci/ci.sh
@@ -154,7 +154,7 @@
     TEST_TARGET=i686-unknown-freebsd   run_tests_minimal $BASIC $UNIX time hashmap random threadname pthread fs libc-pipe
     TEST_TARGET=x86_64-unknown-illumos run_tests_minimal $BASIC $UNIX time hashmap random thread sync available-parallelism tls libc-pipe
     TEST_TARGET=x86_64-pc-solaris      run_tests_minimal $BASIC $UNIX time hashmap random thread sync available-parallelism tls libc-pipe
-    TEST_TARGET=aarch64-linux-android  run_tests_minimal $BASIC $UNIX time hashmap pthread --skip threadname
+    TEST_TARGET=aarch64-linux-android  run_tests_minimal $BASIC $UNIX time hashmap threadname pthread
     TEST_TARGET=wasm32-wasip2          run_tests_minimal $BASIC wasm
     TEST_TARGET=wasm32-unknown-unknown run_tests_minimal no_std empty_main wasm # this target doesn't really have std
     TEST_TARGET=thumbv7em-none-eabihf  run_tests_minimal no_std
diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version
index 8b9e7ef..133edd3 100644
--- a/src/tools/miri/rust-version
+++ b/src/tools/miri/rust-version
@@ -1 +1 @@
-17a19e684cdf3ca088af8b4da6a6209d128913f4
+814df6e50eaf89b90793e7d9618bb60f1f18377a
diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/diagnostics.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/diagnostics.rs
index 1684abe..5624c4c 100644
--- a/src/tools/miri/src/borrow_tracker/stacked_borrows/diagnostics.rs
+++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/diagnostics.rs
@@ -424,7 +424,11 @@
     }
 
     #[inline(never)] // This is only called on fatal code paths
-    pub(super) fn protector_error(&self, item: &Item, kind: ProtectorKind) -> InterpErrorKind<'tcx> {
+    pub(super) fn protector_error(
+        &self,
+        item: &Item,
+        kind: ProtectorKind,
+    ) -> InterpErrorKind<'tcx> {
         let protected = match kind {
             ProtectorKind::WeakProtector => "weakly protected",
             ProtectorKind::StrongProtector => "strongly protected",
diff --git a/src/tools/miri/src/intrinsics/mod.rs b/src/tools/miri/src/intrinsics/mod.rs
index 09ec2cb..776d256 100644
--- a/src/tools/miri/src/intrinsics/mod.rs
+++ b/src/tools/miri/src/intrinsics/mod.rs
@@ -145,6 +145,21 @@
                 this.write_scalar(Scalar::from_bool(branch), dest)?;
             }
 
+            "floorf16" | "ceilf16" | "truncf16" | "roundf16" | "rintf16" => {
+                let [f] = check_arg_count(args)?;
+                let f = this.read_scalar(f)?.to_f16()?;
+                let mode = match intrinsic_name {
+                    "floorf16" => Round::TowardNegative,
+                    "ceilf16" => Round::TowardPositive,
+                    "truncf16" => Round::TowardZero,
+                    "roundf16" => Round::NearestTiesToAway,
+                    "rintf16" => Round::NearestTiesToEven,
+                    _ => bug!(),
+                };
+                let res = f.round_to_integral(mode).value;
+                let res = this.adjust_nan(res, &[f]);
+                this.write_scalar(res, dest)?;
+            }
             "floorf32" | "ceilf32" | "truncf32" | "roundf32" | "rintf32" => {
                 let [f] = check_arg_count(args)?;
                 let f = this.read_scalar(f)?.to_f32()?;
@@ -175,6 +190,21 @@
                 let res = this.adjust_nan(res, &[f]);
                 this.write_scalar(res, dest)?;
             }
+            "floorf128" | "ceilf128" | "truncf128" | "roundf128" | "rintf128" => {
+                let [f] = check_arg_count(args)?;
+                let f = this.read_scalar(f)?.to_f128()?;
+                let mode = match intrinsic_name {
+                    "floorf128" => Round::TowardNegative,
+                    "ceilf128" => Round::TowardPositive,
+                    "truncf128" => Round::TowardZero,
+                    "roundf128" => Round::NearestTiesToAway,
+                    "rintf128" => Round::NearestTiesToEven,
+                    _ => bug!(),
+                };
+                let res = f.round_to_integral(mode).value;
+                let res = this.adjust_nan(res, &[f]);
+                this.write_scalar(res, dest)?;
+            }
 
             #[rustfmt::skip]
             | "sinf32"
diff --git a/src/tools/miri/src/intrinsics/simd.rs b/src/tools/miri/src/intrinsics/simd.rs
index 0799b93..f15b83a 100644
--- a/src/tools/miri/src/intrinsics/simd.rs
+++ b/src/tools/miri/src/intrinsics/simd.rs
@@ -1,7 +1,8 @@
 use either::Either;
 use rustc_apfloat::{Float, Round};
+use rustc_middle::ty::FloatTy;
 use rustc_middle::ty::layout::LayoutOf;
-use rustc_middle::{mir, ty, ty::FloatTy};
+use rustc_middle::{mir, ty};
 use rustc_span::{Symbol, sym};
 use rustc_target::abi::{Endian, HasDataLayout};
 
@@ -630,12 +631,8 @@
                 let (right, right_len) = this.project_to_simd(right)?;
                 let (dest, dest_len) = this.project_to_simd(dest)?;
 
-                let index = generic_args[2]
-                    .expect_const()
-                    .try_to_valtree()
-                    .unwrap()
-                    .0
-                    .unwrap_branch();
+                let index =
+                    generic_args[2].expect_const().try_to_valtree().unwrap().0.unwrap_branch();
                 let index_len = index.len();
 
                 assert_eq!(left_len, right_len);
diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs
index 660f2e4..938d1ca 100644
--- a/src/tools/miri/src/lib.rs
+++ b/src/tools/miri/src/lib.rs
@@ -147,7 +147,7 @@
 pub use crate::shims::EmulateItemResult;
 pub use crate::shims::env::{EnvVars, EvalContextExt as _};
 pub use crate::shims::foreign_items::{DynSym, EvalContextExt as _};
-pub use crate::shims::io_error::{EvalContextExt as _, LibcError};
+pub use crate::shims::io_error::{EvalContextExt as _, IoError, LibcError};
 pub use crate::shims::os_str::EvalContextExt as _;
 pub use crate::shims::panic::{CatchUnwindData, EvalContextExt as _};
 pub use crate::shims::time::EvalContextExt as _;
diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs
index f6f91e5..12f8fac 100644
--- a/src/tools/miri/src/shims/foreign_items.rs
+++ b/src/tools/miri/src/shims/foreign_items.rs
@@ -447,8 +447,7 @@
                 } else {
                     // If this does not fit in an isize, return null and, on Unix, set errno.
                     if this.target_os_is_unix() {
-                        let einval = this.eval_libc("ENOMEM");
-                        this.set_last_error(einval)?;
+                        this.set_last_error(LibcError("ENOMEM"))?;
                     }
                     this.write_null(dest)?;
                 }
@@ -464,8 +463,7 @@
                 } else {
                     // On size overflow, return null and, on Unix, set errno.
                     if this.target_os_is_unix() {
-                        let einval = this.eval_libc("ENOMEM");
-                        this.set_last_error(einval)?;
+                        this.set_last_error(LibcError("ENOMEM"))?;
                     }
                     this.write_null(dest)?;
                 }
@@ -486,8 +484,7 @@
                 } else {
                     // If this does not fit in an isize, return null and, on Unix, set errno.
                     if this.target_os_is_unix() {
-                        let einval = this.eval_libc("ENOMEM");
-                        this.set_last_error(einval)?;
+                        this.set_last_error(LibcError("ENOMEM"))?;
                     }
                     this.write_null(dest)?;
                 }
diff --git a/src/tools/miri/src/shims/io_error.rs b/src/tools/miri/src/shims/io_error.rs
index 38aa181..04491f0 100644
--- a/src/tools/miri/src/shims/io_error.rs
+++ b/src/tools/miri/src/shims/io_error.rs
@@ -141,6 +141,16 @@
         interp_ok(Scalar::from_i32(-1))
     }
 
+    /// Sets the last OS error and return `-1` as a `i64`-typed Scalar
+    fn set_last_error_and_return_i64(
+        &mut self,
+        err: impl Into<IoError>,
+    ) -> InterpResult<'tcx, Scalar> {
+        let this = self.eval_context_mut();
+        this.set_last_error(err)?;
+        interp_ok(Scalar::from_i64(-1))
+    }
+
     /// Gets the last error variable.
     fn get_last_error(&mut self) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_mut();
diff --git a/src/tools/miri/src/shims/time.rs b/src/tools/miri/src/shims/time.rs
index 12c7679..6436823 100644
--- a/src/tools/miri/src/shims/time.rs
+++ b/src/tools/miri/src/shims/time.rs
@@ -81,9 +81,7 @@
         } else if relative_clocks.contains(&clk_id) {
             this.machine.clock.now().duration_since(this.machine.clock.epoch())
         } else {
-            let einval = this.eval_libc("EINVAL");
-            this.set_last_error(einval)?;
-            return interp_ok(Scalar::from_i32(-1));
+            return this.set_last_error_and_return_i32(LibcError("EINVAL"));
         };
 
         let tv_sec = duration.as_secs();
@@ -109,9 +107,7 @@
         // Using tz is obsolete and should always be null
         let tz = this.read_pointer(tz_op)?;
         if !this.ptr_is_null(tz)? {
-            let einval = this.eval_libc("EINVAL");
-            this.set_last_error(einval)?;
-            return interp_ok(Scalar::from_i32(-1));
+            return this.set_last_error_and_return_i32(LibcError("EINVAL"));
         }
 
         let duration = system_time_to_duration(&SystemTime::now())?;
@@ -323,9 +319,7 @@
         let duration = match this.read_timespec(&req)? {
             Some(duration) => duration,
             None => {
-                let einval = this.eval_libc("EINVAL");
-                this.set_last_error(einval)?;
-                return interp_ok(Scalar::from_i32(-1));
+                return this.set_last_error_and_return_i32(LibcError("EINVAL"));
             }
         };
 
diff --git a/src/tools/miri/src/shims/unix/android/foreign_items.rs b/src/tools/miri/src/shims/unix/android/foreign_items.rs
index 583a1f6..b6f0495 100644
--- a/src/tools/miri/src/shims/unix/android/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/android/foreign_items.rs
@@ -1,6 +1,7 @@
 use rustc_span::Symbol;
 use rustc_target::spec::abi::Abi;
 
+use crate::shims::unix::android::thread::prctl;
 use crate::*;
 
 pub fn is_dyn_sym(_name: &str) -> bool {
@@ -25,6 +26,9 @@
                 this.write_scalar(errno_place.to_ref(this).to_scalar(), dest)?;
             }
 
+            // Threading
+            "prctl" => prctl(this, link_name, abi, args, dest)?,
+
             _ => return interp_ok(EmulateItemResult::NotSupported),
         }
         interp_ok(EmulateItemResult::NeedsReturn)
diff --git a/src/tools/miri/src/shims/unix/android/mod.rs b/src/tools/miri/src/shims/unix/android/mod.rs
index 09c6507..1f2a74b 100644
--- a/src/tools/miri/src/shims/unix/android/mod.rs
+++ b/src/tools/miri/src/shims/unix/android/mod.rs
@@ -1 +1,2 @@
 pub mod foreign_items;
+pub mod thread;
diff --git a/src/tools/miri/src/shims/unix/android/thread.rs b/src/tools/miri/src/shims/unix/android/thread.rs
new file mode 100644
index 0000000..6f5f0f7
--- /dev/null
+++ b/src/tools/miri/src/shims/unix/android/thread.rs
@@ -0,0 +1,57 @@
+use rustc_span::Symbol;
+use rustc_target::abi::Size;
+use rustc_target::spec::abi::Abi;
+
+use crate::helpers::check_min_arg_count;
+use crate::shims::unix::thread::EvalContextExt as _;
+use crate::*;
+
+const TASK_COMM_LEN: usize = 16;
+
+pub fn prctl<'tcx>(
+    this: &mut MiriInterpCx<'tcx>,
+    link_name: Symbol,
+    abi: Abi,
+    args: &[OpTy<'tcx>],
+    dest: &MPlaceTy<'tcx>,
+) -> InterpResult<'tcx> {
+    // We do not use `check_shim` here because `prctl` is variadic. The argument
+    // count is checked bellow.
+    this.check_abi_and_shim_symbol_clash(abi, Abi::C { unwind: false }, link_name)?;
+
+    // FIXME: Use constants once https://github.com/rust-lang/libc/pull/3941 backported to the 0.2 branch.
+    let pr_set_name = 15;
+    let pr_get_name = 16;
+
+    let [op] = check_min_arg_count("prctl", args)?;
+    let res = match this.read_scalar(op)?.to_i32()? {
+        op if op == pr_set_name => {
+            let [_, name] = check_min_arg_count("prctl(PR_SET_NAME, ...)", args)?;
+            let name = this.read_scalar(name)?;
+            let thread = this.pthread_self()?;
+            // The Linux kernel silently truncates long names.
+            // https://www.man7.org/linux/man-pages/man2/PR_SET_NAME.2const.html
+            let res =
+                this.pthread_setname_np(thread, name, TASK_COMM_LEN, /* truncate */ true)?;
+            assert!(res);
+            Scalar::from_u32(0)
+        }
+        op if op == pr_get_name => {
+            let [_, name] = check_min_arg_count("prctl(PR_GET_NAME, ...)", args)?;
+            let name = this.read_scalar(name)?;
+            let thread = this.pthread_self()?;
+            let len = Scalar::from_target_usize(TASK_COMM_LEN as u64, this);
+            this.check_ptr_access(
+                name.to_pointer(this)?,
+                Size::from_bytes(TASK_COMM_LEN),
+                CheckInAllocMsg::MemoryAccessTest,
+            )?;
+            let res = this.pthread_getname_np(thread, name, len, /* truncate*/ false)?;
+            assert!(res);
+            Scalar::from_u32(0)
+        }
+        op => throw_unsup_format!("Miri does not support `prctl` syscall with op={}", op),
+    };
+    this.write_scalar(res, dest)?;
+    interp_ok(())
+}
diff --git a/src/tools/miri/src/shims/unix/fd.rs b/src/tools/miri/src/shims/unix/fd.rs
index e391464..f3db566 100644
--- a/src/tools/miri/src/shims/unix/fd.rs
+++ b/src/tools/miri/src/shims/unix/fd.rs
@@ -423,7 +423,7 @@
         let this = self.eval_context_mut();
 
         let Some(fd) = this.machine.fds.get(old_fd_num) else {
-            return interp_ok(Scalar::from_i32(this.fd_not_found()?));
+            return this.set_last_error_and_return_i32(LibcError("EBADF"));
         };
         interp_ok(Scalar::from_i32(this.machine.fds.insert(fd)))
     }
@@ -432,7 +432,7 @@
         let this = self.eval_context_mut();
 
         let Some(fd) = this.machine.fds.get(old_fd_num) else {
-            return interp_ok(Scalar::from_i32(this.fd_not_found()?));
+            return this.set_last_error_and_return_i32(LibcError("EBADF"));
         };
         if new_fd_num != old_fd_num {
             // Close new_fd if it is previously opened.
@@ -448,7 +448,7 @@
     fn flock(&mut self, fd_num: i32, op: i32) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_mut();
         let Some(fd) = this.machine.fds.get(fd_num) else {
-            return interp_ok(Scalar::from_i32(this.fd_not_found()?));
+            return this.set_last_error_and_return_i32(LibcError("EBADF"));
         };
 
         // We need to check that there aren't unsupported options in `op`.
@@ -498,11 +498,11 @@
                 // `FD_CLOEXEC` value without checking if the flag is set for the file because `std`
                 // always sets this flag when opening a file. However we still need to check that the
                 // file itself is open.
-                interp_ok(Scalar::from_i32(if this.machine.fds.is_fd_num(fd_num) {
-                    this.eval_libc_i32("FD_CLOEXEC")
+                if !this.machine.fds.is_fd_num(fd_num) {
+                    this.set_last_error_and_return_i32(LibcError("EBADF"))
                 } else {
-                    this.fd_not_found()?
-                }))
+                    interp_ok(this.eval_libc("FD_CLOEXEC"))
+                }
             }
             cmd if cmd == f_dupfd || cmd == f_dupfd_cloexec => {
                 // Note that we always assume the FD_CLOEXEC flag is set for every open file, in part
@@ -521,7 +521,7 @@
                 if let Some(fd) = this.machine.fds.get(fd_num) {
                     interp_ok(Scalar::from_i32(this.machine.fds.insert_with_min_num(fd, start)))
                 } else {
-                    interp_ok(Scalar::from_i32(this.fd_not_found()?))
+                    this.set_last_error_and_return_i32(LibcError("EBADF"))
                 }
             }
             cmd if this.tcx.sess.target.os == "macos"
@@ -547,7 +547,7 @@
         let fd_num = this.read_scalar(fd_op)?.to_i32()?;
 
         let Some(fd) = this.machine.fds.remove(fd_num) else {
-            return interp_ok(Scalar::from_i32(this.fd_not_found()?));
+            return this.set_last_error_and_return_i32(LibcError("EBADF"));
         };
         let result = fd.close(this.machine.communicate(), this)?;
         // return `0` if close is successful
@@ -555,17 +555,6 @@
         interp_ok(Scalar::from_i32(this.try_unwrap_io_result(result)?))
     }
 
-    /// Function used when a file descriptor does not exist. It returns `Ok(-1)`and sets
-    /// the last OS error to `libc::EBADF` (invalid file descriptor). This function uses
-    /// `T: From<i32>` instead of `i32` directly because some fs functions return different integer
-    /// types (like `read`, that returns an `i64`).
-    fn fd_not_found<T: From<i32>>(&mut self) -> InterpResult<'tcx, T> {
-        let this = self.eval_context_mut();
-        let ebadf = this.eval_libc("EBADF");
-        this.set_last_error(ebadf)?;
-        interp_ok((-1).into())
-    }
-
     /// Read data from `fd` into buffer specified by `buf` and `count`.
     ///
     /// If `offset` is `None`, reads data from current cursor position associated with `fd`
@@ -599,9 +588,7 @@
         // We temporarily dup the FD to be able to retain mutable access to `this`.
         let Some(fd) = this.machine.fds.get(fd_num) else {
             trace!("read: FD not found");
-            let res: i32 = this.fd_not_found()?;
-            this.write_int(res, dest)?;
-            return interp_ok(());
+            return this.set_last_error_and_return(LibcError("EBADF"), dest);
         };
 
         trace!("read: FD mapped to {fd:?}");
@@ -646,9 +633,7 @@
 
         // We temporarily dup the FD to be able to retain mutable access to `this`.
         let Some(fd) = this.machine.fds.get(fd_num) else {
-            let res: i32 = this.fd_not_found()?;
-            this.write_int(res, dest)?;
-            return interp_ok(());
+            return this.set_last_error_and_return(LibcError("EBADF"), dest);
         };
 
         match offset {
diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs
index 7ba9898..355c93c 100644
--- a/src/tools/miri/src/shims/unix/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/foreign_items.rs
@@ -362,8 +362,7 @@
                 // FreeBSD: https://man.freebsd.org/cgi/man.cgi?query=reallocarray
                 match this.compute_size_in_bytes(Size::from_bytes(size), nmemb) {
                     None => {
-                        let enmem = this.eval_libc("ENOMEM");
-                        this.set_last_error(enmem)?;
+                        this.set_last_error(LibcError("ENOMEM"))?;
                         this.write_null(dest)?;
                     }
                     Some(len) => {
@@ -653,13 +652,10 @@
                 let chunk_size = CpuAffinityMask::chunk_size(this);
 
                 if this.ptr_is_null(mask)? {
-                    let efault = this.eval_libc("EFAULT");
-                    this.set_last_error(efault)?;
-                    this.write_int(-1, dest)?;
+                    this.set_last_error_and_return(LibcError("EFAULT"), dest)?;
                 } else if cpusetsize == 0 || cpusetsize.checked_rem(chunk_size).unwrap() != 0 {
                     // we only copy whole chunks of size_of::<c_ulong>()
-                    this.set_last_error(LibcError("EINVAL"))?;
-                    this.write_int(-1, dest)?;
+                    this.set_last_error_and_return(LibcError("EINVAL"), dest)?;
                 } else if let Some(cpuset) = this.machine.thread_cpu_affinity.get(&thread_id) {
                     let cpuset = cpuset.clone();
                     // we only copy whole chunks of size_of::<c_ulong>()
@@ -668,9 +664,7 @@
                     this.write_null(dest)?;
                 } else {
                     // The thread whose ID is pid could not be found
-                    let esrch = this.eval_libc("ESRCH");
-                    this.set_last_error(esrch)?;
-                    this.write_int(-1, dest)?;
+                    this.set_last_error_and_return(LibcError("ESRCH"), dest)?;
                 }
             }
             "sched_setaffinity" => {
@@ -695,9 +689,7 @@
                 };
 
                 if this.ptr_is_null(mask)? {
-                    let efault = this.eval_libc("EFAULT");
-                    this.set_last_error(efault)?;
-                    this.write_int(-1, dest)?;
+                    this.set_last_error_and_return(LibcError("EFAULT"), dest)?;
                 } else {
                     // NOTE: cpusetsize might be smaller than `CpuAffinityMask::CPU_MASK_BYTES`.
                     // Any unspecified bytes are treated as zero here (none of the CPUs are configured).
@@ -713,8 +705,7 @@
                         }
                         None => {
                             // The intersection between the mask and the available CPUs was empty.
-                            this.set_last_error(LibcError("EINVAL"))?;
-                            this.write_int(-1, dest)?;
+                            this.set_last_error_and_return(LibcError("EINVAL"), dest)?;
                         }
                     }
                 }
@@ -770,9 +761,7 @@
                 // macOS: https://keith.github.io/xcode-man-pages/getentropy.2.html
                 // Solaris/Illumos: https://illumos.org/man/3C/getentropy
                 if bufsize > 256 {
-                    let err = this.eval_libc("EIO");
-                    this.set_last_error(err)?;
-                    this.write_int(-1, dest)?;
+                    this.set_last_error_and_return(LibcError("EIO"), dest)?;
                 } else {
                     this.gen_random(buf, bufsize)?;
                     this.write_null(dest)?;
diff --git a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs
index 5204e57..71953ac 100644
--- a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs
@@ -29,6 +29,7 @@
                     this.read_scalar(thread)?,
                     this.read_scalar(name)?,
                     max_len,
+                    /* truncate */ false,
                 )?;
             }
             "pthread_get_name_np" => {
diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs
index 4b3ae8e..f7436d7 100644
--- a/src/tools/miri/src/shims/unix/fs.rs
+++ b/src/tools/miri/src/shims/unix/fs.rs
@@ -149,6 +149,7 @@
             // to handle possible errors correctly.
             let result = self.file.sync_all();
             // Now we actually close the file and return the result.
+            drop(*self);
             interp_ok(result)
         } else {
             // We drop the file, this closes it but ignores any errors
@@ -157,6 +158,7 @@
             // `/dev/urandom` which are read-only. Check
             // https://github.com/rust-lang/miri/issues/999#issuecomment-568920439
             // for a deeper discussion.
+            drop(*self);
             interp_ok(Ok(()))
         }
     }
@@ -229,6 +231,8 @@
                 TRUE => Ok(()),
                 FALSE => {
                     let mut err = io::Error::last_os_error();
+                    // This only runs on Windows hosts so we can use `raw_os_error`.
+                    // We have to be careful not to forward that error code to target code.
                     let code: u32 = err.raw_os_error().unwrap().try_into().unwrap();
                     if matches!(code, ERROR_IO_PENDING | ERROR_LOCK_VIOLATION) {
                         if lock_nb {
@@ -337,15 +341,10 @@
                     _ => interp_ok(this.eval_libc("DT_UNKNOWN").to_u8()?.into()),
                 }
             }
-            Err(e) =>
-                match e.raw_os_error() {
-                    Some(error) => interp_ok(error),
-                    None =>
-                        throw_unsup_format!(
-                            "the error {} couldn't be converted to a return value",
-                            e
-                        ),
-                },
+            Err(_) => {
+                // Fallback on error
+                interp_ok(this.eval_libc("DT_UNKNOWN").to_u8()?.into())
+            }
         }
     }
 }
@@ -528,8 +527,7 @@
             let o_tmpfile = this.eval_libc_i32("O_TMPFILE");
             if flag & o_tmpfile == o_tmpfile {
                 // if the flag contains `O_TMPFILE` then we return a graceful error
-                this.set_last_error(LibcError("EOPNOTSUPP"))?;
-                return interp_ok(Scalar::from_i32(-1));
+                return this.set_last_error_and_return_i32(LibcError("EOPNOTSUPP"));
             }
         }
 
@@ -548,9 +546,7 @@
                 // O_NOFOLLOW only fails when the trailing component is a symlink;
                 // the entire rest of the path can still contain symlinks.
                 if path.is_symlink() {
-                    let eloop = this.eval_libc("ELOOP");
-                    this.set_last_error(eloop)?;
-                    return interp_ok(Scalar::from_i32(-1));
+                    return this.set_last_error_and_return_i32(LibcError("ELOOP"));
                 }
             }
             mirror |= o_nofollow;
@@ -565,8 +561,7 @@
         // Reject if isolation is enabled.
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`open`", reject_with)?;
-            this.set_last_error(ErrorKind::PermissionDenied)?;
-            return interp_ok(Scalar::from_i32(-1));
+            return this.set_last_error_and_return_i32(ErrorKind::PermissionDenied);
         }
 
         let fd = options
@@ -584,8 +579,7 @@
         let seek_from = if whence == this.eval_libc_i32("SEEK_SET") {
             if offset < 0 {
                 // Negative offsets return `EINVAL`.
-                this.set_last_error(LibcError("EINVAL"))?;
-                return interp_ok(Scalar::from_i64(-1));
+                return this.set_last_error_and_return_i64(LibcError("EINVAL"));
             } else {
                 SeekFrom::Start(u64::try_from(offset).unwrap())
             }
@@ -594,14 +588,13 @@
         } else if whence == this.eval_libc_i32("SEEK_END") {
             SeekFrom::End(i64::try_from(offset).unwrap())
         } else {
-            this.set_last_error(LibcError("EINVAL"))?;
-            return interp_ok(Scalar::from_i64(-1));
+            return this.set_last_error_and_return_i64(LibcError("EINVAL"));
         };
 
         let communicate = this.machine.communicate();
 
         let Some(fd) = this.machine.fds.get(fd_num) else {
-            return interp_ok(Scalar::from_i64(this.fd_not_found()?));
+            return this.set_last_error_and_return_i64(LibcError("EBADF"));
         };
         let result = fd.seek(communicate, seek_from)?.map(|offset| i64::try_from(offset).unwrap());
         drop(fd);
@@ -618,8 +611,7 @@
         // Reject if isolation is enabled.
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`unlink`", reject_with)?;
-            this.set_last_error(ErrorKind::PermissionDenied)?;
-            return interp_ok(Scalar::from_i32(-1));
+            return this.set_last_error_and_return_i32(ErrorKind::PermissionDenied);
         }
 
         let result = remove_file(path).map(|_| 0);
@@ -649,8 +641,7 @@
         // Reject if isolation is enabled.
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`symlink`", reject_with)?;
-            this.set_last_error(ErrorKind::PermissionDenied)?;
-            return interp_ok(Scalar::from_i32(-1));
+            return this.set_last_error_and_return_i32(ErrorKind::PermissionDenied);
         }
 
         let result = create_link(&target, &linkpath).map(|_| 0);
@@ -674,15 +665,13 @@
         // Reject if isolation is enabled.
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`stat`", reject_with)?;
-            let eacc = this.eval_libc("EACCES");
-            this.set_last_error(eacc)?;
-            return interp_ok(Scalar::from_i32(-1));
+            return this.set_last_error_and_return_i32(LibcError("EACCES"));
         }
 
         // `stat` always follows symlinks.
         let metadata = match FileMetadata::from_path(this, &path, true)? {
-            Some(metadata) => metadata,
-            None => return interp_ok(Scalar::from_i32(-1)), // `FileMetadata` has set errno
+            Ok(metadata) => metadata,
+            Err(err) => return this.set_last_error_and_return_i32(err),
         };
 
         interp_ok(Scalar::from_i32(this.macos_stat_write_buf(metadata, buf_op)?))
@@ -706,14 +695,12 @@
         // Reject if isolation is enabled.
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`lstat`", reject_with)?;
-            let eacc = this.eval_libc("EACCES");
-            this.set_last_error(eacc)?;
-            return interp_ok(Scalar::from_i32(-1));
+            return this.set_last_error_and_return_i32(LibcError("EACCES"));
         }
 
         let metadata = match FileMetadata::from_path(this, &path, false)? {
-            Some(metadata) => metadata,
-            None => return interp_ok(Scalar::from_i32(-1)), // `FileMetadata` has set errno
+            Ok(metadata) => metadata,
+            Err(err) => return this.set_last_error_and_return_i32(err),
         };
 
         interp_ok(Scalar::from_i32(this.macos_stat_write_buf(metadata, buf_op)?))
@@ -736,12 +723,12 @@
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`fstat`", reject_with)?;
             // Set error code as "EBADF" (bad fd)
-            return interp_ok(Scalar::from_i32(this.fd_not_found()?));
+            return this.set_last_error_and_return_i32(LibcError("EBADF"));
         }
 
         let metadata = match FileMetadata::from_fd_num(this, fd)? {
-            Some(metadata) => metadata,
-            None => return interp_ok(Scalar::from_i32(-1)),
+            Ok(metadata) => metadata,
+            Err(err) => return this.set_last_error_and_return_i32(err),
         };
         interp_ok(Scalar::from_i32(this.macos_stat_write_buf(metadata, buf_op)?))
     }
@@ -766,9 +753,7 @@
 
         // If the statxbuf or pathname pointers are null, the function fails with `EFAULT`.
         if this.ptr_is_null(statxbuf_ptr)? || this.ptr_is_null(pathname_ptr)? {
-            let efault = this.eval_libc("EFAULT");
-            this.set_last_error(efault)?;
-            return interp_ok(Scalar::from_i32(-1));
+            return this.set_last_error_and_return_i32(LibcError("EFAULT"));
         }
 
         let statxbuf = this.deref_pointer_as(statxbuf_op, this.libc_ty_layout("statx"))?;
@@ -801,16 +786,15 @@
             let ecode = if path.is_absolute() || dirfd == this.eval_libc_i32("AT_FDCWD") {
                 // since `path` is provided, either absolute or
                 // relative to CWD, `EACCES` is the most relevant.
-                this.eval_libc("EACCES")
+                LibcError("EACCES")
             } else {
                 // `dirfd` is set to target file, and `path` is empty
                 // (or we would have hit the `throw_unsup_format`
                 // above). `EACCES` would violate the spec.
                 assert!(empty_path_flag);
-                this.eval_libc("EBADF")
+                LibcError("EBADF")
             };
-            this.set_last_error(ecode)?;
-            return interp_ok(Scalar::from_i32(-1));
+            return this.set_last_error_and_return_i32(ecode);
         }
 
         // the `_mask_op` parameter specifies the file information that the caller requested.
@@ -831,8 +815,8 @@
             FileMetadata::from_path(this, &path, follow_symlink)?
         };
         let metadata = match metadata {
-            Some(metadata) => metadata,
-            None => return interp_ok(Scalar::from_i32(-1)),
+            Ok(metadata) => metadata,
+            Err(err) => return this.set_last_error_and_return_i32(err),
         };
 
         // The `mode` field specifies the type of the file and the permissions over the file for
@@ -939,9 +923,7 @@
         let newpath_ptr = this.read_pointer(newpath_op)?;
 
         if this.ptr_is_null(oldpath_ptr)? || this.ptr_is_null(newpath_ptr)? {
-            let efault = this.eval_libc("EFAULT");
-            this.set_last_error(efault)?;
-            return interp_ok(Scalar::from_i32(-1));
+            return this.set_last_error_and_return_i32(LibcError("EFAULT"));
         }
 
         let oldpath = this.read_path_from_c_str(oldpath_ptr)?;
@@ -950,8 +932,7 @@
         // Reject if isolation is enabled.
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`rename`", reject_with)?;
-            this.set_last_error(ErrorKind::PermissionDenied)?;
-            return interp_ok(Scalar::from_i32(-1));
+            return this.set_last_error_and_return_i32(ErrorKind::PermissionDenied);
         }
 
         let result = rename(oldpath, newpath).map(|_| 0);
@@ -974,8 +955,7 @@
         // Reject if isolation is enabled.
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`mkdir`", reject_with)?;
-            this.set_last_error(ErrorKind::PermissionDenied)?;
-            return interp_ok(Scalar::from_i32(-1));
+            return this.set_last_error_and_return_i32(ErrorKind::PermissionDenied);
         }
 
         #[cfg_attr(not(unix), allow(unused_mut))]
@@ -1002,8 +982,7 @@
         // Reject if isolation is enabled.
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`rmdir`", reject_with)?;
-            this.set_last_error(ErrorKind::PermissionDenied)?;
-            return interp_ok(Scalar::from_i32(-1));
+            return this.set_last_error_and_return_i32(ErrorKind::PermissionDenied);
         }
 
         let result = remove_dir(path).map(|_| 0i32);
@@ -1019,8 +998,7 @@
         // Reject if isolation is enabled.
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`opendir`", reject_with)?;
-            let eacc = this.eval_libc("EACCES");
-            this.set_last_error(eacc)?;
+            this.set_last_error(LibcError("EACCES"))?;
             return interp_ok(Scalar::null_ptr(this));
         }
 
@@ -1052,8 +1030,7 @@
         // Reject if isolation is enabled.
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`readdir`", reject_with)?;
-            let eacc = this.eval_libc("EBADF");
-            this.set_last_error(eacc)?;
+            this.set_last_error(LibcError("EBADF"))?;
             return interp_ok(Scalar::null_ptr(this));
         }
 
@@ -1152,14 +1129,14 @@
         // Reject if isolation is enabled.
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`readdir_r`", reject_with)?;
-            // Set error code as "EBADF" (bad fd)
-            return interp_ok(Scalar::from_i32(this.fd_not_found()?));
+            // Return error code, do *not* set `errno`.
+            return interp_ok(this.eval_libc("EBADF"));
         }
 
         let open_dir = this.machine.dirs.streams.get_mut(&dirp).ok_or_else(|| {
             err_unsup_format!("the DIR pointer passed to readdir_r did not come from opendir")
         })?;
-        interp_ok(Scalar::from_i32(match open_dir.read_dir.next() {
+        interp_ok(match open_dir.read_dir.next() {
             Some(Ok(dir_entry)) => {
                 // Write into entry, write pointer to result, return 0 on success.
                 // The name is written with write_os_str_to_c_str, while the rest of the
@@ -1237,25 +1214,18 @@
                 let result_place = this.deref_pointer(result_op)?;
                 this.write_scalar(this.read_scalar(entry_op)?, &result_place)?;
 
-                0
+                Scalar::from_i32(0)
             }
             None => {
                 // end of stream: return 0, assign *result=NULL
                 this.write_null(&this.deref_pointer(result_op)?)?;
-                0
+                Scalar::from_i32(0)
             }
-            Some(Err(e)) =>
-                match e.raw_os_error() {
-                    // return positive error number on error
-                    Some(error) => error,
-                    None => {
-                        throw_unsup_format!(
-                            "the error {} couldn't be converted to a return value",
-                            e
-                        )
-                    }
-                },
-        }))
+            Some(Err(e)) => {
+                // return positive error number on error (do *not* set last error)
+                this.io_error_to_errnum(e)?
+            }
+        })
     }
 
     fn closedir(&mut self, dirp_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
@@ -1264,20 +1234,21 @@
         let dirp = this.read_target_usize(dirp_op)?;
 
         // Reject if isolation is enabled.
-        interp_ok(Scalar::from_i32(
-            if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
-                this.reject_in_isolation("`closedir`", reject_with)?;
-                this.fd_not_found()?
-            } else if let Some(open_dir) = this.machine.dirs.streams.remove(&dirp) {
-                if let Some(entry) = open_dir.entry {
-                    this.deallocate_ptr(entry, None, MiriMemoryKind::Runtime.into())?;
-                }
-                drop(open_dir);
-                0
-            } else {
-                this.fd_not_found()?
-            },
-        ))
+        if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
+            this.reject_in_isolation("`closedir`", reject_with)?;
+            return this.set_last_error_and_return_i32(LibcError("EBADF"));
+        }
+
+        let Some(mut open_dir) = this.machine.dirs.streams.remove(&dirp) else {
+            return this.set_last_error_and_return_i32(LibcError("EBADF"));
+        };
+        if let Some(entry) = open_dir.entry.take() {
+            this.deallocate_ptr(entry, None, MiriMemoryKind::Runtime.into())?;
+        }
+        // We drop the `open_dir`, which will close the host dir handle.
+        drop(open_dir);
+
+        interp_ok(Scalar::from_i32(0))
     }
 
     fn ftruncate64(&mut self, fd_num: i32, length: i128) -> InterpResult<'tcx, Scalar> {
@@ -1287,11 +1258,11 @@
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`ftruncate64`", reject_with)?;
             // Set error code as "EBADF" (bad fd)
-            return interp_ok(Scalar::from_i32(this.fd_not_found()?));
+            return this.set_last_error_and_return_i32(LibcError("EBADF"));
         }
 
         let Some(fd) = this.machine.fds.get(fd_num) else {
-            return interp_ok(Scalar::from_i32(this.fd_not_found()?));
+            return this.set_last_error_and_return_i32(LibcError("EBADF"));
         };
 
         // FIXME: Support ftruncate64 for all FDs
@@ -1307,14 +1278,12 @@
                 interp_ok(Scalar::from_i32(result))
             } else {
                 drop(fd);
-                this.set_last_error(LibcError("EINVAL"))?;
-                interp_ok(Scalar::from_i32(-1))
+                this.set_last_error_and_return_i32(LibcError("EINVAL"))
             }
         } else {
             drop(fd);
             // The file is not writable
-            this.set_last_error(LibcError("EINVAL"))?;
-            interp_ok(Scalar::from_i32(-1))
+            this.set_last_error_and_return_i32(LibcError("EINVAL"))
         }
     }
 
@@ -1332,7 +1301,7 @@
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`fsync`", reject_with)?;
             // Set error code as "EBADF" (bad fd)
-            return interp_ok(Scalar::from_i32(this.fd_not_found()?));
+            return this.set_last_error_and_return_i32(LibcError("EBADF"));
         }
 
         self.ffullsync_fd(fd)
@@ -1341,7 +1310,7 @@
     fn ffullsync_fd(&mut self, fd_num: i32) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_mut();
         let Some(fd) = this.machine.fds.get(fd_num) else {
-            return interp_ok(Scalar::from_i32(this.fd_not_found()?));
+            return this.set_last_error_and_return_i32(LibcError("EBADF"));
         };
         // Only regular files support synchronization.
         let FileHandle { file, writable } = fd.downcast::<FileHandle>().ok_or_else(|| {
@@ -1361,11 +1330,11 @@
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`fdatasync`", reject_with)?;
             // Set error code as "EBADF" (bad fd)
-            return interp_ok(Scalar::from_i32(this.fd_not_found()?));
+            return this.set_last_error_and_return_i32(LibcError("EBADF"));
         }
 
         let Some(fd) = this.machine.fds.get(fd) else {
-            return interp_ok(Scalar::from_i32(this.fd_not_found()?));
+            return this.set_last_error_and_return_i32(LibcError("EBADF"));
         };
         // Only regular files support synchronization.
         let FileHandle { file, writable } = fd.downcast::<FileHandle>().ok_or_else(|| {
@@ -1391,26 +1360,24 @@
         let flags = this.read_scalar(flags_op)?.to_i32()?;
 
         if offset < 0 || nbytes < 0 {
-            this.set_last_error(LibcError("EINVAL"))?;
-            return interp_ok(Scalar::from_i32(-1));
+            return this.set_last_error_and_return_i32(LibcError("EINVAL"));
         }
         let allowed_flags = this.eval_libc_i32("SYNC_FILE_RANGE_WAIT_BEFORE")
             | this.eval_libc_i32("SYNC_FILE_RANGE_WRITE")
             | this.eval_libc_i32("SYNC_FILE_RANGE_WAIT_AFTER");
         if flags & allowed_flags != flags {
-            this.set_last_error(LibcError("EINVAL"))?;
-            return interp_ok(Scalar::from_i32(-1));
+            return this.set_last_error_and_return_i32(LibcError("EINVAL"));
         }
 
         // Reject if isolation is enabled.
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`sync_file_range`", reject_with)?;
             // Set error code as "EBADF" (bad fd)
-            return interp_ok(Scalar::from_i32(this.fd_not_found()?));
+            return this.set_last_error_and_return_i32(LibcError("EBADF"));
         }
 
         let Some(fd) = this.machine.fds.get(fd) else {
-            return interp_ok(Scalar::from_i32(this.fd_not_found()?));
+            return this.set_last_error_and_return_i32(LibcError("EBADF"));
         };
         // Only regular files support synchronization.
         let FileHandle { file, writable } = fd.downcast::<FileHandle>().ok_or_else(|| {
@@ -1436,8 +1403,7 @@
         // Reject if isolation is enabled.
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`readlink`", reject_with)?;
-            let eacc = this.eval_libc("EACCES");
-            this.set_last_error(eacc)?;
+            this.set_last_error(LibcError("EACCES"))?;
             return interp_ok(-1);
         }
 
@@ -1475,11 +1441,11 @@
             if fd.is_tty(this.machine.communicate()) {
                 return interp_ok(Scalar::from_i32(1));
             } else {
-                this.eval_libc("ENOTTY")
+                LibcError("ENOTTY")
             }
         } else {
             // FD does not exist
-            this.eval_libc("EBADF")
+            LibcError("EBADF")
         };
         this.set_last_error(error)?;
         interp_ok(Scalar::from_i32(0))
@@ -1499,8 +1465,7 @@
         // Reject if isolation is enabled.
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`realpath`", reject_with)?;
-            let eacc = this.eval_libc("EACCES");
-            this.set_last_error(eacc)?;
+            this.set_last_error(LibcError("EACCES"))?;
             return interp_ok(Scalar::from_target_usize(0, this));
         }
 
@@ -1530,8 +1495,7 @@
                         // Note that we do not explicitly handle `FILENAME_MAX`
                         // (different from `PATH_MAX` above) as it is Linux-specific and
                         // seems like a bit of a mess anyway: <https://eklitzke.org/path-max-is-tricky>.
-                        let enametoolong = this.eval_libc("ENAMETOOLONG");
-                        this.set_last_error(enametoolong)?;
+                        this.set_last_error(LibcError("ENAMETOOLONG"))?;
                         return interp_ok(Scalar::from_target_usize(0, this));
                     }
                     processed_ptr
@@ -1574,9 +1538,7 @@
         // Reject if isolation is enabled.
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`mkstemp`", reject_with)?;
-            let eacc = this.eval_libc("EACCES");
-            this.set_last_error(eacc)?;
-            return interp_ok(Scalar::from_i32(-1));
+            return this.set_last_error_and_return_i32(LibcError("EACCES"));
         }
 
         // Get the bytes of the suffix we expect in _target_ encoding.
@@ -1592,8 +1554,7 @@
 
         // If we don't find the suffix, it is an error.
         if last_six_char_bytes != suffix_bytes {
-            this.set_last_error(LibcError("EINVAL"))?;
-            return interp_ok(Scalar::from_i32(-1));
+            return this.set_last_error_and_return_i32(LibcError("EINVAL"));
         }
 
         // At this point we know we have 6 ASCII 'X' characters as a suffix.
@@ -1658,17 +1619,14 @@
                         _ => {
                             // "On error, -1 is returned, and errno is set to
                             // indicate the error"
-                            this.set_last_error(e)?;
-                            return interp_ok(Scalar::from_i32(-1));
+                            return this.set_last_error_and_return_i32(e);
                         }
                     },
             }
         }
 
         // We ran out of attempts to create the file, return an error.
-        let eexist = this.eval_libc("EEXIST");
-        this.set_last_error(eexist)?;
-        interp_ok(Scalar::from_i32(-1))
+        this.set_last_error_and_return_i32(LibcError("EEXIST"))
     }
 }
 
@@ -1702,7 +1660,7 @@
         ecx: &mut MiriInterpCx<'tcx>,
         path: &Path,
         follow_symlink: bool,
-    ) -> InterpResult<'tcx, Option<FileMetadata>> {
+    ) -> InterpResult<'tcx, Result<FileMetadata, IoError>> {
         let metadata =
             if follow_symlink { std::fs::metadata(path) } else { std::fs::symlink_metadata(path) };
 
@@ -1712,9 +1670,9 @@
     fn from_fd_num<'tcx>(
         ecx: &mut MiriInterpCx<'tcx>,
         fd_num: i32,
-    ) -> InterpResult<'tcx, Option<FileMetadata>> {
+    ) -> InterpResult<'tcx, Result<FileMetadata, IoError>> {
         let Some(fd) = ecx.machine.fds.get(fd_num) else {
-            return ecx.fd_not_found().map(|_: i32| None);
+            return interp_ok(Err(LibcError("EBADF")));
         };
 
         let file = &fd
@@ -1734,12 +1692,11 @@
     fn from_meta<'tcx>(
         ecx: &mut MiriInterpCx<'tcx>,
         metadata: Result<std::fs::Metadata, std::io::Error>,
-    ) -> InterpResult<'tcx, Option<FileMetadata>> {
+    ) -> InterpResult<'tcx, Result<FileMetadata, IoError>> {
         let metadata = match metadata {
             Ok(metadata) => metadata,
             Err(e) => {
-                ecx.set_last_error(e)?;
-                return interp_ok(None);
+                return interp_ok(Err(e.into()));
             }
         };
 
@@ -1762,6 +1719,6 @@
         let modified = extract_sec_and_nsec(metadata.modified())?;
 
         // FIXME: Provide more fields using platform specific methods.
-        interp_ok(Some(FileMetadata { mode, size, created, accessed, modified }))
+        interp_ok(Ok(FileMetadata { mode, size, created, accessed, modified }))
     }
 }
diff --git a/src/tools/miri/src/shims/unix/linux/epoll.rs b/src/tools/miri/src/shims/unix/linux/epoll.rs
index cafc716..de10866 100644
--- a/src/tools/miri/src/shims/unix/linux/epoll.rs
+++ b/src/tools/miri/src/shims/unix/linux/epoll.rs
@@ -256,23 +256,14 @@
         let epollhup = this.eval_libc_u32("EPOLLHUP");
         let epollerr = this.eval_libc_u32("EPOLLERR");
 
-        // Fail on unsupported operations.
-        if op & epoll_ctl_add != epoll_ctl_add
-            && op & epoll_ctl_mod != epoll_ctl_mod
-            && op & epoll_ctl_del != epoll_ctl_del
-        {
-            throw_unsup_format!("epoll_ctl: encountered unknown unsupported operation {:#x}", op);
-        }
-
         // Throw EINVAL if epfd and fd have the same value.
         if epfd_value == fd {
-            this.set_last_error(LibcError("EINVAL"))?;
-            return interp_ok(Scalar::from_i32(-1));
+            return this.set_last_error_and_return_i32(LibcError("EINVAL"));
         }
 
         // Check if epfd is a valid epoll file descriptor.
         let Some(epfd) = this.machine.fds.get(epfd_value) else {
-            return interp_ok(Scalar::from_i32(this.fd_not_found()?));
+            return this.set_last_error_and_return_i32(LibcError("EBADF"));
         };
         let epoll_file_description = epfd
             .downcast::<Epoll>()
@@ -282,7 +273,7 @@
         let ready_list = &epoll_file_description.ready_list;
 
         let Some(fd_ref) = this.machine.fds.get(fd) else {
-            return interp_ok(Scalar::from_i32(this.fd_not_found()?));
+            return this.set_last_error_and_return_i32(LibcError("EBADF"));
         };
         let id = fd_ref.get_id();
 
@@ -332,15 +323,11 @@
             // Check the existence of fd in the interest list.
             if op == epoll_ctl_add {
                 if interest_list.contains_key(&epoll_key) {
-                    let eexist = this.eval_libc("EEXIST");
-                    this.set_last_error(eexist)?;
-                    return interp_ok(Scalar::from_i32(-1));
+                    return this.set_last_error_and_return_i32(LibcError("EEXIST"));
                 }
             } else {
                 if !interest_list.contains_key(&epoll_key) {
-                    let enoent = this.eval_libc("ENOENT");
-                    this.set_last_error(enoent)?;
-                    return interp_ok(Scalar::from_i32(-1));
+                    return this.set_last_error_and_return_i32(LibcError("ENOENT"));
                 }
             }
 
@@ -368,15 +355,13 @@
             // Notification will be returned for current epfd if there is event in the file
             // descriptor we registered.
             check_and_update_one_event_interest(&fd_ref, interest, id, this)?;
-            return interp_ok(Scalar::from_i32(0));
+            interp_ok(Scalar::from_i32(0))
         } else if op == epoll_ctl_del {
             let epoll_key = (id, fd);
 
             // Remove epoll_event_interest from interest_list.
             let Some(epoll_interest) = interest_list.remove(&epoll_key) else {
-                let enoent = this.eval_libc("ENOENT");
-                this.set_last_error(enoent)?;
-                return interp_ok(Scalar::from_i32(-1));
+                return this.set_last_error_and_return_i32(LibcError("ENOENT"));
             };
             // All related Weak<EpollEventInterest> will fail to upgrade after the drop.
             drop(epoll_interest);
@@ -394,9 +379,10 @@
                 .unwrap()
                 .retain(|event| event.upgrade().is_some());
 
-            return interp_ok(Scalar::from_i32(0));
+            interp_ok(Scalar::from_i32(0))
+        } else {
+            throw_unsup_format!("unsupported epoll_ctl operation: {op}");
         }
-        interp_ok(Scalar::from_i32(-1))
     }
 
     /// The `epoll_wait()` system call waits for events on the `Epoll`
@@ -447,9 +433,7 @@
         let timeout = this.read_scalar(timeout)?.to_i32()?;
 
         if epfd_value <= 0 || maxevents <= 0 {
-            this.set_last_error(LibcError("EINVAL"))?;
-            this.write_int(-1, dest)?;
-            return interp_ok(());
+            return this.set_last_error_and_return(LibcError("EINVAL"), dest);
         }
 
         // This needs to come after the maxevents value check, or else maxevents.try_into().unwrap()
@@ -460,9 +444,7 @@
         )?;
 
         let Some(epfd) = this.machine.fds.get(epfd_value) else {
-            let result_value: i32 = this.fd_not_found()?;
-            this.write_int(result_value, dest)?;
-            return interp_ok(());
+            return this.set_last_error_and_return(LibcError("EBADF"), dest);
         };
         // Create a weak ref of epfd and pass it to callback so we will make sure that epfd
         // is not close after the thread unblocks.
diff --git a/src/tools/miri/src/shims/unix/linux/foreign_items.rs b/src/tools/miri/src/shims/unix/linux/foreign_items.rs
index e73bde1..6616a98 100644
--- a/src/tools/miri/src/shims/unix/linux/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/linux/foreign_items.rs
@@ -84,6 +84,7 @@
                     this.read_scalar(thread)?,
                     this.read_scalar(name)?,
                     TASK_COMM_LEN,
+                    /* truncate */ false,
                 )?;
                 let res = if res { Scalar::from_u32(0) } else { this.eval_libc("ERANGE") };
                 this.write_scalar(res, dest)?;
diff --git a/src/tools/miri/src/shims/unix/linux/mem.rs b/src/tools/miri/src/shims/unix/linux/mem.rs
index 4f2e17d..d5f9669 100644
--- a/src/tools/miri/src/shims/unix/linux/mem.rs
+++ b/src/tools/miri/src/shims/unix/linux/mem.rs
@@ -24,7 +24,7 @@
         // old_address must be a multiple of the page size
         #[allow(clippy::arithmetic_side_effects)] // PAGE_SIZE is nonzero
         if old_address.addr().bytes() % this.machine.page_size != 0 || new_size == 0 {
-            this.set_last_error(this.eval_libc("EINVAL"))?;
+            this.set_last_error(LibcError("EINVAL"))?;
             return interp_ok(this.eval_libc("MAP_FAILED"));
         }
 
@@ -38,7 +38,7 @@
 
         if flags & this.eval_libc_i32("MREMAP_MAYMOVE") == 0 {
             // We only support MREMAP_MAYMOVE, so not passing the flag is just a failure
-            this.set_last_error(this.eval_libc("EINVAL"))?;
+            this.set_last_error(LibcError("EINVAL"))?;
             return interp_ok(this.eval_libc("MAP_FAILED"));
         }
 
diff --git a/src/tools/miri/src/shims/unix/linux/sync.rs b/src/tools/miri/src/shims/unix/linux/sync.rs
index 941011b..c258be7 100644
--- a/src/tools/miri/src/shims/unix/linux/sync.rs
+++ b/src/tools/miri/src/shims/unix/linux/sync.rs
@@ -63,8 +63,7 @@
             };
 
             if bitset == 0 {
-                this.set_last_error(LibcError("EINVAL"))?;
-                this.write_scalar(Scalar::from_target_isize(-1, this), dest)?;
+                this.set_last_error_and_return(LibcError("EINVAL"), dest)?;
                 return interp_ok(());
             }
 
@@ -75,9 +74,7 @@
                 let duration = match this.read_timespec(&timeout)? {
                     Some(duration) => duration,
                     None => {
-                        this.set_last_error(LibcError("EINVAL"))?;
-                        this.write_scalar(Scalar::from_target_isize(-1, this), dest)?;
-                        return interp_ok(());
+                        return this.set_last_error_and_return(LibcError("EINVAL"), dest);
                     }
                 };
                 let timeout_clock = if op & futex_realtime == futex_realtime {
@@ -153,14 +150,12 @@
                     Scalar::from_target_isize(0, this), // retval_succ
                     Scalar::from_target_isize(-1, this), // retval_timeout
                     dest.clone(),
-                    this.eval_libc("ETIMEDOUT"),
+                    this.eval_libc("ETIMEDOUT"), // errno_timeout
                 );
             } else {
                 // The futex value doesn't match the expected value, so we return failure
                 // right away without sleeping: -1 and errno set to EAGAIN.
-                let eagain = this.eval_libc("EAGAIN");
-                this.set_last_error(eagain)?;
-                this.write_scalar(Scalar::from_target_isize(-1, this), dest)?;
+                return this.set_last_error_and_return(LibcError("EAGAIN"), dest);
             }
         }
         // FUTEX_WAKE: (int *addr, int op = FUTEX_WAKE, int val)
@@ -180,9 +175,7 @@
                 u32::MAX
             };
             if bitset == 0 {
-                this.set_last_error(LibcError("EINVAL"))?;
-                this.write_scalar(Scalar::from_target_isize(-1, this), dest)?;
-                return interp_ok(());
+                return this.set_last_error_and_return(LibcError("EINVAL"), dest);
             }
             // Together with the SeqCst fence in futex_wait, this makes sure that futex_wait
             // will see the latest value on addr which could be changed by our caller
diff --git a/src/tools/miri/src/shims/unix/macos/foreign_items.rs b/src/tools/miri/src/shims/unix/macos/foreign_items.rs
index b199992..cd07bc9 100644
--- a/src/tools/miri/src/shims/unix/macos/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/macos/foreign_items.rs
@@ -181,6 +181,7 @@
                     thread,
                     this.read_scalar(name)?,
                     this.eval_libc("MAXTHREADNAMESIZE").to_target_usize(this)?.try_into().unwrap(),
+                    /* truncate */ false,
                 )? {
                     Scalar::from_u32(0)
                 } else {
diff --git a/src/tools/miri/src/shims/unix/mem.rs b/src/tools/miri/src/shims/unix/mem.rs
index 9273748..9371edf 100644
--- a/src/tools/miri/src/shims/unix/mem.rs
+++ b/src/tools/miri/src/shims/unix/mem.rs
@@ -57,11 +57,11 @@
 
         // First, we do some basic argument validation as required by mmap
         if (flags & (map_private | map_shared)).count_ones() != 1 {
-            this.set_last_error(this.eval_libc("EINVAL"))?;
+            this.set_last_error(LibcError("EINVAL"))?;
             return interp_ok(this.eval_libc("MAP_FAILED"));
         }
         if length == 0 {
-            this.set_last_error(this.eval_libc("EINVAL"))?;
+            this.set_last_error(LibcError("EINVAL"))?;
             return interp_ok(this.eval_libc("MAP_FAILED"));
         }
 
@@ -103,11 +103,11 @@
 
         let align = this.machine.page_align();
         let Some(map_length) = length.checked_next_multiple_of(this.machine.page_size) else {
-            this.set_last_error(this.eval_libc("EINVAL"))?;
+            this.set_last_error(LibcError("EINVAL"))?;
             return interp_ok(this.eval_libc("MAP_FAILED"));
         };
         if map_length > this.target_usize_max() {
-            this.set_last_error(this.eval_libc("EINVAL"))?;
+            this.set_last_error(LibcError("EINVAL"))?;
             return interp_ok(this.eval_libc("MAP_FAILED"));
         }
 
@@ -134,16 +134,14 @@
         // as a dealloc.
         #[allow(clippy::arithmetic_side_effects)] // PAGE_SIZE is nonzero
         if addr.addr().bytes() % this.machine.page_size != 0 {
-            this.set_last_error(this.eval_libc("EINVAL"))?;
-            return interp_ok(Scalar::from_i32(-1));
+            return this.set_last_error_and_return_i32(LibcError("EINVAL"));
         }
 
         let Some(length) = length.checked_next_multiple_of(this.machine.page_size) else {
-            this.set_last_error(this.eval_libc("EINVAL"))?;
-            return interp_ok(Scalar::from_i32(-1));
+            return this.set_last_error_and_return_i32(LibcError("EINVAL"));
         };
         if length > this.target_usize_max() {
-            this.set_last_error(this.eval_libc("EINVAL"))?;
+            this.set_last_error(LibcError("EINVAL"))?;
             return interp_ok(this.eval_libc("MAP_FAILED"));
         }
 
diff --git a/src/tools/miri/src/shims/unix/solarish/foreign_items.rs b/src/tools/miri/src/shims/unix/solarish/foreign_items.rs
index 7f3d0f0..c9c1b01 100644
--- a/src/tools/miri/src/shims/unix/solarish/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/solarish/foreign_items.rs
@@ -30,6 +30,7 @@
                     this.read_scalar(thread)?,
                     this.read_scalar(name)?,
                     max_len,
+                    /* truncate */ false,
                 )?;
                 let res = if res { Scalar::from_u32(0) } else { this.eval_libc("ERANGE") };
                 this.write_scalar(res, dest)?;
diff --git a/src/tools/miri/src/shims/unix/thread.rs b/src/tools/miri/src/shims/unix/thread.rs
index 7f97afc..51256d8 100644
--- a/src/tools/miri/src/shims/unix/thread.rs
+++ b/src/tools/miri/src/shims/unix/thread.rs
@@ -64,23 +64,29 @@
     }
 
     /// Set the name of the specified thread. If the name including the null terminator
-    /// is longer than `name_max_len`, then `false` is returned.
+    /// is longer or equals to `name_max_len`, then if `truncate` is set the truncated name
+    /// is used as the thread name, otherwise `false` is returned.
     fn pthread_setname_np(
         &mut self,
         thread: Scalar,
         name: Scalar,
         name_max_len: usize,
+        truncate: bool,
     ) -> InterpResult<'tcx, bool> {
         let this = self.eval_context_mut();
 
         let thread = thread.to_int(this.libc_ty_layout("pthread_t").size)?;
         let thread = ThreadId::try_from(thread).unwrap();
         let name = name.to_pointer(this)?;
-        let name = this.read_c_str(name)?.to_owned();
+        let mut name = this.read_c_str(name)?.to_owned();
 
         // Comparing with `>=` to account for null terminator.
         if name.len() >= name_max_len {
-            return interp_ok(false);
+            if truncate {
+                name.truncate(name_max_len.saturating_sub(1));
+            } else {
+                return interp_ok(false);
+            }
         }
 
         this.set_thread_name(thread, name);
diff --git a/src/tools/miri/src/shims/windows/sync.rs b/src/tools/miri/src/shims/windows/sync.rs
index f886108..f7566a8 100644
--- a/src/tools/miri/src/shims/windows/sync.rs
+++ b/src/tools/miri/src/shims/windows/sync.rs
@@ -202,7 +202,7 @@
                 Scalar::from_i32(1), // retval_succ
                 Scalar::from_i32(0), // retval_timeout
                 dest.clone(),
-                this.eval_windows("c", "ERROR_TIMEOUT"),
+                this.eval_windows("c", "ERROR_TIMEOUT"), // errno_timeout
             );
         }
 
diff --git a/src/tools/miri/test_dependencies/Cargo.lock b/src/tools/miri/test_dependencies/Cargo.lock
index 64bfc84..0a5e9f6 100644
--- a/src/tools/miri/test_dependencies/Cargo.lock
+++ b/src/tools/miri/test_dependencies/Cargo.lock
@@ -1,6 +1,6 @@
 # This file is automatically @generated by Cargo.
 # It is not intended for manual editing.
-version = 3
+version = 4
 
 [[package]]
 name = "addr2line"
@@ -128,9 +128,9 @@
 
 [[package]]
 name = "libc"
-version = "0.2.158"
+version = "0.2.161"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439"
+checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1"
 
 [[package]]
 name = "linux-raw-sys"
diff --git a/src/tools/miri/tests/fail-dep/libc/prctl-get-name-buffer-too-small.rs b/src/tools/miri/tests/fail-dep/libc/prctl-get-name-buffer-too-small.rs
new file mode 100644
index 0000000..4b73186
--- /dev/null
+++ b/src/tools/miri/tests/fail-dep/libc/prctl-get-name-buffer-too-small.rs
@@ -0,0 +1,10 @@
+//! Ensure we report UB when the buffer is smaller than 16 bytes (even if the thread
+//! name would fit in the smaller buffer).
+//@only-target: android  # Miri supports prctl for Android only
+
+fn main() {
+    let mut buf = vec![0u8; 15];
+    unsafe {
+        libc::prctl(libc::PR_GET_NAME, buf.as_mut_ptr().cast::<libc::c_char>()); //~ ERROR: memory access failed: expected a pointer to 16 bytes of memory, but got alloc952 which is only 15 bytes from the end of the allocation
+    }
+}
diff --git a/src/tools/miri/tests/fail-dep/libc/prctl-get-name-buffer-too-small.stderr b/src/tools/miri/tests/fail-dep/libc/prctl-get-name-buffer-too-small.stderr
new file mode 100644
index 0000000..275a38e
--- /dev/null
+++ b/src/tools/miri/tests/fail-dep/libc/prctl-get-name-buffer-too-small.stderr
@@ -0,0 +1,21 @@
+error: Undefined Behavior: memory access failed: expected a pointer to 16 bytes of memory, but got ALLOC which is only 15 bytes from the end of the allocation
+  --> tests/fail-dep/libc/prctl-threadname.rs:LL:CC
+   |
+LL |         libc::prctl(libc::PR_GET_NAME, buf.as_mut_ptr().cast::<libc::c_char>());
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 16 bytes of memory, but got ALLOC which is only 15 bytes from the end of the allocation
+   |
+   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
+   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+help: ALLOC was allocated here:
+  --> tests/fail-dep/libc/prctl-threadname.rs:LL:CC
+   |
+LL |     let mut buf = vec![0u8; 15];
+   |                   ^^^^^^^^^^^^^
+   = note: BACKTRACE (of the first span):
+   = note: inside `main` at tests/fail-dep/libc/prctl-threadname.rs:LL:CC
+   = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/miri/tests/fail-dep/libc/socketpair-data-race.rs b/src/tools/miri/tests/fail-dep/libc/socketpair-data-race.rs
index f4c0094..55491da 100644
--- a/src/tools/miri/tests/fail-dep/libc/socketpair-data-race.rs
+++ b/src/tools/miri/tests/fail-dep/libc/socketpair-data-race.rs
@@ -1,7 +1,7 @@
 //! This is a regression test for <https://github.com/rust-lang/miri/issues/3947>: we had some
 //! faulty logic around `release_clock` that led to this code not reporting a data race.
 //@ignore-target: windows # no libc socketpair on Windows
-//@compile-flags: -Zmiri-preemption-rate=0
+//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-address-reuse-rate=0
 use std::thread;
 
 fn main() {
diff --git a/src/tools/miri/tests/fail/provenance/ptr_invalid.rs b/src/tools/miri/tests/fail/provenance/ptr_invalid.rs
index d4479f3..c91f4ec 100644
--- a/src/tools/miri/tests/fail/provenance/ptr_invalid.rs
+++ b/src/tools/miri/tests/fail/provenance/ptr_invalid.rs
@@ -1,4 +1,3 @@
-
 // Ensure that a `ptr::without_provenance` ptr is truly invalid.
 fn main() {
     let x = 42;
diff --git a/src/tools/miri/tests/fail/tail_calls/dangling-local-var.rs b/src/tools/miri/tests/fail/tail_calls/dangling-local-var.rs
new file mode 100644
index 0000000..b69f7ee
--- /dev/null
+++ b/src/tools/miri/tests/fail/tail_calls/dangling-local-var.rs
@@ -0,0 +1,16 @@
+#![feature(explicit_tail_calls)]
+#![allow(incomplete_features)]
+
+fn g(x: *const i32) {
+    let _val = unsafe { *x }; //~ERROR: has been freed, so this pointer is dangling
+}
+
+fn f(_x: *const i32) {
+    let local = 0;
+    let ptr = &local as *const i32;
+    become g(ptr)
+}
+
+fn main() {
+    f(std::ptr::null());
+}
diff --git a/src/tools/miri/tests/fail/tail_calls/dangling-local-var.stderr b/src/tools/miri/tests/fail/tail_calls/dangling-local-var.stderr
new file mode 100644
index 0000000..6acd69a
--- /dev/null
+++ b/src/tools/miri/tests/fail/tail_calls/dangling-local-var.stderr
@@ -0,0 +1,30 @@
+error: Undefined Behavior: memory access failed: ALLOC has been freed, so this pointer is dangling
+  --> tests/fail/tail_calls/dangling-local-var.rs:LL:CC
+   |
+LL |     let _val = unsafe { *x };
+   |                         ^^ memory access failed: ALLOC has been freed, so this pointer is dangling
+   |
+   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
+   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+help: ALLOC was allocated here:
+  --> tests/fail/tail_calls/dangling-local-var.rs:LL:CC
+   |
+LL |     let local = 0;
+   |         ^^^^^
+help: ALLOC was deallocated here:
+  --> tests/fail/tail_calls/dangling-local-var.rs:LL:CC
+   |
+LL | }
+   | ^
+   = note: BACKTRACE (of the first span):
+   = note: inside `g` at tests/fail/tail_calls/dangling-local-var.rs:LL:CC
+note: inside `main`
+  --> tests/fail/tail_calls/dangling-local-var.rs:LL:CC
+   |
+LL |     f(std::ptr::null());
+   |     ^^^^^^^^^^^^^^^^^^^
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/miri/tests/pass-dep/libc/prctl-threadname.rs b/src/tools/miri/tests/pass-dep/libc/prctl-threadname.rs
new file mode 100644
index 0000000..87ae375
--- /dev/null
+++ b/src/tools/miri/tests/pass-dep/libc/prctl-threadname.rs
@@ -0,0 +1,74 @@
+//@only-target: android  # Miri supports prctl for Android only
+use std::ffi::{CStr, CString};
+use std::thread;
+
+// The Linux kernel all names 16 bytes long including the null terminator.
+const MAX_THREAD_NAME_LEN: usize = 16;
+
+fn main() {
+    // The short name should be shorter than 16 bytes which POSIX promises
+    // for thread names. The length includes a null terminator.
+    let short_name = "test_named".to_owned();
+    let long_name = std::iter::once("test_named_thread_truncation")
+        .chain(std::iter::repeat(" yada").take(100))
+        .collect::<String>();
+
+    fn set_thread_name(name: &CStr) -> i32 {
+        unsafe { libc::prctl(libc::PR_SET_NAME, name.as_ptr().cast::<libc::c_char>()) }
+    }
+
+    fn get_thread_name(name: &mut [u8]) -> i32 {
+        assert!(name.len() >= MAX_THREAD_NAME_LEN);
+        unsafe { libc::prctl(libc::PR_GET_NAME, name.as_mut_ptr().cast::<libc::c_char>()) }
+    }
+
+    // Set name via Rust API, get it via prctl.
+    let long_name2 = long_name.clone();
+    thread::Builder::new()
+        .name(long_name.clone())
+        .spawn(move || {
+            let mut buf = vec![0u8; MAX_THREAD_NAME_LEN];
+            assert_eq!(get_thread_name(&mut buf), 0);
+            let cstr = CStr::from_bytes_until_nul(&buf).unwrap();
+            let truncated_name = &long_name2[..long_name2.len().min(MAX_THREAD_NAME_LEN - 1)];
+            assert_eq!(cstr.to_bytes(), truncated_name.as_bytes());
+        })
+        .unwrap()
+        .join()
+        .unwrap();
+
+    // Set name via prctl and get it again (short name).
+    thread::Builder::new()
+        .spawn(move || {
+            // Set short thread name.
+            let cstr = CString::new(short_name.clone()).unwrap();
+            assert!(cstr.to_bytes_with_nul().len() <= MAX_THREAD_NAME_LEN); // this should fit
+            assert_eq!(set_thread_name(&cstr), 0);
+
+            let mut buf = vec![0u8; MAX_THREAD_NAME_LEN];
+            assert_eq!(get_thread_name(&mut buf), 0);
+            let cstr = CStr::from_bytes_until_nul(&buf).unwrap();
+            assert_eq!(cstr.to_bytes(), short_name.as_bytes());
+        })
+        .unwrap()
+        .join()
+        .unwrap();
+
+    // Set name via prctl and get it again (long name).
+    thread::Builder::new()
+        .spawn(move || {
+            // Set full thread name.
+            let cstr = CString::new(long_name.clone()).unwrap();
+            assert!(cstr.to_bytes_with_nul().len() > MAX_THREAD_NAME_LEN);
+            // Names are truncated by the Linux kernel.
+            assert_eq!(set_thread_name(&cstr), 0);
+
+            let mut buf = vec![0u8; MAX_THREAD_NAME_LEN];
+            assert_eq!(get_thread_name(&mut buf), 0);
+            let cstr = CStr::from_bytes_until_nul(&buf).unwrap();
+            assert_eq!(cstr.to_bytes(), &long_name.as_bytes()[..(MAX_THREAD_NAME_LEN - 1)]);
+        })
+        .unwrap()
+        .join()
+        .unwrap();
+}
diff --git a/src/tools/miri/tests/pass-dep/libc/pthread-threadname.rs b/src/tools/miri/tests/pass-dep/libc/pthread-threadname.rs
index 404ef7c..0e5b501 100644
--- a/src/tools/miri/tests/pass-dep/libc/pthread-threadname.rs
+++ b/src/tools/miri/tests/pass-dep/libc/pthread-threadname.rs
@@ -1,4 +1,5 @@
 //@ignore-target: windows # No pthreads on Windows
+//@ignore-target: android # No pthread_{get,set}_name on Android
 use std::ffi::{CStr, CString};
 use std::thread;
 
@@ -65,6 +66,22 @@
         }
     }
 
+    // Set name via Rust API, get it via pthreads.
+    let long_name2 = long_name.clone();
+    thread::Builder::new()
+        .name(long_name.clone())
+        .spawn(move || {
+            let mut buf = vec![0u8; long_name2.len() + 1];
+            assert_eq!(get_thread_name(&mut buf), 0);
+            let cstr = CStr::from_bytes_until_nul(&buf).unwrap();
+            let truncated_name = &long_name2[..long_name2.len().min(MAX_THREAD_NAME_LEN - 1)];
+            assert_eq!(cstr.to_bytes(), truncated_name.as_bytes());
+        })
+        .unwrap()
+        .join()
+        .unwrap();
+
+    // Set name via pthread and get it again (short name).
     thread::Builder::new()
         .spawn(move || {
             // Set short thread name.
@@ -130,6 +147,7 @@
         .join()
         .unwrap();
 
+    // Set name via pthread and get it again (long name).
     thread::Builder::new()
         .spawn(move || {
             // Set full thread name.
diff --git a/src/tools/miri/tests/pass/dyn-upcast.rs b/src/tools/miri/tests/pass/dyn-upcast.rs
index 306e9ab..61410f7 100644
--- a/src/tools/miri/tests/pass/dyn-upcast.rs
+++ b/src/tools/miri/tests/pass/dyn-upcast.rs
@@ -433,7 +433,8 @@
 }
 
 fn drop_principal() {
-    use std::{alloc::Layout, any::Any};
+    use std::alloc::Layout;
+    use std::any::Any;
 
     const fn yeet_principal(x: Box<dyn Any + Send>) -> Box<dyn Send> {
         x
diff --git a/src/tools/miri/tests/pass/float.rs b/src/tools/miri/tests/pass/float.rs
index 853d3e8..66843ca 100644
--- a/src/tools/miri/tests/pass/float.rs
+++ b/src/tools/miri/tests/pass/float.rs
@@ -157,13 +157,18 @@
     assert_eq(-{ 5.0_f128 }, -5.0_f128);
 
     // infinities, NaN
-    // FIXME(f16_f128): add when constants and `is_infinite` are available
+    assert!((5.0_f16 / 0.0).is_infinite());
+    assert_ne!({ 5.0_f16 / 0.0 }, { -5.0_f16 / 0.0 });
     assert!((5.0_f32 / 0.0).is_infinite());
     assert_ne!({ 5.0_f32 / 0.0 }, { -5.0_f32 / 0.0 });
     assert!((5.0_f64 / 0.0).is_infinite());
     assert_ne!({ 5.0_f64 / 0.0 }, { 5.0_f64 / -0.0 });
+    assert!((5.0_f128 / 0.0).is_infinite());
+    assert_ne!({ 5.0_f128 / 0.0 }, { 5.0_f128 / -0.0 });
+    assert_ne!(f16::NAN, f16::NAN);
     assert_ne!(f32::NAN, f32::NAN);
     assert_ne!(f64::NAN, f64::NAN);
+    assert_ne!(f128::NAN, f128::NAN);
 
     // negative zero
     let posz = 0.0f16;
@@ -215,9 +220,14 @@
     assert!((black_box(-1.0f128) % 1.0).is_sign_negative());
     assert!((black_box(-1.0f128) % -1.0).is_sign_negative());
 
-    // FIXME(f16_f128): add when `abs` is available
+    assert_eq!((-1.0f16).abs(), 1.0f16);
+    assert_eq!(34.2f16.abs(), 34.2f16);
     assert_eq!((-1.0f32).abs(), 1.0f32);
+    assert_eq!(34.2f32.abs(), 34.2f32);
+    assert_eq!((-1.0f64).abs(), 1.0f64);
     assert_eq!(34.2f64.abs(), 34.2f64);
+    assert_eq!((-1.0f128).abs(), 1.0f128);
+    assert_eq!(34.2f128.abs(), 34.2f128);
 }
 
 /// Test casts from floats to ints and back
@@ -654,6 +664,14 @@
 }
 
 fn ops() {
+    // f16 min/max
+    assert_eq((1.0_f16).max(-1.0), 1.0);
+    assert_eq((1.0_f16).min(-1.0), -1.0);
+    assert_eq(f16::NAN.min(9.0), 9.0);
+    assert_eq(f16::NAN.max(-9.0), -9.0);
+    assert_eq((9.0_f16).min(f16::NAN), 9.0);
+    assert_eq((-9.0_f16).max(f16::NAN), -9.0);
+
     // f32 min/max
     assert_eq((1.0 as f32).max(-1.0), 1.0);
     assert_eq((1.0 as f32).min(-1.0), -1.0);
@@ -670,6 +688,21 @@
     assert_eq((9.0 as f64).min(f64::NAN), 9.0);
     assert_eq((-9.0 as f64).max(f64::NAN), -9.0);
 
+    // f128 min/max
+    assert_eq((1.0_f128).max(-1.0), 1.0);
+    assert_eq((1.0_f128).min(-1.0), -1.0);
+    assert_eq(f128::NAN.min(9.0), 9.0);
+    assert_eq(f128::NAN.max(-9.0), -9.0);
+    assert_eq((9.0_f128).min(f128::NAN), 9.0);
+    assert_eq((-9.0_f128).max(f128::NAN), -9.0);
+
+    // f16 copysign
+    assert_eq(3.5_f16.copysign(0.42), 3.5_f16);
+    assert_eq(3.5_f16.copysign(-0.42), -3.5_f16);
+    assert_eq((-3.5_f16).copysign(0.42), 3.5_f16);
+    assert_eq((-3.5_f16).copysign(-0.42), -3.5_f16);
+    assert!(f16::NAN.copysign(1.0).is_nan());
+
     // f32 copysign
     assert_eq(3.5_f32.copysign(0.42), 3.5_f32);
     assert_eq(3.5_f32.copysign(-0.42), -3.5_f32);
@@ -683,6 +716,13 @@
     assert_eq((-3.5_f64).copysign(0.42), 3.5_f64);
     assert_eq((-3.5_f64).copysign(-0.42), -3.5_f64);
     assert!(f64::NAN.copysign(1.0).is_nan());
+
+    // f128 copysign
+    assert_eq(3.5_f128.copysign(0.42), 3.5_f128);
+    assert_eq(3.5_f128.copysign(-0.42), -3.5_f128);
+    assert_eq((-3.5_f128).copysign(0.42), 3.5_f128);
+    assert_eq((-3.5_f128).copysign(-0.42), -3.5_f128);
+    assert!(f128::NAN.copysign(1.0).is_nan());
 }
 
 /// Tests taken from rustc test suite.
@@ -807,6 +847,18 @@
 
 fn rounding() {
     // Test cases taken from the library's tests for this feature
+    // f16
+    assert_eq(2.5f16.round_ties_even(), 2.0f16);
+    assert_eq(1.0f16.round_ties_even(), 1.0f16);
+    assert_eq(1.3f16.round_ties_even(), 1.0f16);
+    assert_eq(1.5f16.round_ties_even(), 2.0f16);
+    assert_eq(1.7f16.round_ties_even(), 2.0f16);
+    assert_eq(0.0f16.round_ties_even(), 0.0f16);
+    assert_eq((-0.0f16).round_ties_even(), -0.0f16);
+    assert_eq((-1.0f16).round_ties_even(), -1.0f16);
+    assert_eq((-1.3f16).round_ties_even(), -1.0f16);
+    assert_eq((-1.5f16).round_ties_even(), -2.0f16);
+    assert_eq((-1.7f16).round_ties_even(), -2.0f16);
     // f32
     assert_eq(2.5f32.round_ties_even(), 2.0f32);
     assert_eq(1.0f32.round_ties_even(), 1.0f32);
@@ -831,23 +883,59 @@
     assert_eq((-1.3f64).round_ties_even(), -1.0f64);
     assert_eq((-1.5f64).round_ties_even(), -2.0f64);
     assert_eq((-1.7f64).round_ties_even(), -2.0f64);
+    // f128
+    assert_eq(2.5f128.round_ties_even(), 2.0f128);
+    assert_eq(1.0f128.round_ties_even(), 1.0f128);
+    assert_eq(1.3f128.round_ties_even(), 1.0f128);
+    assert_eq(1.5f128.round_ties_even(), 2.0f128);
+    assert_eq(1.7f128.round_ties_even(), 2.0f128);
+    assert_eq(0.0f128.round_ties_even(), 0.0f128);
+    assert_eq((-0.0f128).round_ties_even(), -0.0f128);
+    assert_eq((-1.0f128).round_ties_even(), -1.0f128);
+    assert_eq((-1.3f128).round_ties_even(), -1.0f128);
+    assert_eq((-1.5f128).round_ties_even(), -2.0f128);
+    assert_eq((-1.7f128).round_ties_even(), -2.0f128);
 
+    assert_eq!(3.8f16.floor(), 3.0f16);
+    assert_eq!((-1.1f16).floor(), -2.0f16);
     assert_eq!(3.8f32.floor(), 3.0f32);
+    assert_eq!((-1.1f32).floor(), -2.0f32);
+    assert_eq!(3.8f64.floor(), 3.0f64);
     assert_eq!((-1.1f64).floor(), -2.0f64);
+    assert_eq!(3.8f128.floor(), 3.0f128);
+    assert_eq!((-1.1f128).floor(), -2.0f128);
 
+    assert_eq!(3.8f16.ceil(), 4.0f16);
+    assert_eq!((-2.3f16).ceil(), -2.0f16);
+    assert_eq!(3.8f32.ceil(), 4.0f32);
     assert_eq!((-2.3f32).ceil(), -2.0f32);
     assert_eq!(3.8f64.ceil(), 4.0f64);
+    assert_eq!((-2.3f64).ceil(), -2.0f64);
+    assert_eq!(3.8f128.ceil(), 4.0f128);
+    assert_eq!((-2.3f128).ceil(), -2.0f128);
 
+    assert_eq!(0.1f16.trunc(), 0.0f16);
+    assert_eq!((-0.1f16).trunc(), 0.0f16);
     assert_eq!(0.1f32.trunc(), 0.0f32);
+    assert_eq!((-0.1f32).trunc(), 0.0f32);
+    assert_eq!(0.1f64.trunc(), 0.0f64);
     assert_eq!((-0.1f64).trunc(), 0.0f64);
+    assert_eq!(0.1f128.trunc(), 0.0f128);
+    assert_eq!((-0.1f128).trunc(), 0.0f128);
 
+    assert_eq!(3.3_f16.round(), 3.0);
+    assert_eq!(2.5_f16.round(), 3.0);
     assert_eq!(3.3_f32.round(), 3.0);
     assert_eq!(2.5_f32.round(), 3.0);
     assert_eq!(3.9_f64.round(), 4.0);
     assert_eq!(2.5_f64.round(), 3.0);
+    assert_eq!(3.9_f128.round(), 4.0);
+    assert_eq!(2.5_f128.round(), 3.0);
 }
 
 fn mul_add() {
+    // FIXME(f16_f128): add when supported
+
     assert_eq!(3.0f32.mul_add(2.0f32, 5.0f32), 11.0);
     assert_eq!(0.0f32.mul_add(-2.0, f32::consts::E), f32::consts::E);
     assert_eq!(3.0f64.mul_add(2.0, 5.0), 11.0);
@@ -983,7 +1071,7 @@
     use std::intrinsics::{fadd_fast, fdiv_fast, fmul_fast, frem_fast, fsub_fast};
 
     #[inline(never)]
-    pub fn test_operations_f64(a: f64, b: f64) {
+    pub fn test_operations_f16(a: f16, b: f16) {
         // make sure they all map to the correct operation
         unsafe {
             assert_eq!(fadd_fast(a, b), a + b);
@@ -1006,10 +1094,38 @@
         }
     }
 
-    test_operations_f64(1., 2.);
-    test_operations_f64(10., 5.);
+    #[inline(never)]
+    pub fn test_operations_f64(a: f64, b: f64) {
+        // make sure they all map to the correct operation
+        unsafe {
+            assert_eq!(fadd_fast(a, b), a + b);
+            assert_eq!(fsub_fast(a, b), a - b);
+            assert_eq!(fmul_fast(a, b), a * b);
+            assert_eq!(fdiv_fast(a, b), a / b);
+            assert_eq!(frem_fast(a, b), a % b);
+        }
+    }
+
+    #[inline(never)]
+    pub fn test_operations_f128(a: f128, b: f128) {
+        // make sure they all map to the correct operation
+        unsafe {
+            assert_eq!(fadd_fast(a, b), a + b);
+            assert_eq!(fsub_fast(a, b), a - b);
+            assert_eq!(fmul_fast(a, b), a * b);
+            assert_eq!(fdiv_fast(a, b), a / b);
+            assert_eq!(frem_fast(a, b), a % b);
+        }
+    }
+
+    test_operations_f16(11., 2.);
+    test_operations_f16(10., 15.);
     test_operations_f32(11., 2.);
     test_operations_f32(10., 15.);
+    test_operations_f64(1., 2.);
+    test_operations_f64(10., 5.);
+    test_operations_f128(1., 2.);
+    test_operations_f128(10., 5.);
 }
 
 fn test_algebraic() {
@@ -1018,7 +1134,7 @@
     };
 
     #[inline(never)]
-    pub fn test_operations_f64(a: f64, b: f64) {
+    pub fn test_operations_f16(a: f16, b: f16) {
         // make sure they all map to the correct operation
         assert_eq!(fadd_algebraic(a, b), a + b);
         assert_eq!(fsub_algebraic(a, b), a - b);
@@ -1037,15 +1153,41 @@
         assert_eq!(frem_algebraic(a, b), a % b);
     }
 
-    test_operations_f64(1., 2.);
-    test_operations_f64(10., 5.);
+    #[inline(never)]
+    pub fn test_operations_f64(a: f64, b: f64) {
+        // make sure they all map to the correct operation
+        assert_eq!(fadd_algebraic(a, b), a + b);
+        assert_eq!(fsub_algebraic(a, b), a - b);
+        assert_eq!(fmul_algebraic(a, b), a * b);
+        assert_eq!(fdiv_algebraic(a, b), a / b);
+        assert_eq!(frem_algebraic(a, b), a % b);
+    }
+
+    #[inline(never)]
+    pub fn test_operations_f128(a: f128, b: f128) {
+        // make sure they all map to the correct operation
+        assert_eq!(fadd_algebraic(a, b), a + b);
+        assert_eq!(fsub_algebraic(a, b), a - b);
+        assert_eq!(fmul_algebraic(a, b), a * b);
+        assert_eq!(fdiv_algebraic(a, b), a / b);
+        assert_eq!(frem_algebraic(a, b), a % b);
+    }
+
+    test_operations_f16(11., 2.);
+    test_operations_f16(10., 15.);
     test_operations_f32(11., 2.);
     test_operations_f32(10., 15.);
+    test_operations_f64(1., 2.);
+    test_operations_f64(10., 5.);
+    test_operations_f128(1., 2.);
+    test_operations_f128(10., 5.);
 }
 
 fn test_fmuladd() {
     use std::intrinsics::{fmuladdf32, fmuladdf64};
 
+    // FIXME(f16_f128): add when supported
+
     #[inline(never)]
     pub fn test_operations_f32(a: f32, b: f32, c: f32) {
         assert_approx_eq!(unsafe { fmuladdf32(a, b, c) }, a * b + c);
diff --git a/src/tools/run-make-support/Cargo.toml b/src/tools/run-make-support/Cargo.toml
index d3605cd..3affa19 100644
--- a/src/tools/run-make-support/Cargo.toml
+++ b/src/tools/run-make-support/Cargo.toml
@@ -13,3 +13,6 @@
 build_helper = { path = "../build_helper" }
 serde_json = "1.0"
 libc = "0.2"
+
+[lib]
+crate-type = ["lib", "dylib"]
diff --git a/src/tools/run-make-support/src/command.rs b/src/tools/run-make-support/src/command.rs
index 6b58173..9e09527 100644
--- a/src/tools/run-make-support/src/command.rs
+++ b/src/tools/run-make-support/src/command.rs
@@ -224,6 +224,12 @@
 impl CompletedProcess {
     #[must_use]
     #[track_caller]
+    pub fn stdout(&self) -> Vec<u8> {
+        self.output.stdout.clone()
+    }
+
+    #[must_use]
+    #[track_caller]
     pub fn stdout_utf8(&self) -> String {
         String::from_utf8(self.output.stdout.clone()).expect("stdout is not valid UTF-8")
     }
@@ -236,11 +242,23 @@
 
     #[must_use]
     #[track_caller]
+    pub fn stderr(&self) -> Vec<u8> {
+        self.output.stderr.clone()
+    }
+
+    #[must_use]
+    #[track_caller]
     pub fn stderr_utf8(&self) -> String {
         String::from_utf8(self.output.stderr.clone()).expect("stderr is not valid UTF-8")
     }
 
     #[must_use]
+    #[track_caller]
+    pub fn invalid_stderr_utf8(&self) -> String {
+        String::from_utf8_lossy(&self.output.stderr.clone()).to_string()
+    }
+
+    #[must_use]
     pub fn status(&self) -> ExitStatus {
         self.output.status
     }
diff --git a/src/tools/run-make-support/src/external_deps/llvm.rs b/src/tools/run-make-support/src/external_deps/llvm.rs
index 38a9ac9..9a6e35d 100644
--- a/src/tools/run-make-support/src/external_deps/llvm.rs
+++ b/src/tools/run-make-support/src/external_deps/llvm.rs
@@ -60,6 +60,18 @@
     LlvmPdbutil::new()
 }
 
+/// Construct a new `llvm-dis` invocation. This assumes that `llvm-dis` is available
+/// at `$LLVM_BIN_DIR/llvm-dis`.
+pub fn llvm_dis() -> LlvmDis {
+    LlvmDis::new()
+}
+
+/// Construct a new `llvm-objcopy` invocation. This assumes that `llvm-objcopy` is available
+/// at `$LLVM_BIN_DIR/llvm-objcopy`.
+pub fn llvm_objcopy() -> LlvmObjcopy {
+    LlvmObjcopy::new()
+}
+
 /// A `llvm-readobj` invocation builder.
 #[derive(Debug)]
 #[must_use]
@@ -123,6 +135,20 @@
     cmd: Command,
 }
 
+/// A `llvm-dis` invocation builder.
+#[derive(Debug)]
+#[must_use]
+pub struct LlvmDis {
+    cmd: Command,
+}
+
+/// A `llvm-objcopy` invocation builder.
+#[derive(Debug)]
+#[must_use]
+pub struct LlvmObjcopy {
+    cmd: Command,
+}
+
 crate::macros::impl_common_helpers!(LlvmReadobj);
 crate::macros::impl_common_helpers!(LlvmProfdata);
 crate::macros::impl_common_helpers!(LlvmFilecheck);
@@ -132,6 +158,8 @@
 crate::macros::impl_common_helpers!(LlvmBcanalyzer);
 crate::macros::impl_common_helpers!(LlvmDwarfdump);
 crate::macros::impl_common_helpers!(LlvmPdbutil);
+crate::macros::impl_common_helpers!(LlvmDis);
+crate::macros::impl_common_helpers!(LlvmObjcopy);
 
 /// Generate the path to the bin directory of LLVM.
 #[must_use]
@@ -390,3 +418,41 @@
         self
     }
 }
+
+impl LlvmObjcopy {
+    /// Construct a new `llvm-objcopy` invocation. This assumes that `llvm-objcopy` is available
+    /// at `$LLVM_BIN_DIR/llvm-objcopy`.
+    pub fn new() -> Self {
+        let llvm_objcopy = llvm_bin_dir().join("llvm-objcopy");
+        let cmd = Command::new(llvm_objcopy);
+        Self { cmd }
+    }
+
+    /// Dump the contents of `section` into the file at `path`.
+    #[track_caller]
+    pub fn dump_section<S: AsRef<str>, P: AsRef<Path>>(
+        &mut self,
+        section_name: S,
+        path: P,
+    ) -> &mut Self {
+        self.cmd.arg("--dump-section");
+        self.cmd.arg(format!("{}={}", section_name.as_ref(), path.as_ref().to_str().unwrap()));
+        self
+    }
+}
+
+impl LlvmDis {
+    /// Construct a new `llvm-dis` invocation. This assumes that `llvm-dis` is available
+    /// at `$LLVM_BIN_DIR/llvm-dis`.
+    pub fn new() -> Self {
+        let llvm_dis = llvm_bin_dir().join("llvm-dis");
+        let cmd = Command::new(llvm_dis);
+        Self { cmd }
+    }
+
+    /// Provide an input file.
+    pub fn input<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
+        self.cmd.arg(path.as_ref());
+        self
+    }
+}
diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs
index 15d813c..368b98c 100644
--- a/src/tools/run-make-support/src/lib.rs
+++ b/src/tools/run-make-support/src/lib.rs
@@ -49,14 +49,17 @@
 
 // These rely on external dependencies.
 pub use cc::{cc, cxx, extra_c_flags, extra_cxx_flags, Cc};
-pub use c_build::{build_native_dynamic_lib, build_native_static_lib, build_native_static_lib_optimized, build_native_static_lib_cxx};
+pub use c_build::{
+    build_native_dynamic_lib, build_native_static_lib, build_native_static_lib_cxx,
+    build_native_static_lib_optimized,
+};
 pub use cargo::cargo;
 pub use clang::{clang, Clang};
 pub use htmldocck::htmldocck;
 pub use llvm::{
-    llvm_ar, llvm_bcanalyzer, llvm_dwarfdump, llvm_filecheck, llvm_nm, llvm_objdump, llvm_profdata,
-    llvm_readobj, LlvmAr, LlvmBcanalyzer, LlvmDwarfdump, LlvmFilecheck, LlvmNm, LlvmObjdump,
-    LlvmProfdata, LlvmReadobj,
+    llvm_ar, llvm_bcanalyzer, llvm_dis, llvm_dwarfdump, llvm_filecheck, llvm_nm, llvm_objcopy,
+    llvm_objdump, llvm_profdata, llvm_readobj, LlvmAr, LlvmBcanalyzer, LlvmDis, LlvmDwarfdump,
+    LlvmFilecheck, LlvmNm, LlvmObjcopy, LlvmObjdump, LlvmProfdata, LlvmReadobj,
 };
 pub use python::python_command;
 pub use rustc::{aux_build, bare_rustc, rustc, rustc_path, Rustc};
diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock
index 8bbccc8..695c37f 100644
--- a/src/tools/rust-analyzer/Cargo.lock
+++ b/src/tools/rust-analyzer/Cargo.lock
@@ -164,6 +164,7 @@
  "rustc-hash 2.0.0",
  "syntax",
  "syntax-bridge",
+ "tracing",
  "tt",
 ]
 
@@ -671,7 +672,6 @@
  "syntax",
  "test-fixture",
  "test-utils",
- "text-edit",
  "toolchain",
  "tracing",
  "triomphe",
@@ -693,7 +693,6 @@
  "syntax",
  "test-fixture",
  "test-utils",
- "text-edit",
  "tracing",
 ]
 
@@ -712,7 +711,6 @@
  "syntax",
  "test-fixture",
  "test-utils",
- "text-edit",
  "tracing",
 ]
 
@@ -744,7 +742,6 @@
  "syntax",
  "test-fixture",
  "test-utils",
- "text-edit",
  "tracing",
  "triomphe",
 ]
@@ -766,7 +763,6 @@
  "syntax",
  "test-fixture",
  "test-utils",
- "text-edit",
  "tracing",
 ]
 
@@ -785,7 +781,6 @@
  "syntax",
  "test-fixture",
  "test-utils",
- "text-edit",
  "triomphe",
 ]
 
@@ -1498,9 +1493,9 @@
 
 [[package]]
 name = "ra-ap-rustc_abi"
-version = "0.73.0"
+version = "0.75.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "879ece0781e3c1cb670b9f29775c81a43a16db789d1296fad6bc5c74065b2fac"
+checksum = "d5bc2cfc7264d84215a08875ef90a1d35f76b5c9ad1993515d2da7e4e40b2b4b"
 dependencies = [
  "bitflags 2.6.0",
  "ra-ap-rustc_index",
@@ -1509,9 +1504,9 @@
 
 [[package]]
 name = "ra-ap-rustc_index"
-version = "0.73.0"
+version = "0.75.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6910087ff89bb9f3db114bfcd86b5139042731fe7278d3ff4ceaa69a140154a7"
+checksum = "e8929140697812e5dd09e19cf446d85146332363f0dbc125d4214834c34ead96"
 dependencies = [
  "arrayvec",
  "ra-ap-rustc_index_macros",
@@ -1520,9 +1515,9 @@
 
 [[package]]
 name = "ra-ap-rustc_index_macros"
-version = "0.73.0"
+version = "0.75.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3b6f7bd12b678fbb37444ba77f3b0cfc13b7394a6dc7b0c799491fc9df0a9997"
+checksum = "514a3f5d04c8b4a2750f29746cc9abb1f78deb7e72e4ad1dc95bbc608f3db157"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1531,9 +1526,9 @@
 
 [[package]]
 name = "ra-ap-rustc_lexer"
-version = "0.73.0"
+version = "0.75.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "119bc05b5b6bc3e7f5b67ce8b8080e185da94bd83c447f91b6b3f3ecf60cbab1"
+checksum = "276fcb1205da071a0cd64416f3f0e198043c11f176c5b501a45dbf0cb33979f2"
 dependencies = [
  "unicode-properties",
  "unicode-xid",
@@ -1541,9 +1536,9 @@
 
 [[package]]
 name = "ra-ap-rustc_parse_format"
-version = "0.73.0"
+version = "0.75.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "70ed6150ae71d905c064dc88d7824ebb0fa81083f45d7477cba7b57176f2f635"
+checksum = "961b30b22cfac296b14b72e9f95e79c16cebc8c926872755fb1568a6c4243a62"
 dependencies = [
  "ra-ap-rustc_index",
  "ra-ap-rustc_lexer",
@@ -1551,9 +1546,9 @@
 
 [[package]]
 name = "ra-ap-rustc_pattern_analysis"
-version = "0.73.0"
+version = "0.75.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6e830862a0ec85fce211d34735315686bb8d6a12d418d6d735fb534aa1cd3293"
+checksum = "614232513814a4b714fea7f11345d31c0c277bca3089bb6ca1ec20870bfc022a"
 dependencies = [
  "ra-ap-rustc_index",
  "rustc-hash 2.0.0",
@@ -1979,7 +1974,6 @@
  "smol_str",
  "stdx",
  "test-utils",
- "text-edit",
  "tracing",
  "triomphe",
 ]
@@ -2028,14 +2022,6 @@
 ]
 
 [[package]]
-name = "text-edit"
-version = "0.0.0"
-dependencies = [
- "itertools",
- "text-size",
-]
-
-[[package]]
 name = "text-size"
 version = "1.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml
index 4e6861d..3aa93b7 100644
--- a/src/tools/rust-analyzer/Cargo.toml
+++ b/src/tools/rust-analyzer/Cargo.toml
@@ -79,17 +79,16 @@
 stdx = { path = "./crates/stdx", version = "0.0.0" }
 syntax = { path = "./crates/syntax", version = "0.0.0" }
 syntax-bridge = { path = "./crates/syntax-bridge", version = "0.0.0" }
-text-edit = { path = "./crates/text-edit", version = "0.0.0" }
 toolchain = { path = "./crates/toolchain", version = "0.0.0" }
 tt = { path = "./crates/tt", version = "0.0.0" }
 vfs-notify = { path = "./crates/vfs-notify", version = "0.0.0" }
 vfs = { path = "./crates/vfs", version = "0.0.0" }
 
-ra-ap-rustc_lexer = { version = "0.73", default-features = false }
-ra-ap-rustc_parse_format = { version = "0.73", default-features = false }
-ra-ap-rustc_index = { version = "0.73", default-features = false }
-ra-ap-rustc_abi = { version = "0.73", default-features = false }
-ra-ap-rustc_pattern_analysis = { version = "0.73", default-features = false }
+ra-ap-rustc_lexer = { version = "0.75", default-features = false }
+ra-ap-rustc_parse_format = { version = "0.75", default-features = false }
+ra-ap-rustc_index = { version = "0.75", default-features = false }
+ra-ap-rustc_abi = { version = "0.75", default-features = false }
+ra-ap-rustc_pattern_analysis = { version = "0.75", default-features = false }
 
 # local crates that aren't published to crates.io. These should not have versions.
 test-fixture = { path = "./crates/test-fixture" }
diff --git a/src/tools/rust-analyzer/crates/cfg/Cargo.toml b/src/tools/rust-analyzer/crates/cfg/Cargo.toml
index 29b7ad6..040bddbd 100644
--- a/src/tools/rust-analyzer/crates/cfg/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/cfg/Cargo.toml
@@ -14,6 +14,7 @@
 
 [dependencies]
 rustc-hash.workspace = true
+tracing.workspace = true
 
 # locals deps
 tt = { workspace = true, optional = true }
diff --git a/src/tools/rust-analyzer/crates/cfg/src/lib.rs b/src/tools/rust-analyzer/crates/cfg/src/lib.rs
index c2d4008..6a6213a 100644
--- a/src/tools/rust-analyzer/crates/cfg/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/cfg/src/lib.rs
@@ -9,7 +9,7 @@
 
 use rustc_hash::FxHashSet;
 
-use intern::Symbol;
+use intern::{sym, Symbol};
 
 pub use cfg_expr::{CfgAtom, CfgExpr};
 pub use dnf::DnfExpr;
@@ -24,11 +24,17 @@
 /// of key and value in `key_values`.
 ///
 /// See: <https://doc.rust-lang.org/reference/conditional-compilation.html#set-configuration-options>
-#[derive(Clone, PartialEq, Eq, Default)]
+#[derive(Clone, PartialEq, Eq)]
 pub struct CfgOptions {
     enabled: FxHashSet<CfgAtom>,
 }
 
+impl Default for CfgOptions {
+    fn default() -> Self {
+        Self { enabled: FxHashSet::from_iter([CfgAtom::Flag(sym::true_.clone())]) }
+    }
+}
+
 impl fmt::Debug for CfgOptions {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         let mut items = self
@@ -54,23 +60,37 @@
     }
 
     pub fn insert_atom(&mut self, key: Symbol) {
-        self.enabled.insert(CfgAtom::Flag(key));
+        self.insert_any_atom(CfgAtom::Flag(key));
     }
 
     pub fn insert_key_value(&mut self, key: Symbol, value: Symbol) {
-        self.enabled.insert(CfgAtom::KeyValue { key, value });
+        self.insert_any_atom(CfgAtom::KeyValue { key, value });
     }
 
     pub fn apply_diff(&mut self, diff: CfgDiff) {
         for atom in diff.enable {
-            self.enabled.insert(atom);
+            self.insert_any_atom(atom);
         }
 
         for atom in diff.disable {
+            let (CfgAtom::Flag(sym) | CfgAtom::KeyValue { key: sym, .. }) = &atom;
+            if *sym == sym::true_ || *sym == sym::false_ {
+                tracing::error!("cannot remove `true` or `false` from cfg");
+                continue;
+            }
             self.enabled.remove(&atom);
         }
     }
 
+    fn insert_any_atom(&mut self, atom: CfgAtom) {
+        let (CfgAtom::Flag(sym) | CfgAtom::KeyValue { key: sym, .. }) = &atom;
+        if *sym == sym::true_ || *sym == sym::false_ {
+            tracing::error!("cannot insert `true` or `false` to cfg");
+            return;
+        }
+        self.enabled.insert(atom);
+    }
+
     pub fn get_cfg_keys(&self) -> impl Iterator<Item = &Symbol> {
         self.enabled.iter().map(|it| match it {
             CfgAtom::Flag(key) => key,
@@ -88,7 +108,7 @@
 
 impl Extend<CfgAtom> for CfgOptions {
     fn extend<T: IntoIterator<Item = CfgAtom>>(&mut self, iter: T) {
-        iter.into_iter().for_each(|cfg_flag| _ = self.enabled.insert(cfg_flag));
+        iter.into_iter().for_each(|cfg_flag| self.insert_any_atom(cfg_flag));
     }
 }
 
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs
index 0b108b5..1ab49e9 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs
@@ -407,7 +407,7 @@
                 let method_name = e.name_ref().map(|nr| nr.as_name()).unwrap_or_else(Name::missing);
                 let generic_args = e
                     .generic_arg_list()
-                    .and_then(|it| GenericArgs::from_ast(&self.ctx(), it))
+                    .and_then(|it| GenericArgs::from_ast(&mut self.ctx(), it))
                     .map(Box::new);
                 self.alloc_expr(
                     Expr::MethodCall { receiver, method_name, args, generic_args },
@@ -533,7 +533,7 @@
             ast::Expr::TryExpr(e) => self.collect_try_operator(syntax_ptr, e),
             ast::Expr::CastExpr(e) => {
                 let expr = self.collect_expr_opt(e.expr());
-                let type_ref = TypeRef::from_ast_opt(&self.ctx(), e.ty());
+                let type_ref = TypeRef::from_ast_opt(&mut self.ctx(), e.ty());
                 self.alloc_expr(Expr::Cast { expr, type_ref }, syntax_ptr)
             }
             ast::Expr::RefExpr(e) => {
@@ -572,13 +572,15 @@
                     arg_types.reserve_exact(num_params);
                     for param in pl.params() {
                         let pat = this.collect_pat_top(param.pat());
-                        let type_ref = param.ty().map(|it| TypeRef::from_ast(&this.ctx(), it));
+                        let type_ref = param.ty().map(|it| TypeRef::from_ast(&mut this.ctx(), it));
                         args.push(pat);
                         arg_types.push(type_ref);
                     }
                 }
-                let ret_type =
-                    e.ret_type().and_then(|r| r.ty()).map(|it| TypeRef::from_ast(&this.ctx(), it));
+                let ret_type = e
+                    .ret_type()
+                    .and_then(|r| r.ty())
+                    .map(|it| TypeRef::from_ast(&mut this.ctx(), it));
 
                 let prev_is_lowering_coroutine = mem::take(&mut this.is_lowering_coroutine);
                 let prev_try_block_label = this.current_try_block_label.take();
@@ -705,7 +707,7 @@
             ast::Expr::UnderscoreExpr(_) => self.alloc_expr(Expr::Underscore, syntax_ptr),
             ast::Expr::AsmExpr(e) => self.lower_inline_asm(e, syntax_ptr),
             ast::Expr::OffsetOfExpr(e) => {
-                let container = TypeRef::from_ast_opt(&self.ctx(), e.ty());
+                let container = TypeRef::from_ast_opt(&mut self.ctx(), e.ty());
                 let fields = e.fields().map(|it| it.as_name()).collect();
                 self.alloc_expr(Expr::OffsetOf(OffsetOf { container, fields }), syntax_ptr)
             }
@@ -1317,7 +1319,7 @@
                     return;
                 }
                 let pat = self.collect_pat_top(stmt.pat());
-                let type_ref = stmt.ty().map(|it| TypeRef::from_ast(&self.ctx(), it));
+                let type_ref = stmt.ty().map(|it| TypeRef::from_ast(&mut self.ctx(), it));
                 let initializer = stmt.initializer().map(|e| self.collect_expr(e));
                 let else_branch = stmt
                     .let_else()
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expander.rs b/src/tools/rust-analyzer/crates/hir-def/src/expander.rs
index d430733..5315c1c 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expander.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expander.rs
@@ -161,14 +161,14 @@
         types_map: &mut TypesMap,
         types_source_map: &mut TypesSourceMap,
     ) -> Option<Path> {
-        let ctx = LowerCtx::with_span_map_cell(
+        let mut ctx = LowerCtx::with_span_map_cell(
             db,
             self.current_file_id,
             self.span_map.clone(),
             types_map,
             types_source_map,
         );
-        Path::from_src(&ctx, path)
+        Path::from_src(&mut ctx, path)
     }
 
     fn within_limit<F, T: ast::AstNode>(
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/generics.rs b/src/tools/rust-analyzer/crates/hir-def/src/generics.rs
index 6b79850..11e9bb0 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/generics.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/generics.rs
@@ -451,7 +451,7 @@
 impl GenericParamsCollector {
     pub(crate) fn fill(
         &mut self,
-        lower_ctx: &LowerCtx<'_>,
+        lower_ctx: &mut LowerCtx<'_>,
         node: &dyn HasGenericParams,
         add_param_attrs: impl FnMut(
             Either<LocalTypeOrConstParamId, LocalLifetimeParamId>,
@@ -468,7 +468,7 @@
 
     pub(crate) fn fill_bounds(
         &mut self,
-        lower_ctx: &LowerCtx<'_>,
+        lower_ctx: &mut LowerCtx<'_>,
         type_bounds: Option<ast::TypeBoundList>,
         target: Either<TypeRefId, LifetimeRef>,
     ) {
@@ -479,7 +479,7 @@
 
     fn fill_params(
         &mut self,
-        lower_ctx: &LowerCtx<'_>,
+        lower_ctx: &mut LowerCtx<'_>,
         params: ast::GenericParamList,
         mut add_param_attrs: impl FnMut(
             Either<LocalTypeOrConstParamId, LocalLifetimeParamId>,
@@ -535,7 +535,11 @@
         }
     }
 
-    fn fill_where_predicates(&mut self, lower_ctx: &LowerCtx<'_>, where_clause: ast::WhereClause) {
+    fn fill_where_predicates(
+        &mut self,
+        lower_ctx: &mut LowerCtx<'_>,
+        where_clause: ast::WhereClause,
+    ) {
         for pred in where_clause.predicates() {
             let target = if let Some(type_ref) = pred.ty() {
                 Either::Left(TypeRef::from_ast(lower_ctx, type_ref))
@@ -569,7 +573,7 @@
 
     fn add_where_predicate_from_bound(
         &mut self,
-        lower_ctx: &LowerCtx<'_>,
+        lower_ctx: &mut LowerCtx<'_>,
         bound: ast::TypeBound,
         hrtb_lifetimes: Option<&[Name]>,
         target: Either<TypeRefId, LifetimeRef>,
@@ -670,8 +674,9 @@
                 {
                     let (mut macro_types_map, mut macro_types_source_map) =
                         (TypesMap::default(), TypesSourceMap::default());
-                    let ctx = expander.ctx(db, &mut macro_types_map, &mut macro_types_source_map);
-                    let type_ref = TypeRef::from_ast(&ctx, expanded.tree());
+                    let mut ctx =
+                        expander.ctx(db, &mut macro_types_map, &mut macro_types_source_map);
+                    let type_ref = TypeRef::from_ast(&mut ctx, expanded.tree());
                     self.fill_implicit_impl_trait_args(
                         db,
                         generics_types_map,
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs
index 2582340..4d83ef9 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs
@@ -98,7 +98,7 @@
 
 impl TraitRef {
     /// Converts an `ast::PathType` to a `hir::TraitRef`.
-    pub(crate) fn from_ast(ctx: &LowerCtx<'_>, node: ast::Type) -> Option<Self> {
+    pub(crate) fn from_ast(ctx: &mut LowerCtx<'_>, node: ast::Type) -> Option<Self> {
         // FIXME: Use `Path::from_src`
         match node {
             ast::Type::PathType(path) => {
@@ -240,7 +240,7 @@
 
 impl TypeRef {
     /// Converts an `ast::TypeRef` to a `hir::TypeRef`.
-    pub fn from_ast(ctx: &LowerCtx<'_>, node: ast::Type) -> TypeRefId {
+    pub fn from_ast(ctx: &mut LowerCtx<'_>, node: ast::Type) -> TypeRefId {
         let ty = match &node {
             ast::Type::ParenType(inner) => return TypeRef::from_ast_opt(ctx, inner.ty()),
             ast::Type::TupleType(inner) => TypeRef::Tuple(EmptyOptimizedThinVec::from_iter(
@@ -321,8 +321,9 @@
                     // Disallow nested impl traits
                     TypeRef::Error
                 } else {
-                    let _guard = ctx.outer_impl_trait_scope(true);
-                    TypeRef::ImplTrait(type_bounds_from_ast(ctx, inner.type_bound_list()))
+                    ctx.with_outer_impl_trait_scope(true, |ctx| {
+                        TypeRef::ImplTrait(type_bounds_from_ast(ctx, inner.type_bound_list()))
+                    })
                 }
             }
             ast::Type::DynTraitType(inner) => {
@@ -336,7 +337,7 @@
         ctx.alloc_type_ref(ty, AstPtr::new(&node))
     }
 
-    pub(crate) fn from_ast_opt(ctx: &LowerCtx<'_>, node: Option<ast::Type>) -> TypeRefId {
+    pub(crate) fn from_ast_opt(ctx: &mut LowerCtx<'_>, node: Option<ast::Type>) -> TypeRefId {
         match node {
             Some(node) => TypeRef::from_ast(ctx, node),
             None => ctx.alloc_error_type(),
@@ -410,7 +411,7 @@
 }
 
 pub(crate) fn type_bounds_from_ast(
-    lower_ctx: &LowerCtx<'_>,
+    lower_ctx: &mut LowerCtx<'_>,
     type_bounds_opt: Option<ast::TypeBoundList>,
 ) -> ThinVec<TypeBound> {
     if let Some(type_bounds) = type_bounds_opt {
@@ -423,8 +424,8 @@
 }
 
 impl TypeBound {
-    pub(crate) fn from_ast(ctx: &LowerCtx<'_>, node: ast::TypeBound) -> Self {
-        let lower_path_type = |path_type: ast::PathType| ctx.lower_path(path_type.path()?);
+    pub(crate) fn from_ast(ctx: &mut LowerCtx<'_>, node: ast::TypeBound) -> Self {
+        let mut lower_path_type = |path_type: ast::PathType| ctx.lower_path(path_type.path()?);
 
         match node.kind() {
             ast::TypeBoundKind::PathType(path_type) => {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs
index b39a3fe..b5bf2fe 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs
@@ -1166,6 +1166,11 @@
         self.expand_impl(None, &mut cb)
     }
 
+    /// The [`UseTreeKind`] of this `UseTree`.
+    pub fn kind(&self) -> &UseTreeKind {
+        &self.kind
+    }
+
     fn expand_impl(
         &self,
         prefix: Option<ModPath>,
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs
index bd17fce..d519c17 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs
@@ -234,11 +234,11 @@
     fn lower_struct(&mut self, strukt: &ast::Struct) -> Option<FileItemTreeId<Struct>> {
         let (mut types_map, mut types_source_map) =
             (TypesMap::default(), TypesSourceMap::default());
-        let body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
+        let mut body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
         let visibility = self.lower_visibility(strukt);
         let name = strukt.name()?.as_name();
         let ast_id = self.source_ast_id_map.ast_id(strukt);
-        let (fields, kind, attrs) = self.lower_fields(&strukt.kind(), &body_ctx);
+        let (fields, kind, attrs) = self.lower_fields(&strukt.kind(), &mut body_ctx);
         let (generic_params, generics_source_map) =
             self.lower_generic_params(HasImplicitSelf::No, strukt);
         types_map.shrink_to_fit();
@@ -273,7 +273,7 @@
     fn lower_fields(
         &mut self,
         strukt_kind: &ast::StructKind,
-        body_ctx: &LowerCtx<'_>,
+        body_ctx: &mut LowerCtx<'_>,
     ) -> (Box<[Field]>, FieldsShape, Vec<(usize, RawAttrs)>) {
         match strukt_kind {
             ast::StructKind::Record(it) => {
@@ -308,7 +308,11 @@
         }
     }
 
-    fn lower_record_field(&mut self, field: &ast::RecordField, body_ctx: &LowerCtx<'_>) -> Field {
+    fn lower_record_field(
+        &mut self,
+        field: &ast::RecordField,
+        body_ctx: &mut LowerCtx<'_>,
+    ) -> Field {
         let name = match field.name() {
             Some(name) => name.as_name(),
             None => Name::missing(),
@@ -323,7 +327,7 @@
         &mut self,
         idx: usize,
         field: &ast::TupleField,
-        body_ctx: &LowerCtx<'_>,
+        body_ctx: &mut LowerCtx<'_>,
     ) -> Field {
         let name = Name::new_tuple_field(idx);
         let visibility = self.lower_visibility(field);
@@ -334,13 +338,13 @@
     fn lower_union(&mut self, union: &ast::Union) -> Option<FileItemTreeId<Union>> {
         let (mut types_map, mut types_source_map) =
             (TypesMap::default(), TypesSourceMap::default());
-        let body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
+        let mut body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
         let visibility = self.lower_visibility(union);
         let name = union.name()?.as_name();
         let ast_id = self.source_ast_id_map.ast_id(union);
         let (fields, _, attrs) = match union.record_field_list() {
             Some(record_field_list) => {
-                self.lower_fields(&StructKind::Record(record_field_list), &body_ctx)
+                self.lower_fields(&StructKind::Record(record_field_list), &mut body_ctx)
             }
             None => (Box::default(), FieldsShape::Record, Vec::default()),
         };
@@ -409,12 +413,12 @@
     fn lower_variant(&mut self, variant: &ast::Variant) -> Idx<Variant> {
         let (mut types_map, mut types_source_map) =
             (TypesMap::default(), TypesSourceMap::default());
-        let body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
+        let mut body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
         let name = match variant.name() {
             Some(name) => name.as_name(),
             None => Name::missing(),
         };
-        let (fields, kind, attrs) = self.lower_fields(&variant.kind(), &body_ctx);
+        let (fields, kind, attrs) = self.lower_fields(&variant.kind(), &mut body_ctx);
         let ast_id = self.source_ast_id_map.ast_id(variant);
         types_map.shrink_to_fit();
         types_source_map.shrink_to_fit();
@@ -436,7 +440,7 @@
     fn lower_function(&mut self, func: &ast::Fn) -> Option<FileItemTreeId<Function>> {
         let (mut types_map, mut types_source_map) =
             (TypesMap::default(), TypesSourceMap::default());
-        let body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
+        let mut body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
 
         let visibility = self.lower_visibility(func);
         let name = func.name()?.as_name();
@@ -457,7 +461,7 @@
                     RawAttrs::new(self.db.upcast(), &self_param, self.span_map()),
                 );
                 let self_type = match self_param.ty() {
-                    Some(type_ref) => TypeRef::from_ast(&body_ctx, type_ref),
+                    Some(type_ref) => TypeRef::from_ast(&mut body_ctx, type_ref),
                     None => {
                         let self_type = body_ctx.alloc_type_ref_desugared(TypeRef::Path(
                             Name::new_symbol_root(sym::Self_.clone()).into(),
@@ -492,7 +496,7 @@
                         Param { type_ref: None }
                     }
                     None => {
-                        let type_ref = TypeRef::from_ast_opt(&body_ctx, param.ty());
+                        let type_ref = TypeRef::from_ast_opt(&mut body_ctx, param.ty());
                         Param { type_ref: Some(type_ref) }
                     }
                 };
@@ -502,7 +506,7 @@
 
         let ret_type = match func.ret_type() {
             Some(rt) => match rt.ty() {
-                Some(type_ref) => TypeRef::from_ast(&body_ctx, type_ref),
+                Some(type_ref) => TypeRef::from_ast(&mut body_ctx, type_ref),
                 None if rt.thin_arrow_token().is_some() => body_ctx.alloc_error_type(),
                 None => body_ctx.alloc_type_ref_desugared(TypeRef::unit()),
             },
@@ -581,11 +585,11 @@
     ) -> Option<FileItemTreeId<TypeAlias>> {
         let (mut types_map, mut types_source_map) =
             (TypesMap::default(), TypesSourceMap::default());
-        let body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
+        let mut body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
         let name = type_alias.name()?.as_name();
-        let type_ref = type_alias.ty().map(|it| TypeRef::from_ast(&body_ctx, it));
+        let type_ref = type_alias.ty().map(|it| TypeRef::from_ast(&mut body_ctx, it));
         let visibility = self.lower_visibility(type_alias);
-        let bounds = self.lower_type_bounds(type_alias, &body_ctx);
+        let bounds = self.lower_type_bounds(type_alias, &mut body_ctx);
         let ast_id = self.source_ast_id_map.ast_id(type_alias);
         let (generic_params, generics_source_map) =
             self.lower_generic_params(HasImplicitSelf::No, type_alias);
@@ -612,9 +616,9 @@
     fn lower_static(&mut self, static_: &ast::Static) -> Option<FileItemTreeId<Static>> {
         let (mut types_map, mut types_source_map) =
             (TypesMap::default(), TypesSourceMap::default());
-        let body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
+        let mut body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
         let name = static_.name()?.as_name();
-        let type_ref = TypeRef::from_ast_opt(&body_ctx, static_.ty());
+        let type_ref = TypeRef::from_ast_opt(&mut body_ctx, static_.ty());
         let visibility = self.lower_visibility(static_);
         let mutable = static_.mut_token().is_some();
         let has_safe_kw = static_.safe_token().is_some();
@@ -639,9 +643,9 @@
     fn lower_const(&mut self, konst: &ast::Const) -> FileItemTreeId<Const> {
         let (mut types_map, mut types_source_map) =
             (TypesMap::default(), TypesSourceMap::default());
-        let body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
+        let mut body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
         let name = konst.name().map(|it| it.as_name());
-        let type_ref = TypeRef::from_ast_opt(&body_ctx, konst.ty());
+        let type_ref = TypeRef::from_ast_opt(&mut body_ctx, konst.ty());
         let visibility = self.lower_visibility(konst);
         let ast_id = self.source_ast_id_map.ast_id(konst);
         types_map.shrink_to_fit();
@@ -724,14 +728,14 @@
     fn lower_impl(&mut self, impl_def: &ast::Impl) -> FileItemTreeId<Impl> {
         let (mut types_map, mut types_source_map) =
             (TypesMap::default(), TypesSourceMap::default());
-        let body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
+        let mut body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
 
         let ast_id = self.source_ast_id_map.ast_id(impl_def);
         // FIXME: If trait lowering fails, due to a non PathType for example, we treat this impl
         // as if it was an non-trait impl. Ideally we want to create a unique missing ref that only
         // equals itself.
-        let self_ty = TypeRef::from_ast_opt(&body_ctx, impl_def.self_ty());
-        let target_trait = impl_def.trait_().and_then(|tr| TraitRef::from_ast(&body_ctx, tr));
+        let self_ty = TypeRef::from_ast_opt(&mut body_ctx, impl_def.self_ty());
+        let target_trait = impl_def.trait_().and_then(|tr| TraitRef::from_ast(&mut body_ctx, tr));
         let is_negative = impl_def.excl_token().is_some();
         let is_unsafe = impl_def.unsafe_token().is_some();
 
@@ -870,13 +874,8 @@
     ) -> (Arc<GenericParams>, TypesSourceMap) {
         let (mut types_map, mut types_source_map) =
             (TypesMap::default(), TypesSourceMap::default());
-        let body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
+        let mut body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
         debug_assert!(self.generic_param_attr_buffer.is_empty(),);
-        let add_param_attrs = |item: Either<LocalTypeOrConstParamId, LocalLifetimeParamId>,
-                               param| {
-            let attrs = RawAttrs::new(self.db.upcast(), &param, body_ctx.span_map());
-            debug_assert!(self.generic_param_attr_buffer.insert(item, attrs).is_none());
-        };
         body_ctx.take_impl_traits_bounds();
         let mut generics = GenericParamsCollector::default();
 
@@ -892,16 +891,19 @@
             );
             // add super traits as bounds on Self
             // i.e., `trait Foo: Bar` is equivalent to `trait Foo where Self: Bar`
-            generics.fill_bounds(
-                &body_ctx,
-                bounds,
-                Either::Left(body_ctx.alloc_type_ref_desugared(TypeRef::Path(
-                    Name::new_symbol_root(sym::Self_.clone()).into(),
-                ))),
-            );
+            let bound_target = Either::Left(body_ctx.alloc_type_ref_desugared(TypeRef::Path(
+                Name::new_symbol_root(sym::Self_.clone()).into(),
+            )));
+            generics.fill_bounds(&mut body_ctx, bounds, bound_target);
         }
 
-        generics.fill(&body_ctx, node, add_param_attrs);
+        let span_map = body_ctx.span_map().clone();
+        let add_param_attrs = |item: Either<LocalTypeOrConstParamId, LocalLifetimeParamId>,
+                               param| {
+            let attrs = RawAttrs::new(self.db.upcast(), &param, span_map.as_ref());
+            debug_assert!(self.generic_param_attr_buffer.insert(item, attrs).is_none());
+        };
+        generics.fill(&mut body_ctx, node, add_param_attrs);
 
         let generics = generics.finish(types_map, &mut types_source_map);
         (generics, types_source_map)
@@ -910,7 +912,7 @@
     fn lower_type_bounds(
         &mut self,
         node: &dyn ast::HasTypeBounds,
-        body_ctx: &LowerCtx<'_>,
+        body_ctx: &mut LowerCtx<'_>,
     ) -> Box<[TypeBound]> {
         match node.type_bound_list() {
             Some(bound_list) => {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/lower.rs
index df58479..6d1a3d1 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/lower.rs
@@ -1,10 +1,7 @@
 //! Context for lowering paths.
-use std::cell::{OnceCell, RefCell};
+use std::{cell::OnceCell, mem};
 
-use hir_expand::{
-    span_map::{SpanMap, SpanMapRef},
-    AstId, HirFileId, InFile,
-};
+use hir_expand::{span_map::SpanMap, AstId, HirFileId, InFile};
 use span::{AstIdMap, AstIdNode};
 use stdx::thin_vec::ThinVec;
 use syntax::ast;
@@ -21,28 +18,11 @@
     file_id: HirFileId,
     span_map: OnceCell<SpanMap>,
     ast_id_map: OnceCell<Arc<AstIdMap>>,
-    impl_trait_bounds: RefCell<Vec<ThinVec<TypeBound>>>,
+    impl_trait_bounds: Vec<ThinVec<TypeBound>>,
     // Prevent nested impl traits like `impl Foo<impl Bar>`.
-    outer_impl_trait: RefCell<bool>,
-    types_map: RefCell<(&'a mut TypesMap, &'a mut TypesSourceMap)>,
-}
-
-pub(crate) struct OuterImplTraitGuard<'a, 'b> {
-    ctx: &'a LowerCtx<'b>,
-    old: bool,
-}
-
-impl<'a, 'b> OuterImplTraitGuard<'a, 'b> {
-    fn new(ctx: &'a LowerCtx<'b>, impl_trait: bool) -> Self {
-        let old = ctx.outer_impl_trait.replace(impl_trait);
-        Self { ctx, old }
-    }
-}
-
-impl Drop for OuterImplTraitGuard<'_, '_> {
-    fn drop(&mut self) {
-        self.ctx.outer_impl_trait.replace(self.old);
-    }
+    outer_impl_trait: bool,
+    types_map: &'a mut TypesMap,
+    types_source_map: &'a mut TypesSourceMap,
 }
 
 impl<'a> LowerCtx<'a> {
@@ -57,9 +37,10 @@
             file_id,
             span_map: OnceCell::new(),
             ast_id_map: OnceCell::new(),
-            impl_trait_bounds: RefCell::new(Vec::new()),
-            outer_impl_trait: RefCell::default(),
-            types_map: RefCell::new((types_map, types_source_map)),
+            impl_trait_bounds: Vec::new(),
+            outer_impl_trait: false,
+            types_map,
+            types_source_map,
         }
     }
 
@@ -75,17 +56,18 @@
             file_id,
             span_map,
             ast_id_map: OnceCell::new(),
-            impl_trait_bounds: RefCell::new(Vec::new()),
-            outer_impl_trait: RefCell::default(),
-            types_map: RefCell::new((types_map, types_source_map)),
+            impl_trait_bounds: Vec::new(),
+            outer_impl_trait: false,
+            types_map,
+            types_source_map,
         }
     }
 
-    pub(crate) fn span_map(&self) -> SpanMapRef<'_> {
-        self.span_map.get_or_init(|| self.db.span_map(self.file_id)).as_ref()
+    pub(crate) fn span_map(&self) -> &SpanMap {
+        self.span_map.get_or_init(|| self.db.span_map(self.file_id))
     }
 
-    pub(crate) fn lower_path(&self, ast: ast::Path) -> Option<Path> {
+    pub(crate) fn lower_path(&mut self, ast: ast::Path) -> Option<Path> {
         Path::from_src(self, ast)
     }
 
@@ -96,44 +78,44 @@
         )
     }
 
-    pub fn update_impl_traits_bounds(&self, bounds: ThinVec<TypeBound>) {
-        self.impl_trait_bounds.borrow_mut().push(bounds);
+    pub fn update_impl_traits_bounds_from_type_ref(&mut self, type_ref: TypeRefId) {
+        TypeRef::walk(type_ref, self.types_map, &mut |tr| {
+            if let TypeRef::ImplTrait(bounds) = tr {
+                self.impl_trait_bounds.push(bounds.clone());
+            }
+        });
     }
 
-    pub fn take_impl_traits_bounds(&self) -> Vec<ThinVec<TypeBound>> {
-        self.impl_trait_bounds.take()
+    pub fn take_impl_traits_bounds(&mut self) -> Vec<ThinVec<TypeBound>> {
+        mem::take(&mut self.impl_trait_bounds)
     }
 
     pub(crate) fn outer_impl_trait(&self) -> bool {
-        *self.outer_impl_trait.borrow()
+        self.outer_impl_trait
     }
 
-    pub(crate) fn outer_impl_trait_scope<'b>(
-        &'b self,
+    pub(crate) fn with_outer_impl_trait_scope<R>(
+        &mut self,
         impl_trait: bool,
-    ) -> OuterImplTraitGuard<'b, 'a> {
-        OuterImplTraitGuard::new(self, impl_trait)
+        f: impl FnOnce(&mut Self) -> R,
+    ) -> R {
+        let old = mem::replace(&mut self.outer_impl_trait, impl_trait);
+        let result = f(self);
+        self.outer_impl_trait = old;
+        result
     }
 
-    pub(crate) fn alloc_type_ref(&self, type_ref: TypeRef, node: TypePtr) -> TypeRefId {
-        let mut types_map = self.types_map.borrow_mut();
-        let (types_map, types_source_map) = &mut *types_map;
-        let id = types_map.types.alloc(type_ref);
-        types_source_map.types_map_back.insert(id, InFile::new(self.file_id, node));
+    pub(crate) fn alloc_type_ref(&mut self, type_ref: TypeRef, node: TypePtr) -> TypeRefId {
+        let id = self.types_map.types.alloc(type_ref);
+        self.types_source_map.types_map_back.insert(id, InFile::new(self.file_id, node));
         id
     }
 
-    pub(crate) fn alloc_type_ref_desugared(&self, type_ref: TypeRef) -> TypeRefId {
-        self.types_map.borrow_mut().0.types.alloc(type_ref)
+    pub(crate) fn alloc_type_ref_desugared(&mut self, type_ref: TypeRef) -> TypeRefId {
+        self.types_map.types.alloc(type_ref)
     }
 
-    pub(crate) fn alloc_error_type(&self) -> TypeRefId {
-        self.types_map.borrow_mut().0.types.alloc(TypeRef::Error)
-    }
-
-    // FIXME: If we alloc while holding this, well... Bad Things will happen. Need to change this
-    // to use proper mutability instead of interior mutability.
-    pub(crate) fn types_map(&self) -> std::cell::Ref<'_, TypesMap> {
-        std::cell::Ref::map(self.types_map.borrow(), |it| &*it.0)
+    pub(crate) fn alloc_error_type(&mut self) -> TypeRefId {
+        self.types_map.types.alloc(TypeRef::Error)
     }
 }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
index b9aec93..a37e3c7 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
@@ -31,7 +31,7 @@
     item_scope::{ImportId, ImportOrExternCrate, ImportType, PerNsGlobImports},
     item_tree::{
         self, AttrOwner, FieldsShape, FileItemTreeId, ImportKind, ItemTree, ItemTreeId,
-        ItemTreeNode, Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, TreeId,
+        ItemTreeNode, Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, TreeId, UseTreeKind,
     },
     macro_call_as_call_id, macro_call_as_call_id_with_eager,
     nameres::{
@@ -1058,8 +1058,33 @@
         vis: Visibility,
         def_import_type: Option<ImportType>,
     ) -> bool {
-        if let Some((_, v, _)) = defs.types.as_mut() {
-            *v = v.min(vis, &self.def_map).unwrap_or(vis);
+        // `extern crate crate_name` things can be re-exported as `pub use crate_name`.
+        // But they cannot be re-exported as `pub use self::crate_name`, `pub use crate::crate_name`
+        // or `pub use ::crate_name`.
+        //
+        // This has been historically allowed, but may be not allowed in future
+        // https://github.com/rust-lang/rust/issues/127909
+        if let Some((_, v, it)) = defs.types.as_mut() {
+            let is_extern_crate_reimport_without_prefix = || {
+                let Some(ImportOrExternCrate::ExternCrate(_)) = it else {
+                    return false;
+                };
+                let Some(ImportType::Import(id)) = def_import_type else {
+                    return false;
+                };
+                let use_id = id.import.lookup(self.db).id;
+                let item_tree = use_id.item_tree(self.db);
+                let use_kind = item_tree[use_id.value].use_tree.kind();
+                let UseTreeKind::Single { path, .. } = use_kind else {
+                    return false;
+                };
+                path.segments().len() < 2
+            };
+            if is_extern_crate_reimport_without_prefix() {
+                *v = vis;
+            } else {
+                *v = v.min(vis, &self.def_map).unwrap_or(vis);
+            }
         }
         if let Some((_, v, _)) = defs.values.as_mut() {
             *v = v.min(vis, &self.def_map).unwrap_or(vis);
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs
index 75cab13..29379d0 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs
@@ -10,6 +10,7 @@
 //!
 //! `ReachedFixedPoint` signals about this.
 
+use either::Either;
 use hir_expand::{name::Name, Lookup};
 use span::Edition;
 use triomphe::Arc;
@@ -150,17 +151,8 @@
 
         let mut arc;
         let mut current_map = self;
-        loop {
-            let new = current_map.resolve_path_fp_with_macro_single(
-                db,
-                mode,
-                original_module,
-                path,
-                shadow,
-                expected_macro_subns,
-            );
 
-            // Merge `new` into `result`.
+        let mut merge = |new: ResolvePathResult| {
             result.resolved_def = result.resolved_def.or(new.resolved_def);
             if result.reached_fixedpoint == ReachedFixedPoint::No {
                 result.reached_fixedpoint = new.reached_fixedpoint;
@@ -171,7 +163,9 @@
                 (Some(old), Some(new)) => Some(old.max(new)),
                 (None, new) => new,
             };
+        };
 
+        loop {
             match current_map.block {
                 Some(block) if original_module == Self::ROOT => {
                     // Block modules "inherit" names from its parent module.
@@ -180,8 +174,38 @@
                     current_map = &arc;
                 }
                 // Proper (non-block) modules, including those in block `DefMap`s, don't.
-                _ => return result,
+                _ => {
+                    if original_module != Self::ROOT && current_map.block.is_some() {
+                        // A module inside a block. Do not resolve items declared in upper blocks, but we do need to get
+                        // the prelude items (which are not inserted into blocks because they can be overridden there).
+                        original_module = Self::ROOT;
+                        arc = db.crate_def_map(self.krate);
+                        current_map = &arc;
+
+                        let new = current_map.resolve_path_fp_in_all_preludes(
+                            db,
+                            mode,
+                            original_module,
+                            path,
+                            shadow,
+                        );
+                        merge(new);
+                    }
+
+                    return result;
+                }
             }
+
+            let new = current_map.resolve_path_fp_with_macro_single(
+                db,
+                mode,
+                original_module,
+                path,
+                shadow,
+                expected_macro_subns,
+            );
+
+            merge(new);
         }
     }
 
@@ -195,7 +219,7 @@
         expected_macro_subns: Option<MacroSubNs>,
     ) -> ResolvePathResult {
         let mut segments = path.segments().iter().enumerate();
-        let mut curr_per_ns = match path.kind {
+        let curr_per_ns = match path.kind {
             PathKind::DollarCrate(krate) => {
                 if krate == self.krate {
                     cov_mark::hit!(macro_dollar_crate_self);
@@ -296,25 +320,96 @@
 
                 PerNs::types(module.into(), Visibility::Public, None)
             }
-            PathKind::Abs => {
-                // 2018-style absolute path -- only extern prelude
-                let segment = match segments.next() {
-                    Some((_, segment)) => segment,
+            PathKind::Abs => match self.resolve_path_abs(&mut segments, path) {
+                Either::Left(it) => it,
+                Either::Right(reached_fixed_point) => {
+                    return ResolvePathResult::empty(reached_fixed_point)
+                }
+            },
+        };
+
+        self.resolve_remaining_segments(segments, curr_per_ns, path, db, shadow, original_module)
+    }
+
+    /// Resolves a path only in the preludes, without accounting for item scopes.
+    pub(super) fn resolve_path_fp_in_all_preludes(
+        &self,
+        db: &dyn DefDatabase,
+        mode: ResolveMode,
+        original_module: LocalModuleId,
+        path: &ModPath,
+        shadow: BuiltinShadowMode,
+    ) -> ResolvePathResult {
+        let mut segments = path.segments().iter().enumerate();
+        let curr_per_ns = match path.kind {
+            // plain import or absolute path in 2015: crate-relative with
+            // fallback to extern prelude (with the simplification in
+            // rust-lang/rust#57745)
+            // FIXME there must be a nicer way to write this condition
+            PathKind::Plain | PathKind::Abs
+                if self.data.edition == Edition::Edition2015
+                    && (path.kind == PathKind::Abs || mode == ResolveMode::Import) =>
+            {
+                let (_, segment) = match segments.next() {
+                    Some((idx, segment)) => (idx, segment),
                     None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
                 };
-                if let Some(&(def, extern_crate)) = self.data.extern_prelude.get(segment) {
-                    tracing::debug!("absolute path {:?} resolved to crate {:?}", path, def);
-                    PerNs::types(
-                        def.into(),
-                        Visibility::Public,
-                        extern_crate.map(ImportOrExternCrate::ExternCrate),
-                    )
-                } else {
-                    return ResolvePathResult::empty(ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude
+                tracing::debug!("resolving {:?} in crate root (+ extern prelude)", segment);
+                self.resolve_name_in_extern_prelude(segment)
+            }
+            PathKind::Plain => {
+                let (_, segment) = match segments.next() {
+                    Some((idx, segment)) => (idx, segment),
+                    None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
+                };
+                tracing::debug!("resolving {:?} in module", segment);
+                self.resolve_name_in_all_preludes(db, segment)
+            }
+            PathKind::Abs => match self.resolve_path_abs(&mut segments, path) {
+                Either::Left(it) => it,
+                Either::Right(reached_fixed_point) => {
+                    return ResolvePathResult::empty(reached_fixed_point)
                 }
+            },
+            PathKind::DollarCrate(_) | PathKind::Crate | PathKind::Super(_) => {
+                return ResolvePathResult::empty(ReachedFixedPoint::Yes)
             }
         };
 
+        self.resolve_remaining_segments(segments, curr_per_ns, path, db, shadow, original_module)
+    }
+
+    /// 2018-style absolute path -- only extern prelude
+    fn resolve_path_abs<'a>(
+        &self,
+        segments: &mut impl Iterator<Item = (usize, &'a Name)>,
+        path: &ModPath,
+    ) -> Either<PerNs, ReachedFixedPoint> {
+        let segment = match segments.next() {
+            Some((_, segment)) => segment,
+            None => return Either::Right(ReachedFixedPoint::Yes),
+        };
+        if let Some(&(def, extern_crate)) = self.data.extern_prelude.get(segment) {
+            tracing::debug!("absolute path {:?} resolved to crate {:?}", path, def);
+            Either::Left(PerNs::types(
+                def.into(),
+                Visibility::Public,
+                extern_crate.map(ImportOrExternCrate::ExternCrate),
+            ))
+        } else {
+            Either::Right(ReachedFixedPoint::No) // extern crate declarations can add to the extern prelude
+        }
+    }
+
+    fn resolve_remaining_segments<'a>(
+        &self,
+        segments: impl Iterator<Item = (usize, &'a Name)>,
+        mut curr_per_ns: PerNs,
+        path: &ModPath,
+        db: &dyn DefDatabase,
+        shadow: BuiltinShadowMode,
+        original_module: LocalModuleId,
+    ) -> ResolvePathResult {
         for (i, segment) in segments {
             let (curr, vis, imp) = match curr_per_ns.take_types_full() {
                 Some(r) => r,
@@ -475,24 +570,9 @@
                 // they might been shadowed by local names.
                 return PerNs::none();
             }
-            self.data.extern_prelude.get(name).map_or(PerNs::none(), |&(it, extern_crate)| {
-                PerNs::types(
-                    it.into(),
-                    Visibility::Public,
-                    extern_crate.map(ImportOrExternCrate::ExternCrate),
-                )
-            })
+            self.resolve_name_in_extern_prelude(name)
         };
-        let macro_use_prelude = || {
-            self.macro_use_prelude.get(name).map_or(PerNs::none(), |&(it, _extern_crate)| {
-                PerNs::macros(
-                    it,
-                    Visibility::Public,
-                    // FIXME?
-                    None, // extern_crate.map(ImportOrExternCrate::ExternCrate),
-                )
-            })
-        };
+        let macro_use_prelude = || self.resolve_in_macro_use_prelude(name);
         let prelude = || {
             if self.block.is_some() && module == DefMap::ROOT {
                 return PerNs::none();
@@ -507,6 +587,38 @@
             .or_else(prelude)
     }
 
+    fn resolve_name_in_all_preludes(&self, db: &dyn DefDatabase, name: &Name) -> PerNs {
+        // Resolve in:
+        //  - extern prelude / macro_use prelude
+        //  - std prelude
+        let extern_prelude = self.resolve_name_in_extern_prelude(name);
+        let macro_use_prelude = || self.resolve_in_macro_use_prelude(name);
+        let prelude = || self.resolve_in_prelude(db, name);
+
+        extern_prelude.or_else(macro_use_prelude).or_else(prelude)
+    }
+
+    fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs {
+        self.data.extern_prelude.get(name).map_or(PerNs::none(), |&(it, extern_crate)| {
+            PerNs::types(
+                it.into(),
+                Visibility::Public,
+                extern_crate.map(ImportOrExternCrate::ExternCrate),
+            )
+        })
+    }
+
+    fn resolve_in_macro_use_prelude(&self, name: &Name) -> PerNs {
+        self.macro_use_prelude.get(name).map_or(PerNs::none(), |&(it, _extern_crate)| {
+            PerNs::macros(
+                it,
+                Visibility::Public,
+                // FIXME?
+                None, // extern_crate.map(ImportOrExternCrate::ExternCrate),
+            )
+        })
+    }
+
     fn resolve_name_in_crate_root_or_extern_prelude(
         &self,
         db: &dyn DefDatabase,
@@ -525,16 +637,7 @@
                 // Don't resolve extern prelude in pseudo-module of a block.
                 return PerNs::none();
             }
-            self.data.extern_prelude.get(name).copied().map_or(
-                PerNs::none(),
-                |(it, extern_crate)| {
-                    PerNs::types(
-                        it.into(),
-                        Visibility::Public,
-                        extern_crate.map(ImportOrExternCrate::ExternCrate),
-                    )
-                },
-            )
+            self.resolve_name_in_extern_prelude(name)
         };
 
         from_crate_root.or_else(from_extern_prelude)
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs
index 7b02a89..e1e30e5 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs
@@ -386,6 +386,52 @@
 }
 
 #[test]
+fn extern_crate_reexport() {
+    check(
+        r#"
+//- /main.rs crate:main deps:importer
+use importer::*;
+use importer::extern_crate1::exported::*;
+use importer::allowed_reexport::*;
+use importer::extern_crate2::*;
+use importer::not_allowed_reexport1;
+use importer::not_allowed_reexport2;
+
+//- /importer.rs crate:importer deps:extern_crate1,extern_crate2
+extern crate extern_crate1;
+extern crate extern_crate2;
+
+pub use extern_crate1;
+pub use extern_crate1 as allowed_reexport;
+
+pub use ::extern_crate;
+pub use self::extern_crate as not_allowed_reexport1;
+pub use crate::extern_crate as not_allowed_reexport2;
+
+//- /extern_crate1.rs crate:extern_crate1
+pub mod exported {
+    pub struct PublicItem;
+    struct PrivateItem;
+}
+
+pub struct Exported;
+
+//- /extern_crate2.rs crate:extern_crate2
+pub struct NotExported;
+"#,
+        expect![[r#"
+            crate
+            Exported: t v
+            PublicItem: t v
+            allowed_reexport: t
+            exported: t
+            not_allowed_reexport1: _
+            not_allowed_reexport2: _
+        "#]],
+    );
+}
+
+#[test]
 fn extern_crate_rename_2015_edition() {
     check(
         r#"
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/path.rs b/src/tools/rust-analyzer/crates/hir-def/src/path.rs
index dc6947c..aa2c4a6 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/path.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/path.rs
@@ -121,7 +121,7 @@
 impl Path {
     /// Converts an `ast::Path` to `Path`. Works with use trees.
     /// It correctly handles `$crate` based path from macro call.
-    pub fn from_src(ctx: &LowerCtx<'_>, path: ast::Path) -> Option<Path> {
+    pub fn from_src(ctx: &mut LowerCtx<'_>, path: ast::Path) -> Option<Path> {
         lower::lower_path(ctx, path)
     }
 
@@ -284,7 +284,7 @@
 
 impl GenericArgs {
     pub(crate) fn from_ast(
-        lower_ctx: &LowerCtx<'_>,
+        lower_ctx: &mut LowerCtx<'_>,
         node: ast::GenericArgList,
     ) -> Option<GenericArgs> {
         lower::lower_generic_args(lower_ctx, node)
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs
index c328b9c..553e615 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs
@@ -19,12 +19,11 @@
 
 /// Converts an `ast::Path` to `Path`. Works with use trees.
 /// It correctly handles `$crate` based path from macro call.
-pub(super) fn lower_path(ctx: &LowerCtx<'_>, mut path: ast::Path) -> Option<Path> {
+pub(super) fn lower_path(ctx: &mut LowerCtx<'_>, mut path: ast::Path) -> Option<Path> {
     let mut kind = PathKind::Plain;
     let mut type_anchor = None;
     let mut segments = Vec::new();
     let mut generic_args = Vec::new();
-    let span_map = ctx.span_map();
     loop {
         let segment = path.segment()?;
 
@@ -37,7 +36,7 @@
                 if name_ref.text() == "$crate" {
                     break kind = resolve_crate_root(
                         ctx.db.upcast(),
-                        span_map.span_for_range(name_ref.syntax().text_range()).ctx,
+                        ctx.span_map().span_for_range(name_ref.syntax().text_range()).ctx,
                     )
                     .map(PathKind::DollarCrate)
                     .unwrap_or(PathKind::Crate);
@@ -151,7 +150,7 @@
     // We follow what it did anyway :)
     if segments.len() == 1 && kind == PathKind::Plain {
         if let Some(_macro_call) = path.syntax().parent().and_then(ast::MacroCall::cast) {
-            let syn_ctxt = span_map.span_for_range(path.segment()?.syntax().text_range()).ctx;
+            let syn_ctxt = ctx.span_map().span_for_range(path.segment()?.syntax().text_range()).ctx;
             if let Some(macro_call_id) = ctx.db.lookup_intern_syntax_context(syn_ctxt).outer_expn {
                 if ctx.db.lookup_intern_macro_call(macro_call_id).def.local_inner {
                     kind = match resolve_crate_root(ctx.db.upcast(), syn_ctxt) {
@@ -183,7 +182,7 @@
 }
 
 pub(super) fn lower_generic_args(
-    lower_ctx: &LowerCtx<'_>,
+    lower_ctx: &mut LowerCtx<'_>,
     node: ast::GenericArgList,
 ) -> Option<GenericArgs> {
     let mut args = Vec::new();
@@ -192,13 +191,7 @@
         match generic_arg {
             ast::GenericArg::TypeArg(type_arg) => {
                 let type_ref = TypeRef::from_ast_opt(lower_ctx, type_arg.ty());
-                let types_map = lower_ctx.types_map();
-                TypeRef::walk(type_ref, &types_map, &mut |tr| {
-                    if let TypeRef::ImplTrait(bounds) = tr {
-                        lower_ctx.update_impl_traits_bounds(bounds.clone());
-                    }
-                });
-                drop(types_map);
+                lower_ctx.update_impl_traits_bounds_from_type_ref(type_ref);
                 args.push(GenericArg::Type(type_ref));
             }
             ast::GenericArg::AssocTypeArg(assoc_type_arg) => {
@@ -208,27 +201,22 @@
                 }
                 if let Some(name_ref) = assoc_type_arg.name_ref() {
                     // Nested impl traits like `impl Foo<Assoc = impl Bar>` are allowed
-                    let _guard = lower_ctx.outer_impl_trait_scope(false);
-                    let name = name_ref.as_name();
-                    let args = assoc_type_arg
-                        .generic_arg_list()
-                        .and_then(|args| lower_generic_args(lower_ctx, args));
-                    let type_ref = assoc_type_arg.ty().map(|it| TypeRef::from_ast(lower_ctx, it));
-                    let type_ref = type_ref.inspect(|&tr| {
-                        let types_map = lower_ctx.types_map();
-                        TypeRef::walk(tr, &types_map, &mut |tr| {
-                            if let TypeRef::ImplTrait(bounds) = tr {
-                                lower_ctx.update_impl_traits_bounds(bounds.clone());
-                            }
-                        });
-                        drop(types_map);
+                    lower_ctx.with_outer_impl_trait_scope(false, |lower_ctx| {
+                        let name = name_ref.as_name();
+                        let args = assoc_type_arg
+                            .generic_arg_list()
+                            .and_then(|args| lower_generic_args(lower_ctx, args));
+                        let type_ref =
+                            assoc_type_arg.ty().map(|it| TypeRef::from_ast(lower_ctx, it));
+                        let type_ref = type_ref
+                            .inspect(|&tr| lower_ctx.update_impl_traits_bounds_from_type_ref(tr));
+                        let bounds = if let Some(l) = assoc_type_arg.type_bound_list() {
+                            l.bounds().map(|it| TypeBound::from_ast(lower_ctx, it)).collect()
+                        } else {
+                            Box::default()
+                        };
+                        bindings.push(AssociatedTypeBinding { name, args, type_ref, bounds });
                     });
-                    let bounds = if let Some(l) = assoc_type_arg.type_bound_list() {
-                        l.bounds().map(|it| TypeBound::from_ast(lower_ctx, it)).collect()
-                    } else {
-                        Box::default()
-                    };
-                    bindings.push(AssociatedTypeBinding { name, args, type_ref, bounds });
                 }
             }
             ast::GenericArg::LifetimeArg(lifetime_arg) => {
@@ -258,7 +246,7 @@
 /// Collect `GenericArgs` from the parts of a fn-like path, i.e. `Fn(X, Y)
 /// -> Z` (which desugars to `Fn<(X, Y), Output=Z>`).
 fn lower_generic_args_from_fn_path(
-    ctx: &LowerCtx<'_>,
+    ctx: &mut LowerCtx<'_>,
     params: Option<ast::ParamList>,
     ret_type: Option<ast::RetType>,
 ) -> Option<GenericArgs> {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
index 277dabe..4e95bdf2 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
@@ -2033,7 +2033,7 @@
             TypeRef::Macro(macro_call) => {
                 let (mut types_map, mut types_source_map) =
                     (TypesMap::default(), TypesSourceMap::default());
-                let ctx = hir_def::lower::LowerCtx::new(
+                let mut ctx = hir_def::lower::LowerCtx::new(
                     f.db.upcast(),
                     macro_call.file_id,
                     &mut types_map,
@@ -2041,7 +2041,7 @@
                 );
                 let macro_call = macro_call.to_node(f.db.upcast());
                 match macro_call.path() {
-                    Some(path) => match Path::from_src(&ctx, path) {
+                    Some(path) => match Path::from_src(&mut ctx, path) {
                         Some(path) => path.hir_fmt(f, &types_map)?,
                         None => write!(f, "{{macro}}")?,
                     },
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs
index 8083144..9f4cc98 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs
@@ -6,7 +6,7 @@
 use chalk_ir::{AdtId, FloatTy, IntTy, TyKind, UintTy};
 use hir_def::{
     layout::{
-        Abi, FieldsShape, Float, Integer, LayoutCalculator, LayoutCalculatorError, LayoutS,
+        Abi, FieldsShape, Float, Integer, LayoutCalculator, LayoutCalculatorError, LayoutData,
         Primitive, ReprOptions, Scalar, Size, StructKind, TargetDataLayout, WrappingRange,
     },
     LocalFieldId, StructId,
@@ -66,7 +66,7 @@
     }
 }
 
-pub type Layout = LayoutS<RustcFieldIdx, RustcEnumVariantIdx>;
+pub type Layout = LayoutData<RustcFieldIdx, RustcEnumVariantIdx>;
 pub type TagEncoding = hir_def::layout::TagEncoding<RustcEnumVariantIdx>;
 pub type Variants = hir_def::layout::Variants<RustcFieldIdx, RustcEnumVariantIdx>;
 
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
index e3a92e5..ee9fd02 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
@@ -465,13 +465,13 @@
                             let (mut types_map, mut types_source_map) =
                                 (TypesMap::default(), TypesSourceMap::default());
 
-                            let ctx = expander.ctx(
+                            let mut ctx = expander.ctx(
                                 self.db.upcast(),
                                 &mut types_map,
                                 &mut types_source_map,
                             );
                             // FIXME: Report syntax errors in expansion here
-                            let type_ref = TypeRef::from_ast(&ctx, expanded.tree());
+                            let type_ref = TypeRef::from_ast(&mut ctx, expanded.tree());
 
                             drop(expander);
 
diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
index feb9a34..29c2660 100644
--- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
@@ -1271,9 +1271,9 @@
         let analyze = self.analyze(ty.syntax())?;
         let (mut types_map, mut types_source_map) =
             (TypesMap::default(), TypesSourceMap::default());
-        let ctx =
+        let mut ctx =
             LowerCtx::new(self.db.upcast(), analyze.file_id, &mut types_map, &mut types_source_map);
-        let type_ref = crate::TypeRef::from_ast(&ctx, ty.clone());
+        let type_ref = crate::TypeRef::from_ast(&mut ctx, ty.clone());
         let ty = hir_ty::TyLoweringContext::new_maybe_unowned(
             self.db,
             &analyze.resolver,
@@ -1289,9 +1289,9 @@
         let analyze = self.analyze(path.syntax())?;
         let (mut types_map, mut types_source_map) =
             (TypesMap::default(), TypesSourceMap::default());
-        let ctx =
+        let mut ctx =
             LowerCtx::new(self.db.upcast(), analyze.file_id, &mut types_map, &mut types_source_map);
-        let hir_path = Path::from_src(&ctx, path.clone())?;
+        let hir_path = Path::from_src(&mut ctx, path.clone())?;
         match analyze.resolver.resolve_path_in_type_ns_fully(self.db.upcast(), &hir_path)? {
             TypeNs::TraitId(id) => Some(Trait { id }),
             _ => None,
@@ -1974,9 +1974,9 @@
     pub fn speculative_resolve(&self, ast_path: &ast::Path) -> Option<PathResolution> {
         let (mut types_map, mut types_source_map) =
             (TypesMap::default(), TypesSourceMap::default());
-        let ctx =
+        let mut ctx =
             LowerCtx::new(self.db.upcast(), self.file_id, &mut types_map, &mut types_source_map);
-        let path = Path::from_src(&ctx, ast_path.clone())?;
+        let path = Path::from_src(&mut ctx, ast_path.clone())?;
         resolve_hir_path(
             self.db,
             &self.resolver,
diff --git a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
index 8d6e228..c16454c 100644
--- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
@@ -616,9 +616,9 @@
     ) -> Option<Macro> {
         let (mut types_map, mut types_source_map) =
             (TypesMap::default(), TypesSourceMap::default());
-        let ctx =
+        let mut ctx =
             LowerCtx::new(db.upcast(), macro_call.file_id, &mut types_map, &mut types_source_map);
-        let path = macro_call.value.path().and_then(|ast| Path::from_src(&ctx, ast))?;
+        let path = macro_call.value.path().and_then(|ast| Path::from_src(&mut ctx, ast))?;
         self.resolver
             .resolve_path_as_macro(db.upcast(), path.mod_path()?, Some(MacroSubNs::Bang))
             .map(|(it, _)| it.into())
@@ -731,8 +731,9 @@
 
         let (mut types_map, mut types_source_map) =
             (TypesMap::default(), TypesSourceMap::default());
-        let ctx = LowerCtx::new(db.upcast(), self.file_id, &mut types_map, &mut types_source_map);
-        let hir_path = Path::from_src(&ctx, path.clone())?;
+        let mut ctx =
+            LowerCtx::new(db.upcast(), self.file_id, &mut types_map, &mut types_source_map);
+        let hir_path = Path::from_src(&mut ctx, path.clone())?;
 
         // Case where path is a qualifier of a use tree, e.g. foo::bar::{Baz, Qux} where we are
         // trying to resolve foo::bar.
diff --git a/src/tools/rust-analyzer/crates/ide-assists/Cargo.toml b/src/tools/rust-analyzer/crates/ide-assists/Cargo.toml
index 2a14fbe..ba21586 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/ide-assists/Cargo.toml
@@ -23,7 +23,6 @@
 # local deps
 stdx.workspace = true
 syntax.workspace = true
-text-edit.workspace = true
 ide-db.workspace = true
 hir.workspace = true
 
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bool_to_enum.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bool_to_enum.rs
index c035c59..605fd14 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bool_to_enum.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bool_to_enum.rs
@@ -1,5 +1,6 @@
 use either::Either;
 use hir::ModuleDef;
+use ide_db::text_edit::TextRange;
 use ide_db::{
     assists::{AssistId, AssistKind},
     defs::Definition,
@@ -19,7 +20,6 @@
     },
     AstNode, NodeOrToken, SyntaxKind, SyntaxNode, T,
 };
-use text_edit::TextRange;
 
 use crate::{
     assist_context::{AssistContext, Assists},
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs
index b229b75..22a1efd 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs
@@ -1,4 +1,5 @@
 use hir::{sym, HasVisibility};
+use ide_db::text_edit::TextRange;
 use ide_db::{
     assists::{AssistId, AssistKind},
     defs::Definition,
@@ -8,7 +9,6 @@
 };
 use itertools::Itertools;
 use syntax::{ast, ted, AstNode, Edition, SmolStr, SyntaxNode, ToSmolStr};
-use text_edit::TextRange;
 
 use crate::{
     assist_context::{AssistContext, Assists, SourceChangeBuilder},
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs
index 9ecfb83..3f0d5cf 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs
@@ -1,3 +1,4 @@
+use ide_db::text_edit::TextRange;
 use ide_db::{
     assists::{AssistId, AssistKind},
     defs::Definition,
@@ -8,7 +9,6 @@
     ast::{self, make, AstNode, FieldExpr, HasName, IdentPat},
     ted,
 };
-use text_edit::TextRange;
 
 use crate::{
     assist_context::{AssistContext, Assists, SourceChangeBuilder},
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs
index c6f99d6..0570b44 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs
@@ -1,6 +1,7 @@
 use std::collections::hash_map::Entry;
 
 use hir::{FileRange, HirFileIdExt, InFile, InRealFile, Module, ModuleSource};
+use ide_db::text_edit::TextRange;
 use ide_db::{
     defs::Definition,
     search::{FileReference, ReferenceCategory, SearchScope},
@@ -10,7 +11,6 @@
     ast::{self, Rename},
     AstNode,
 };
-use text_edit::TextRange;
 
 use crate::{AssistContext, AssistId, AssistKind, Assists};
 
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_named_generic_with_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_named_generic_with_impl.rs
index 8a6c293..26fd887 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_named_generic_with_impl.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_named_generic_with_impl.rs
@@ -1,4 +1,5 @@
 use hir::{FileRange, Semantics};
+use ide_db::text_edit::TextRange;
 use ide_db::{
     defs::Definition,
     search::{SearchScope, UsageSearchResult},
@@ -11,7 +12,6 @@
     },
     match_ast, ted, AstNode,
 };
-use text_edit::TextRange;
 
 use crate::{AssistContext, AssistId, AssistKind, Assists};
 
diff --git a/src/tools/rust-analyzer/crates/ide-completion/Cargo.toml b/src/tools/rust-analyzer/crates/ide-completion/Cargo.toml
index 614465b..1bef82a 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/ide-completion/Cargo.toml
@@ -25,7 +25,6 @@
 ide-db.workspace = true
 stdx.workspace = true
 syntax.workspace = true
-text-edit.workspace = true
 # completions crate should depend only on the top-level `hir` package. if you need
 # something from some `hir-xxx` subpackage, reexport the API via `hir`.
 hir.workspace = true
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs
index 672e179..c38a8ef 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs
@@ -32,6 +32,7 @@
 //! ```
 
 use hir::{db::ExpandDatabase, HasAttrs, MacroFileId, Name};
+use ide_db::text_edit::TextEdit;
 use ide_db::{
     documentation::HasDocs, path_transform::PathTransform,
     syntax_helpers::prettify_macro_expansion, traits::get_missing_assoc_items, SymbolKind,
@@ -40,7 +41,6 @@
     ast::{self, edit_in_place::AttrsOwnerEdit, make, HasGenericArgs, HasTypeBounds},
     format_smolstr, ted, AstNode, SmolStr, SyntaxElement, SyntaxKind, TextRange, ToSmolStr, T,
 };
-use text_edit::TextEdit;
 
 use crate::{
     context::PathCompletionCtx, CompletionContext, CompletionItem, CompletionItemKind,
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs
index d3579fd..495f82d 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs
@@ -3,6 +3,7 @@
 mod format_like;
 
 use hir::ItemInNs;
+use ide_db::text_edit::TextEdit;
 use ide_db::{
     documentation::{Documentation, HasDocs},
     imports::insert_use::ImportScope,
@@ -15,7 +16,6 @@
     SyntaxKind::{BLOCK_EXPR, EXPR_STMT, FOR_EXPR, IF_EXPR, LOOP_EXPR, STMT_LIST, WHILE_EXPR},
     TextRange, TextSize,
 };
-use text_edit::TextEdit;
 
 use crate::{
     completions::postfix::format_like::add_format_like_completions,
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
index 0e1302f..efbee39 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
@@ -20,7 +20,6 @@
     SyntaxKind::{self, *},
     SyntaxToken, TextRange, TextSize, T,
 };
-use text_edit::Indel;
 
 use crate::{
     context::analysis::{expand_and_analyze, AnalysisResult},
@@ -684,8 +683,7 @@
         // actual completion.
         let file_with_fake_ident = {
             let parse = db.parse(file_id);
-            let edit = Indel::insert(offset, COMPLETION_MARKER.to_owned());
-            parse.reparse(&edit, file_id.edition()).tree()
+            parse.reparse(TextRange::empty(offset), COMPLETION_MARKER, file_id.edition()).tree()
         };
 
         // always pick the token to the immediate left of the cursor, as that is what we are actually
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs
index 8c97ebd..52f6bed 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs
@@ -3,6 +3,7 @@
 use std::{fmt, mem};
 
 use hir::Mutability;
+use ide_db::text_edit::TextEdit;
 use ide_db::{
     documentation::Documentation, imports::import_assets::LocatedImport, RootDatabase, SnippetCap,
     SymbolKind,
@@ -11,7 +12,6 @@
 use smallvec::SmallVec;
 use stdx::{impl_from, never};
 use syntax::{format_smolstr, Edition, SmolStr, TextRange, TextSize};
-use text_edit::TextEdit;
 
 use crate::{
     context::{CompletionContext, PathCompletionCtx},
@@ -426,7 +426,7 @@
         self.lookup.as_str()
     }
 
-    pub fn ref_match(&self) -> Option<(String, text_edit::Indel, CompletionRelevance)> {
+    pub fn ref_match(&self) -> Option<(String, ide_db::text_edit::Indel, CompletionRelevance)> {
         // Relevance of the ref match should be the same as the original
         // match, but with exact type match set because self.ref_match
         // is only set if there is an exact type match.
@@ -436,7 +436,10 @@
         self.ref_match.map(|(mutability, offset)| {
             (
                 format!("&{}{}", mutability.as_keyword_for_ref(), self.label),
-                text_edit::Indel::insert(offset, format!("&{}", mutability.as_keyword_for_ref())),
+                ide_db::text_edit::Indel::insert(
+                    offset,
+                    format!("&{}", mutability.as_keyword_for_ref()),
+                ),
                 relevance,
             )
         })
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs b/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs
index a78976d..dfee01b 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs
@@ -10,16 +10,17 @@
 #[cfg(test)]
 mod tests;
 
+use ide_db::text_edit::TextEdit;
 use ide_db::{
     helpers::mod_path_to_ast,
     imports::{
         import_assets::NameToImport,
         insert_use::{self, ImportScope},
     },
-    items_locator, FilePosition, RootDatabase,
+    items_locator,
+    syntax_helpers::tree_diff::diff,
+    FilePosition, RootDatabase,
 };
-use syntax::algo;
-use text_edit::TextEdit;
 
 use crate::{
     completions::Completions,
@@ -297,6 +298,6 @@
         }
     });
 
-    algo::diff(scope.as_syntax_node(), new_ast.as_syntax_node()).into_text_edit(&mut import_insert);
+    diff(scope.as_syntax_node(), new_ast.as_syntax_node()).into_text_edit(&mut import_insert);
     Some(vec![import_insert.finish()])
 }
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs
index 4dd1711..ec3c2fe 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs
@@ -11,6 +11,7 @@
 pub(crate) mod variant;
 
 use hir::{sym, AsAssocItem, HasAttrs, HirDisplay, ModuleDef, ScopeDef, Type};
+use ide_db::text_edit::TextEdit;
 use ide_db::{
     documentation::{Documentation, HasDocs},
     helpers::item_name,
@@ -18,7 +19,6 @@
     RootDatabase, SnippetCap, SymbolKind,
 };
 use syntax::{ast, format_smolstr, AstNode, Edition, SmolStr, SyntaxKind, TextRange, ToSmolStr};
-use text_edit::TextEdit;
 
 use crate::{
     context::{DotAccess, DotAccessKind, PathCompletionCtx, PathKind, PatternContext},
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs
index 1bbe097..4567935 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs
@@ -663,6 +663,7 @@
                 ba dbg
                 ba opt_level
                 ba test
+                ba true
             "#]],
         );
         check(
@@ -674,6 +675,7 @@
                 ba dbg
                 ba opt_level
                 ba test
+                ba true
             "#]],
         );
     }
diff --git a/src/tools/rust-analyzer/crates/ide-db/Cargo.toml b/src/tools/rust-analyzer/crates/ide-db/Cargo.toml
index c078188..17f0e69 100644
--- a/src/tools/rust-analyzer/crates/ide-db/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/ide-db/Cargo.toml
@@ -35,7 +35,6 @@
 profile.workspace = true
 stdx.workspace = true
 syntax.workspace = true
-text-edit.workspace = true
 span.workspace = true
 # ide should depend only on the top-level `hir` package. if you need
 # something from some `hir-xxx` subpackage, reexport the API via `hir`.
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/documentation.rs b/src/tools/rust-analyzer/crates/ide-db/src/documentation.rs
index 5e443ba..b52a325 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/documentation.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/documentation.rs
@@ -5,11 +5,11 @@
     resolve_doc_path_on, sym, AttrId, AttrSourceMap, AttrsWithOwner, HasAttrs, InFile,
 };
 use itertools::Itertools;
+use span::{TextRange, TextSize};
 use syntax::{
     ast::{self, IsString},
     AstToken,
 };
-use text_edit::{TextRange, TextSize};
 
 /// Holds documentation
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/lib.rs b/src/tools/rust-analyzer/crates/ide-db/src/lib.rs
index b764f85..81260c3 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/lib.rs
@@ -19,6 +19,7 @@
 pub mod search;
 pub mod source_change;
 pub mod symbol_index;
+pub mod text_edit;
 pub mod traits;
 pub mod ty_filter;
 pub mod use_trivial_constructor;
@@ -36,6 +37,7 @@
 pub mod syntax_helpers {
     pub mod format_string;
     pub mod format_string_exprs;
+    pub mod tree_diff;
     pub use hir::prettify_macro_expansion;
     pub mod node_ext;
     pub mod suggest_name;
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/rename.rs b/src/tools/rust-analyzer/crates/ide-db/src/rename.rs
index f1404ed9..1d1679c 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/rename.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/rename.rs
@@ -22,6 +22,7 @@
 //! Our current behavior is ¯\_(ツ)_/¯.
 use std::fmt;
 
+use crate::text_edit::{TextEdit, TextEditBuilder};
 use base_db::AnchoredPathBuf;
 use either::Either;
 use hir::{FieldSource, FileRange, HirFileIdExt, InFile, ModuleSource, Semantics};
@@ -32,7 +33,6 @@
     utils::is_raw_identifier,
     AstNode, SyntaxKind, TextRange, T,
 };
-use text_edit::{TextEdit, TextEditBuilder};
 
 use crate::{
     defs::Definition,
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs b/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs
index 73073e9..27ff91d 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs
@@ -5,7 +5,8 @@
 
 use std::{collections::hash_map::Entry, iter, mem};
 
-use crate::{assists::Command, SnippetCap};
+use crate::text_edit::{TextEdit, TextEditBuilder};
+use crate::{assists::Command, syntax_helpers::tree_diff::diff, SnippetCap};
 use base_db::AnchoredPathBuf;
 use itertools::Itertools;
 use nohash_hasher::IntMap;
@@ -13,11 +14,9 @@
 use span::FileId;
 use stdx::never;
 use syntax::{
-    algo,
     syntax_editor::{SyntaxAnnotation, SyntaxEditor},
     AstNode, SyntaxElement, SyntaxNode, SyntaxNodePtr, SyntaxToken, TextRange, TextSize,
 };
-use text_edit::{TextEdit, TextEditBuilder};
 
 #[derive(Default, Debug, Clone)]
 pub struct SourceChange {
@@ -315,7 +314,7 @@
             }
 
             let mut edit = TextEdit::builder();
-            algo::diff(edit_result.old_root(), edit_result.new_root()).into_text_edit(&mut edit);
+            diff(edit_result.old_root(), edit_result.new_root()).into_text_edit(&mut edit);
             let edit = edit.finish();
 
             let snippet_edit =
@@ -334,7 +333,7 @@
         });
 
         if let Some(tm) = self.mutated_tree.take() {
-            algo::diff(&tm.immutable, &tm.mutable_clone).into_text_edit(&mut self.edit);
+            diff(&tm.immutable, &tm.mutable_clone).into_text_edit(&mut self.edit);
         }
 
         let edit = mem::take(&mut self.edit).finish();
@@ -373,7 +372,7 @@
         self.edit.replace(range, replace_with.into())
     }
     pub fn replace_ast<N: AstNode>(&mut self, old: N, new: N) {
-        algo::diff(old.syntax(), new.syntax()).into_text_edit(&mut self.edit)
+        diff(old.syntax(), new.syntax()).into_text_edit(&mut self.edit)
     }
     pub fn create_file(&mut self, dst: AnchoredPathBuf, content: impl Into<String>) {
         let file_system_edit = FileSystemEdit::CreateFile { dst, initial_contents: content.into() };
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/tree_diff.rs b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/tree_diff.rs
new file mode 100644
index 0000000..02e24c4
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/tree_diff.rs
@@ -0,0 +1,559 @@
+//! Basic tree diffing functionality.
+use rustc_hash::FxHashMap;
+use syntax::{NodeOrToken, SyntaxElement, SyntaxNode};
+
+use crate::{text_edit::TextEditBuilder, FxIndexMap};
+
+#[derive(Debug, Hash, PartialEq, Eq)]
+enum TreeDiffInsertPos {
+    After(SyntaxElement),
+    AsFirstChild(SyntaxElement),
+}
+
+#[derive(Debug)]
+pub struct TreeDiff {
+    replacements: FxHashMap<SyntaxElement, SyntaxElement>,
+    deletions: Vec<SyntaxElement>,
+    // the vec as well as the indexmap are both here to preserve order
+    insertions: FxIndexMap<TreeDiffInsertPos, Vec<SyntaxElement>>,
+}
+
+impl TreeDiff {
+    pub fn into_text_edit(&self, builder: &mut TextEditBuilder) {
+        let _p = tracing::info_span!("into_text_edit").entered();
+
+        for (anchor, to) in &self.insertions {
+            let offset = match anchor {
+                TreeDiffInsertPos::After(it) => it.text_range().end(),
+                TreeDiffInsertPos::AsFirstChild(it) => it.text_range().start(),
+            };
+            to.iter().for_each(|to| builder.insert(offset, to.to_string()));
+        }
+        for (from, to) in &self.replacements {
+            builder.replace(from.text_range(), to.to_string());
+        }
+        for text_range in self.deletions.iter().map(SyntaxElement::text_range) {
+            builder.delete(text_range);
+        }
+    }
+
+    pub fn is_empty(&self) -> bool {
+        self.replacements.is_empty() && self.deletions.is_empty() && self.insertions.is_empty()
+    }
+}
+
+/// Finds a (potentially minimal) diff, which, applied to `from`, will result in `to`.
+///
+/// Specifically, returns a structure that consists of a replacements, insertions and deletions
+/// such that applying this map on `from` will result in `to`.
+///
+/// This function tries to find a fine-grained diff.
+pub fn diff(from: &SyntaxNode, to: &SyntaxNode) -> TreeDiff {
+    let _p = tracing::info_span!("diff").entered();
+
+    let mut diff = TreeDiff {
+        replacements: FxHashMap::default(),
+        insertions: FxIndexMap::default(),
+        deletions: Vec::new(),
+    };
+    let (from, to) = (from.clone().into(), to.clone().into());
+
+    if !syntax_element_eq(&from, &to) {
+        go(&mut diff, from, to);
+    }
+    return diff;
+
+    fn syntax_element_eq(lhs: &SyntaxElement, rhs: &SyntaxElement) -> bool {
+        lhs.kind() == rhs.kind()
+            && lhs.text_range().len() == rhs.text_range().len()
+            && match (&lhs, &rhs) {
+                (NodeOrToken::Node(lhs), NodeOrToken::Node(rhs)) => {
+                    lhs == rhs || lhs.text() == rhs.text()
+                }
+                (NodeOrToken::Token(lhs), NodeOrToken::Token(rhs)) => lhs.text() == rhs.text(),
+                _ => false,
+            }
+    }
+
+    // FIXME: this is horribly inefficient. I bet there's a cool algorithm to diff trees properly.
+    fn go(diff: &mut TreeDiff, lhs: SyntaxElement, rhs: SyntaxElement) {
+        let (lhs, rhs) = match lhs.as_node().zip(rhs.as_node()) {
+            Some((lhs, rhs)) => (lhs, rhs),
+            _ => {
+                cov_mark::hit!(diff_node_token_replace);
+                diff.replacements.insert(lhs, rhs);
+                return;
+            }
+        };
+
+        let mut look_ahead_scratch = Vec::default();
+
+        let mut rhs_children = rhs.children_with_tokens();
+        let mut lhs_children = lhs.children_with_tokens();
+        let mut last_lhs = None;
+        loop {
+            let lhs_child = lhs_children.next();
+            match (lhs_child.clone(), rhs_children.next()) {
+                (None, None) => break,
+                (None, Some(element)) => {
+                    let insert_pos = match last_lhs.clone() {
+                        Some(prev) => {
+                            cov_mark::hit!(diff_insert);
+                            TreeDiffInsertPos::After(prev)
+                        }
+                        // first iteration, insert into out parent as the first child
+                        None => {
+                            cov_mark::hit!(diff_insert_as_first_child);
+                            TreeDiffInsertPos::AsFirstChild(lhs.clone().into())
+                        }
+                    };
+                    diff.insertions.entry(insert_pos).or_default().push(element);
+                }
+                (Some(element), None) => {
+                    cov_mark::hit!(diff_delete);
+                    diff.deletions.push(element);
+                }
+                (Some(ref lhs_ele), Some(ref rhs_ele)) if syntax_element_eq(lhs_ele, rhs_ele) => {}
+                (Some(lhs_ele), Some(rhs_ele)) => {
+                    // nodes differ, look for lhs_ele in rhs, if its found we can mark everything up
+                    // until that element as insertions. This is important to keep the diff minimal
+                    // in regards to insertions that have been actually done, this is important for
+                    // use insertions as we do not want to replace the entire module node.
+                    look_ahead_scratch.push(rhs_ele.clone());
+                    let mut rhs_children_clone = rhs_children.clone();
+                    let mut insert = false;
+                    for rhs_child in &mut rhs_children_clone {
+                        if syntax_element_eq(&lhs_ele, &rhs_child) {
+                            cov_mark::hit!(diff_insertions);
+                            insert = true;
+                            break;
+                        }
+                        look_ahead_scratch.push(rhs_child);
+                    }
+                    let drain = look_ahead_scratch.drain(..);
+                    if insert {
+                        let insert_pos = if let Some(prev) = last_lhs.clone().filter(|_| insert) {
+                            TreeDiffInsertPos::After(prev)
+                        } else {
+                            cov_mark::hit!(insert_first_child);
+                            TreeDiffInsertPos::AsFirstChild(lhs.clone().into())
+                        };
+
+                        diff.insertions.entry(insert_pos).or_default().extend(drain);
+                        rhs_children = rhs_children_clone;
+                    } else {
+                        go(diff, lhs_ele, rhs_ele);
+                    }
+                }
+            }
+            last_lhs = lhs_child.or(last_lhs);
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use expect_test::{expect, Expect};
+    use itertools::Itertools;
+    use parser::{Edition, SyntaxKind};
+    use syntax::{AstNode, SourceFile, SyntaxElement};
+
+    use crate::text_edit::TextEdit;
+
+    #[test]
+    fn replace_node_token() {
+        cov_mark::check!(diff_node_token_replace);
+        check_diff(
+            r#"use node;"#,
+            r#"ident"#,
+            expect![[r#"
+                insertions:
+
+
+
+                replacements:
+
+                Line 0: Token(USE_KW@0..3 "use") -> ident
+
+                deletions:
+
+                Line 1: " "
+                Line 1: node
+                Line 1: ;
+            "#]],
+        );
+    }
+
+    #[test]
+    fn replace_parent() {
+        cov_mark::check!(diff_insert_as_first_child);
+        check_diff(
+            r#""#,
+            r#"use foo::bar;"#,
+            expect![[r#"
+                insertions:
+
+                Line 0: AsFirstChild(Node(SOURCE_FILE@0..0))
+                -> use foo::bar;
+
+                replacements:
+
+
+
+                deletions:
+
+
+            "#]],
+        );
+    }
+
+    #[test]
+    fn insert_last() {
+        cov_mark::check!(diff_insert);
+        check_diff(
+            r#"
+use foo;
+use bar;"#,
+            r#"
+use foo;
+use bar;
+use baz;"#,
+            expect![[r#"
+                insertions:
+
+                Line 2: After(Node(USE@10..18))
+                -> "\n"
+                -> use baz;
+
+                replacements:
+
+
+
+                deletions:
+
+
+            "#]],
+        );
+    }
+
+    #[test]
+    fn insert_middle() {
+        check_diff(
+            r#"
+use foo;
+use baz;"#,
+            r#"
+use foo;
+use bar;
+use baz;"#,
+            expect![[r#"
+                insertions:
+
+                Line 2: After(Token(WHITESPACE@9..10 "\n"))
+                -> use bar;
+                -> "\n"
+
+                replacements:
+
+
+
+                deletions:
+
+
+            "#]],
+        )
+    }
+
+    #[test]
+    fn insert_first() {
+        check_diff(
+            r#"
+use bar;
+use baz;"#,
+            r#"
+use foo;
+use bar;
+use baz;"#,
+            expect![[r#"
+                insertions:
+
+                Line 0: After(Token(WHITESPACE@0..1 "\n"))
+                -> use foo;
+                -> "\n"
+
+                replacements:
+
+
+
+                deletions:
+
+
+            "#]],
+        )
+    }
+
+    #[test]
+    fn first_child_insertion() {
+        cov_mark::check!(insert_first_child);
+        check_diff(
+            r#"fn main() {
+        stdi
+    }"#,
+            r#"use foo::bar;
+
+    fn main() {
+        stdi
+    }"#,
+            expect![[r#"
+                insertions:
+
+                Line 0: AsFirstChild(Node(SOURCE_FILE@0..30))
+                -> use foo::bar;
+                -> "\n\n    "
+
+                replacements:
+
+
+
+                deletions:
+
+
+            "#]],
+        );
+    }
+
+    #[test]
+    fn delete_last() {
+        cov_mark::check!(diff_delete);
+        check_diff(
+            r#"use foo;
+            use bar;"#,
+            r#"use foo;"#,
+            expect![[r#"
+                insertions:
+
+
+
+                replacements:
+
+
+
+                deletions:
+
+                Line 1: "\n            "
+                Line 2: use bar;
+            "#]],
+        );
+    }
+
+    #[test]
+    fn delete_middle() {
+        cov_mark::check!(diff_insertions);
+        check_diff(
+            r#"
+use expect_test::{expect, Expect};
+use text_edit::TextEdit;
+
+use crate::AstNode;
+"#,
+            r#"
+use expect_test::{expect, Expect};
+
+use crate::AstNode;
+"#,
+            expect![[r#"
+                insertions:
+
+                Line 1: After(Node(USE@1..35))
+                -> "\n\n"
+                -> use crate::AstNode;
+
+                replacements:
+
+
+
+                deletions:
+
+                Line 2: use text_edit::TextEdit;
+                Line 3: "\n\n"
+                Line 4: use crate::AstNode;
+                Line 5: "\n"
+            "#]],
+        )
+    }
+
+    #[test]
+    fn delete_first() {
+        check_diff(
+            r#"
+use text_edit::TextEdit;
+
+use crate::AstNode;
+"#,
+            r#"
+use crate::AstNode;
+"#,
+            expect![[r#"
+                insertions:
+
+
+
+                replacements:
+
+                Line 2: Token(IDENT@5..14 "text_edit") -> crate
+                Line 2: Token(IDENT@16..24 "TextEdit") -> AstNode
+                Line 2: Token(WHITESPACE@25..27 "\n\n") -> "\n"
+
+                deletions:
+
+                Line 3: use crate::AstNode;
+                Line 4: "\n"
+            "#]],
+        )
+    }
+
+    #[test]
+    fn merge_use() {
+        check_diff(
+            r#"
+use std::{
+    fmt,
+    hash::BuildHasherDefault,
+    ops::{self, RangeInclusive},
+};
+"#,
+            r#"
+use std::fmt;
+use std::hash::BuildHasherDefault;
+use std::ops::{self, RangeInclusive};
+"#,
+            expect![[r#"
+                insertions:
+
+                Line 2: After(Node(PATH_SEGMENT@5..8))
+                -> ::
+                -> fmt
+                Line 6: After(Token(WHITESPACE@86..87 "\n"))
+                -> use std::hash::BuildHasherDefault;
+                -> "\n"
+                -> use std::ops::{self, RangeInclusive};
+                -> "\n"
+
+                replacements:
+
+                Line 2: Token(IDENT@5..8 "std") -> std
+
+                deletions:
+
+                Line 2: ::
+                Line 2: {
+                    fmt,
+                    hash::BuildHasherDefault,
+                    ops::{self, RangeInclusive},
+                }
+            "#]],
+        )
+    }
+
+    #[test]
+    fn early_return_assist() {
+        check_diff(
+            r#"
+fn main() {
+    if let Ok(x) = Err(92) {
+        foo(x);
+    }
+}
+            "#,
+            r#"
+fn main() {
+    let x = match Err(92) {
+        Ok(it) => it,
+        _ => return,
+    };
+    foo(x);
+}
+            "#,
+            expect![[r#"
+                insertions:
+
+                Line 3: After(Node(BLOCK_EXPR@40..63))
+                -> " "
+                -> match Err(92) {
+                        Ok(it) => it,
+                        _ => return,
+                    }
+                -> ;
+                Line 3: After(Node(IF_EXPR@17..63))
+                -> "\n    "
+                -> foo(x);
+
+                replacements:
+
+                Line 3: Token(IF_KW@17..19 "if") -> let
+                Line 3: Token(LET_KW@20..23 "let") -> x
+                Line 3: Node(BLOCK_EXPR@40..63) -> =
+
+                deletions:
+
+                Line 3: " "
+                Line 3: Ok(x)
+                Line 3: " "
+                Line 3: =
+                Line 3: " "
+                Line 3: Err(92)
+            "#]],
+        )
+    }
+
+    fn check_diff(from: &str, to: &str, expected_diff: Expect) {
+        let from_node = SourceFile::parse(from, Edition::CURRENT).tree().syntax().clone();
+        let to_node = SourceFile::parse(to, Edition::CURRENT).tree().syntax().clone();
+        let diff = super::diff(&from_node, &to_node);
+
+        let line_number =
+            |syn: &SyntaxElement| from[..syn.text_range().start().into()].lines().count();
+
+        let fmt_syntax = |syn: &SyntaxElement| match syn.kind() {
+            SyntaxKind::WHITESPACE => format!("{:?}", syn.to_string()),
+            _ => format!("{syn}"),
+        };
+
+        let insertions =
+            diff.insertions.iter().format_with("\n", |(k, v), f| -> Result<(), std::fmt::Error> {
+                f(&format!(
+                    "Line {}: {:?}\n-> {}",
+                    line_number(match k {
+                        super::TreeDiffInsertPos::After(syn) => syn,
+                        super::TreeDiffInsertPos::AsFirstChild(syn) => syn,
+                    }),
+                    k,
+                    v.iter().format_with("\n-> ", |v, f| f(&fmt_syntax(v)))
+                ))
+            });
+
+        let replacements = diff
+            .replacements
+            .iter()
+            .sorted_by_key(|(syntax, _)| syntax.text_range().start())
+            .format_with("\n", |(k, v), f| {
+                f(&format!("Line {}: {k:?} -> {}", line_number(k), fmt_syntax(v)))
+            });
+
+        let deletions = diff
+            .deletions
+            .iter()
+            .format_with("\n", |v, f| f(&format!("Line {}: {}", line_number(v), fmt_syntax(v))));
+
+        let actual = format!(
+            "insertions:\n\n{insertions}\n\nreplacements:\n\n{replacements}\n\ndeletions:\n\n{deletions}\n"
+        );
+        expected_diff.assert_eq(&actual);
+
+        let mut from = from.to_owned();
+        let mut text_edit = TextEdit::builder();
+        diff.into_text_edit(&mut text_edit);
+        text_edit.finish().apply(&mut from);
+        assert_eq!(&*from, to, "diff did not turn `from` to `to`");
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/text-edit/src/lib.rs b/src/tools/rust-analyzer/crates/ide-db/src/text_edit.rs
similarity index 98%
rename from src/tools/rust-analyzer/crates/text-edit/src/lib.rs
rename to src/tools/rust-analyzer/crates/ide-db/src/text_edit.rs
index 3efe085..0c675f0 100644
--- a/src/tools/rust-analyzer/crates/text-edit/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/text_edit.rs
@@ -5,8 +5,8 @@
 //! rust-analyzer.
 
 use itertools::Itertools;
+pub use span::{TextRange, TextSize};
 use std::cmp::max;
-pub use text_size::{TextRange, TextSize};
 
 /// `InsertDelete` -- a single "atomic" change to text
 ///
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/Cargo.toml b/src/tools/rust-analyzer/crates/ide-diagnostics/Cargo.toml
index bf54f4a..281a08e 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/Cargo.toml
@@ -22,7 +22,6 @@
 # local deps
 stdx.workspace = true
 syntax.workspace = true
-text-edit.workspace = true
 cfg.workspace = true
 hir.workspace = true
 ide-db.workspace = true
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/field_shorthand.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/field_shorthand.rs
index c7071d1..876c2cc 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/field_shorthand.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/field_shorthand.rs
@@ -1,9 +1,9 @@
 //! Suggests shortening `Foo { field: field }` to `Foo { field }` in both
 //! expressions and patterns.
 
+use ide_db::text_edit::TextEdit;
 use ide_db::{source_change::SourceChange, EditionedFileId, FileRange};
 use syntax::{ast, match_ast, AstNode, SyntaxNode};
-use text_edit::TextEdit;
 
 use crate::{fix, Diagnostic, DiagnosticCode};
 
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/inactive_code.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/inactive_code.rs
index 1f8f805..4c0c685 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/inactive_code.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/inactive_code.rs
@@ -195,4 +195,20 @@
 "#,
         );
     }
+
+    #[test]
+    fn cfg_true_false() {
+        check(
+            r#"
+  #[cfg(false)] fn inactive() {}
+//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: false is disabled
+
+  #[cfg(true)] fn active() {}
+
+  #[cfg(any(not(true)), false)] fn inactive2() {}
+//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: true is enabled
+
+"#,
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs
index ccb33fe..dca889d 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs
@@ -2,6 +2,7 @@
 //! example.
 
 use hir::{ImportPathConfig, PathResolution, Semantics};
+use ide_db::text_edit::TextEdit;
 use ide_db::{
     helpers::mod_path_to_ast,
     imports::insert_use::{insert_use, ImportScope},
@@ -14,7 +15,6 @@
     ast::{self, make},
     Edition, SyntaxKind, SyntaxNode,
 };
-use text_edit::TextEdit;
 
 use crate::{fix, Diagnostic, DiagnosticCode, DiagnosticsConfig, Severity};
 
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs
index 3a622c6..fd1044e 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs
@@ -5,15 +5,14 @@
 };
 use ide_db::{
     assists::Assist, famous_defs::FamousDefs, imports::import_assets::item_for_path_search,
-    source_change::SourceChange, use_trivial_constructor::use_trivial_constructor, FxHashMap,
+    source_change::SourceChange, syntax_helpers::tree_diff::diff, text_edit::TextEdit,
+    use_trivial_constructor::use_trivial_constructor, FxHashMap,
 };
 use stdx::format_to;
 use syntax::{
-    algo,
     ast::{self, make},
     AstNode, Edition, SyntaxNode, SyntaxNodePtr, ToSmolStr,
 };
-use text_edit::TextEdit;
 
 use crate::{fix, Diagnostic, DiagnosticCode, DiagnosticsContext};
 
@@ -77,7 +76,7 @@
                 // FIXME: this also currently discards a lot of whitespace in the input... we really need a formatter here
                 builder.replace(old_range.range, new_syntax.to_string());
             } else {
-                algo::diff(old_syntax, new_syntax).into_text_edit(&mut builder);
+                diff(old_syntax, new_syntax).into_text_edit(&mut builder);
             }
             builder.finish()
         };
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs
index b18219c..a630d3c 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs
@@ -1,9 +1,9 @@
 use hir::db::ExpandDatabase;
 use hir::HirFileIdExt;
+use ide_db::text_edit::TextEdit;
 use ide_db::{assists::Assist, source_change::SourceChange};
 use syntax::{ast, SyntaxNode};
 use syntax::{match_ast, AstNode};
-use text_edit::TextEdit;
 
 use crate::{fix, Diagnostic, DiagnosticCode, DiagnosticsContext};
 
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs
index acf1cf1..1397979 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs
@@ -1,7 +1,7 @@
 use hir::db::ExpandDatabase;
 use ide_db::source_change::SourceChange;
+use ide_db::text_edit::TextEdit;
 use syntax::{ast, AstNode, SyntaxKind, SyntaxNode, SyntaxNodePtr, SyntaxToken, T};
-use text_edit::TextEdit;
 
 use crate::{fix, Diagnostic, DiagnosticCode, DiagnosticsContext};
 
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs
index dfadef1..e5d8719 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs
@@ -1,11 +1,11 @@
 use either::Either;
 use hir::{db::ExpandDatabase, HasSource, HirDisplay, HirFileIdExt, Semantics, VariantId};
+use ide_db::text_edit::TextEdit;
 use ide_db::{source_change::SourceChange, EditionedFileId, RootDatabase};
 use syntax::{
     ast::{self, edit::IndentLevel, make},
     AstNode,
 };
-use text_edit::TextEdit;
 
 use crate::{fix, Assist, Diagnostic, DiagnosticCode, DiagnosticsContext};
 
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_trailing_return.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_trailing_return.rs
index 62bc1f3..c8e3cff 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_trailing_return.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_trailing_return.rs
@@ -1,7 +1,7 @@
 use hir::{db::ExpandDatabase, diagnostics::RemoveTrailingReturn, FileRange};
+use ide_db::text_edit::TextEdit;
 use ide_db::{assists::Assist, source_change::SourceChange};
 use syntax::{ast, AstNode};
-use text_edit::TextEdit;
 
 use crate::{adjusted_display_range, fix, Diagnostic, DiagnosticCode, DiagnosticsContext};
 
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_unnecessary_else.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_unnecessary_else.rs
index 448df1c..a46c486 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_unnecessary_else.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_unnecessary_else.rs
@@ -1,4 +1,5 @@
 use hir::{db::ExpandDatabase, diagnostics::RemoveUnnecessaryElse, HirFileIdExt};
+use ide_db::text_edit::TextEdit;
 use ide_db::{assists::Assist, source_change::SourceChange};
 use itertools::Itertools;
 use syntax::{
@@ -8,7 +9,6 @@
     },
     AstNode, SyntaxToken, TextRange,
 };
-use text_edit::TextEdit;
 
 use crate::{
     adjusted_display_range, fix, Diagnostic, DiagnosticCode, DiagnosticsContext, Severity,
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs
index 1864720..f481365 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs
@@ -1,10 +1,10 @@
 use hir::{db::ExpandDatabase, HirFileIdExt, InFile};
 use ide_db::source_change::SourceChange;
+use ide_db::text_edit::TextEdit;
 use syntax::{
     ast::{self, HasArgList},
     AstNode, TextRange,
 };
-use text_edit::TextEdit;
 
 use crate::{fix, Assist, Diagnostic, DiagnosticCode, DiagnosticsContext};
 
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs
index 3de51ca..1363a8f 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs
@@ -1,11 +1,11 @@
 use hir::{db::ExpandDatabase, HasSource, HirDisplay};
+use ide_db::text_edit::TextRange;
 use ide_db::{
     assists::{Assist, AssistId, AssistKind},
     label::Label,
     source_change::SourceChangeBuilder,
 };
 use syntax::ToSmolStr;
-use text_edit::TextRange;
 
 use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext};
 
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs
index 90f88d6..93fe937 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs
@@ -1,5 +1,6 @@
 use either::Either;
 use hir::{db::ExpandDatabase, ClosureStyle, HirDisplay, HirFileIdExt, InFile, Type};
+use ide_db::text_edit::TextEdit;
 use ide_db::{famous_defs::FamousDefs, source_change::SourceChange};
 use syntax::{
     ast::{
@@ -9,7 +10,6 @@
     },
     AstNode, AstPtr, TextSize,
 };
-use text_edit::TextEdit;
 
 use crate::{adjusted_display_range, fix, Assist, Diagnostic, DiagnosticCode, DiagnosticsContext};
 
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs
index 6994a7e..3ad84f7 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs
@@ -3,13 +3,13 @@
     term_search::{term_search, TermSearchConfig, TermSearchCtx},
     ClosureStyle, HirDisplay, ImportPathConfig,
 };
+use ide_db::text_edit::TextEdit;
 use ide_db::{
     assists::{Assist, AssistId, AssistKind, GroupLabel},
     label::Label,
     source_change::SourceChange,
 };
 use itertools::Itertools;
-use text_edit::TextEdit;
 
 use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext};
 
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs
index e0822fc..13591df 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs
@@ -3,6 +3,7 @@
 use std::iter;
 
 use hir::{db::DefDatabase, DefMap, InFile, ModuleSource};
+use ide_db::text_edit::TextEdit;
 use ide_db::{
     base_db::{FileLoader, SourceDatabase, SourceRootDatabase},
     source_change::SourceChange,
@@ -13,7 +14,6 @@
     ast::{self, edit::IndentLevel, HasModuleItem, HasName},
     AstNode, TextRange,
 };
-use text_edit::TextEdit;
 
 use crate::{fix, Assist, Diagnostic, DiagnosticCode, DiagnosticsContext, Severity};
 
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs
index 76d624c..656bedf 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs
@@ -1,6 +1,7 @@
 use std::iter;
 
 use hir::{db::ExpandDatabase, Adt, FileRange, HasSource, HirDisplay, InFile, Struct, Union};
+use ide_db::text_edit::TextEdit;
 use ide_db::{
     assists::{Assist, AssistId, AssistKind},
     helpers::is_editable_crate,
@@ -16,7 +17,6 @@
     ast::{edit::AstNodeEdit, Type},
     SyntaxNode,
 };
-use text_edit::TextEdit;
 
 use crate::{adjusted_display_range, Diagnostic, DiagnosticCode, DiagnosticsContext};
 
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_macro_call.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_macro_call.rs
index 5b59612..0d1c977 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_macro_call.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_macro_call.rs
@@ -82,4 +82,29 @@
 "#,
         );
     }
+
+    #[test]
+    fn no_unresolved_panic_inside_mod_inside_fn() {
+        check_diagnostics(
+            r#"
+//- /core.rs library crate:core
+#[macro_export]
+macro_rules! panic {
+    () => {};
+}
+
+//- /lib.rs crate:foo deps:core
+#[macro_use]
+extern crate core;
+
+fn foo() {
+    mod init {
+        pub fn init() {
+            panic!();
+        }
+    }
+}
+    "#,
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs
index c0d038a..81cb452 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs
@@ -1,4 +1,5 @@
 use hir::{db::ExpandDatabase, AssocItem, FileRange, HirDisplay, InFile};
+use ide_db::text_edit::TextEdit;
 use ide_db::{
     assists::{Assist, AssistId, AssistKind},
     label::Label,
@@ -8,7 +9,6 @@
     ast::{self, make, HasArgList},
     format_smolstr, AstNode, SmolStr, TextRange, ToSmolStr,
 };
-use text_edit::TextEdit;
 
 use crate::{adjusted_display_range, Diagnostic, DiagnosticCode, DiagnosticsContext};
 
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs
index 84007b1..67ece56 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs
@@ -1,4 +1,5 @@
 use hir::Name;
+use ide_db::text_edit::TextEdit;
 use ide_db::{
     assists::{Assist, AssistId, AssistKind},
     label::Label,
@@ -6,7 +7,6 @@
     FileRange, RootDatabase,
 };
 use syntax::{Edition, TextRange};
-use text_edit::TextEdit;
 
 use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext};
 
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/useless_braces.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/useless_braces.rs
index 2d380ae..e5c2eca 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/useless_braces.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/useless_braces.rs
@@ -1,8 +1,8 @@
 use hir::InFile;
+use ide_db::text_edit::TextEdit;
 use ide_db::{source_change::SourceChange, EditionedFileId, FileRange};
 use itertools::Itertools;
 use syntax::{ast, AstNode, SyntaxNode, SyntaxNodePtr};
-use text_edit::TextEdit;
 
 use crate::{fix, Diagnostic, DiagnosticCode};
 
diff --git a/src/tools/rust-analyzer/crates/ide-ssr/Cargo.toml b/src/tools/rust-analyzer/crates/ide-ssr/Cargo.toml
index fad62fa..2561467 100644
--- a/src/tools/rust-analyzer/crates/ide-ssr/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/ide-ssr/Cargo.toml
@@ -24,7 +24,6 @@
 parser.workspace = true
 stdx.workspace = true
 syntax.workspace = true
-text-edit.workspace = true
 
 [dev-dependencies]
 expect-test = "1.4.0"
@@ -34,4 +33,4 @@
 test-fixture.workspace = true
 
 [lints]
-workspace = true
\ No newline at end of file
+workspace = true
diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs
index 54236ea..eaca95d 100644
--- a/src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs
@@ -84,10 +84,10 @@
 
 use crate::{errors::bail, matching::MatchFailureReason};
 use hir::{FileRange, Semantics};
+use ide_db::text_edit::TextEdit;
 use ide_db::{base_db::SourceDatabase, EditionedFileId, FileId, FxHashMap, RootDatabase};
 use resolving::ResolvedRule;
 use syntax::{ast, AstNode, SyntaxNode, TextRange};
-use text_edit::TextEdit;
 
 // A structured search replace rule. Create by calling `parse` on a str.
 #[derive(Debug)]
diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/replacing.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/replacing.rs
index 6575660..11c1615 100644
--- a/src/tools/rust-analyzer/crates/ide-ssr/src/replacing.rs
+++ b/src/tools/rust-analyzer/crates/ide-ssr/src/replacing.rs
@@ -1,5 +1,6 @@
 //! Code for applying replacement templates for matches that have previously been found.
 
+use ide_db::text_edit::TextEdit;
 use ide_db::{FxHashMap, FxHashSet};
 use itertools::Itertools;
 use parser::Edition;
@@ -7,7 +8,6 @@
     ast::{self, AstNode, AstToken},
     SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken, TextRange, TextSize,
 };
-use text_edit::TextEdit;
 
 use crate::{fragments, resolving::ResolvedRule, Match, SsrMatches};
 
diff --git a/src/tools/rust-analyzer/crates/ide/Cargo.toml b/src/tools/rust-analyzer/crates/ide/Cargo.toml
index d976d60..7c66b36 100644
--- a/src/tools/rust-analyzer/crates/ide/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/ide/Cargo.toml
@@ -39,7 +39,6 @@
 stdx.workspace = true
 syntax.workspace = true
 span.workspace = true
-text-edit.workspace = true
 # ide should depend only on the top-level `hir` package. if you need
 # something from some `hir-xxx` subpackage, reexport the API via `hir`.
 hir.workspace = true
diff --git a/src/tools/rust-analyzer/crates/ide/src/file_structure.rs b/src/tools/rust-analyzer/crates/ide/src/file_structure.rs
index 9245818..055080a 100644
--- a/src/tools/rust-analyzer/crates/ide/src/file_structure.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/file_structure.rs
@@ -187,6 +187,24 @@
                 };
                 Some(node)
             },
+            ast::LetStmt(it) => {
+                let pat = it.pat()?;
+
+                let mut label = String::new();
+                collapse_ws(pat.syntax(), &mut label);
+
+                let node = StructureNode {
+                    parent: None,
+                    label,
+                    navigation_range: pat.syntax().text_range(),
+                    node_range: it.syntax().text_range(),
+                    kind: StructureNodeKind::SymbolKind(SymbolKind::Local),
+                    detail: it.ty().map(|ty| ty.to_string()),
+                    deprecated: false,
+                };
+
+                Some(node)
+            },
             ast::Macro(it) => decl(it, StructureNodeKind::SymbolKind(SymbolKind::Macro)),
             _ => None,
         }
@@ -308,6 +326,17 @@
 // endregion
 fn g() {}
 }
+
+fn let_statements() {
+    let x = 42;
+    let mut y = x;
+    let Foo {
+        ..
+    } = Foo { x };
+    if let None = Some(x) {}
+    _ = ();
+    let _ = g();
+}
 "#,
             expect![[r#"
                 [
@@ -633,6 +662,71 @@
                         ),
                         deprecated: false,
                     },
+                    StructureNode {
+                        parent: None,
+                        label: "let_statements",
+                        navigation_range: 641..655,
+                        node_range: 638..798,
+                        kind: SymbolKind(
+                            Function,
+                        ),
+                        detail: Some(
+                            "fn()",
+                        ),
+                        deprecated: false,
+                    },
+                    StructureNode {
+                        parent: Some(
+                            26,
+                        ),
+                        label: "x",
+                        navigation_range: 668..669,
+                        node_range: 664..675,
+                        kind: SymbolKind(
+                            Local,
+                        ),
+                        detail: None,
+                        deprecated: false,
+                    },
+                    StructureNode {
+                        parent: Some(
+                            26,
+                        ),
+                        label: "mut y",
+                        navigation_range: 684..689,
+                        node_range: 680..694,
+                        kind: SymbolKind(
+                            Local,
+                        ),
+                        detail: None,
+                        deprecated: false,
+                    },
+                    StructureNode {
+                        parent: Some(
+                            26,
+                        ),
+                        label: "Foo { .. }",
+                        navigation_range: 703..725,
+                        node_range: 699..738,
+                        kind: SymbolKind(
+                            Local,
+                        ),
+                        detail: None,
+                        deprecated: false,
+                    },
+                    StructureNode {
+                        parent: Some(
+                            26,
+                        ),
+                        label: "_",
+                        navigation_range: 788..789,
+                        node_range: 784..796,
+                        kind: SymbolKind(
+                            Local,
+                        ),
+                        detail: None,
+                        deprecated: false,
+                    },
                 ]
             "#]],
         );
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
index b6e46c3..c58ca0f 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
@@ -8,6 +8,7 @@
     sym, ClosureStyle, HasVisibility, HirDisplay, HirDisplayError, HirWrite, ModuleDef,
     ModuleDefId, Semantics,
 };
+use ide_db::text_edit::TextEdit;
 use ide_db::{famous_defs::FamousDefs, FileRange, RootDatabase};
 use itertools::Itertools;
 use smallvec::{smallvec, SmallVec};
@@ -17,7 +18,6 @@
     ast::{self, AstNode, HasGenericParams},
     format_smolstr, match_ast, SmolStr, SyntaxNode, TextRange, TextSize, WalkEvent,
 };
-use text_edit::TextEdit;
 
 use crate::{navigation_target::TryToNav, FileId};
 
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs
index 0e0d50b..4d7d6e2 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs
@@ -11,13 +11,13 @@
 };
 use ide_db::famous_defs::FamousDefs;
 
+use ide_db::text_edit::TextEditBuilder;
 use span::EditionedFileId;
 use stdx::never;
 use syntax::{
     ast::{self, make, AstNode},
     ted,
 };
-use text_edit::TextEditBuilder;
 
 use crate::{
     AdjustmentHints, AdjustmentHintsMode, InlayHint, InlayHintLabel, InlayHintLabelPart,
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/binding_mode.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/binding_mode.rs
index e38450b..cfe8657 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/binding_mode.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/binding_mode.rs
@@ -7,9 +7,9 @@
 use hir::Mutability;
 use ide_db::famous_defs::FamousDefs;
 
+use ide_db::text_edit::TextEditBuilder;
 use span::EditionedFileId;
 use syntax::ast::{self, AstNode};
-use text_edit::TextEditBuilder;
 
 use crate::{InlayHint, InlayHintLabel, InlayHintPosition, InlayHintsConfig, InlayKind};
 
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs
index 58d8f97..028ed16 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs
@@ -77,7 +77,7 @@
 #[cfg(test)]
 mod tests {
     use expect_test::{expect, Expect};
-    use text_edit::{TextRange, TextSize};
+    use ide_db::text_edit::{TextRange, TextSize};
 
     use crate::{
         fixture,
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_captures.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_captures.rs
index 628ddc6..906f2ac 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_captures.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_captures.rs
@@ -2,10 +2,10 @@
 //!
 //! Tests live in [`bind_pat`][super::bind_pat] module.
 use ide_db::famous_defs::FamousDefs;
+use ide_db::text_edit::{TextRange, TextSize};
 use span::EditionedFileId;
 use stdx::{never, TupleExt};
 use syntax::ast::{self, AstNode};
-use text_edit::{TextRange, TextSize};
 
 use crate::{
     InlayHint, InlayHintLabel, InlayHintLabelPart, InlayHintPosition, InlayHintsConfig, InlayKind,
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/discriminant.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/discriminant.rs
index 40d7367..cd77c3e 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/discriminant.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/discriminant.rs
@@ -5,10 +5,10 @@
 //! }
 //! ```
 use hir::Semantics;
+use ide_db::text_edit::TextEdit;
 use ide_db::{famous_defs::FamousDefs, RootDatabase};
 use span::EditionedFileId;
 use syntax::ast::{self, AstNode, HasName};
-use text_edit::TextEdit;
 
 use crate::{
     DiscriminantHints, InlayHint, InlayHintLabel, InlayHintPosition, InlayHintsConfig, InlayKind,
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_static.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_static.rs
index f15d190..1560df3 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_static.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_static.rs
@@ -4,12 +4,12 @@
 //! ```
 use either::Either;
 use ide_db::famous_defs::FamousDefs;
+use ide_db::text_edit::TextEdit;
 use span::EditionedFileId;
 use syntax::{
     ast::{self, AstNode},
     SyntaxKind,
 };
-use text_edit::TextEdit;
 
 use crate::{InlayHint, InlayHintPosition, InlayHintsConfig, InlayKind, LifetimeElisionHints};
 
diff --git a/src/tools/rust-analyzer/crates/ide/src/join_lines.rs b/src/tools/rust-analyzer/crates/ide/src/join_lines.rs
index 9d8ba90..5192f91 100644
--- a/src/tools/rust-analyzer/crates/ide/src/join_lines.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/join_lines.rs
@@ -8,7 +8,7 @@
     SyntaxToken, TextRange, TextSize, T,
 };
 
-use text_edit::{TextEdit, TextEditBuilder};
+use ide_db::text_edit::{TextEdit, TextEditBuilder};
 
 pub struct JoinLinesConfig {
     pub join_else_if: bool,
diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs
index d7163d5..d053c4b 100644
--- a/src/tools/rust-analyzer/crates/ide/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs
@@ -122,6 +122,7 @@
     CallableSnippets, CompletionConfig, CompletionFieldsToResolve, CompletionItem,
     CompletionItemKind, CompletionRelevance, Snippet, SnippetScope,
 };
+pub use ide_db::text_edit::{Indel, TextEdit};
 pub use ide_db::{
     base_db::{Cancelled, CrateGraph, CrateId, FileChange, SourceRoot, SourceRootId},
     documentation::Documentation,
@@ -139,7 +140,6 @@
 pub use ide_ssr::SsrError;
 pub use span::Edition;
 pub use syntax::{TextRange, TextSize};
-pub use text_edit::{Indel, TextEdit};
 
 pub type Cancellable<T> = Result<T, Cancelled>;
 
diff --git a/src/tools/rust-analyzer/crates/ide/src/move_item.rs b/src/tools/rust-analyzer/crates/ide/src/move_item.rs
index ea6cc9d..a232df2 100644
--- a/src/tools/rust-analyzer/crates/ide/src/move_item.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/move_item.rs
@@ -1,10 +1,11 @@
 use std::{iter::once, mem};
 
 use hir::Semantics;
+use ide_db::syntax_helpers::tree_diff::diff;
+use ide_db::text_edit::{TextEdit, TextEditBuilder};
 use ide_db::{helpers::pick_best_token, FileRange, RootDatabase};
 use itertools::Itertools;
-use syntax::{algo, ast, match_ast, AstNode, SyntaxElement, SyntaxKind, SyntaxNode, TextRange};
-use text_edit::{TextEdit, TextEditBuilder};
+use syntax::{ast, match_ast, AstNode, SyntaxElement, SyntaxKind, SyntaxNode, TextRange};
 
 #[derive(Copy, Clone, Debug)]
 pub enum Direction {
@@ -166,7 +167,7 @@
 
     let mut edit = TextEditBuilder::default();
 
-    algo::diff(first, second).into_text_edit(&mut edit);
+    diff(first, second).into_text_edit(&mut edit);
     edit.replace(second.text_range(), first_with_cursor);
 
     edit.finish()
diff --git a/src/tools/rust-analyzer/crates/ide/src/rename.rs b/src/tools/rust-analyzer/crates/ide/src/rename.rs
index f17c1fa..665fc95 100644
--- a/src/tools/rust-analyzer/crates/ide/src/rename.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/rename.rs
@@ -15,7 +15,7 @@
 use stdx::{always, never};
 use syntax::{ast, AstNode, SyntaxKind, SyntaxNode, TextRange, TextSize};
 
-use text_edit::TextEdit;
+use ide_db::text_edit::TextEdit;
 
 use crate::{FilePosition, RangeInfo, SourceChange};
 
@@ -449,9 +449,9 @@
 mod tests {
     use expect_test::{expect, Expect};
     use ide_db::source_change::SourceChange;
+    use ide_db::text_edit::TextEdit;
     use stdx::trim_indent;
     use test_utils::assert_eq_text;
-    use text_edit::TextEdit;
 
     use crate::fixture;
 
diff --git a/src/tools/rust-analyzer/crates/ide/src/typing.rs b/src/tools/rust-analyzer/crates/ide/src/typing.rs
index a09e1e8..9bb5de9 100644
--- a/src/tools/rust-analyzer/crates/ide/src/typing.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/typing.rs
@@ -23,7 +23,7 @@
     AstNode, Parse, SourceFile, SyntaxKind, TextRange, TextSize, T,
 };
 
-use text_edit::{Indel, TextEdit};
+use ide_db::text_edit::TextEdit;
 
 use crate::SourceChange;
 
@@ -126,7 +126,7 @@
         return None;
     }
     // FIXME: Edition
-    let file = file.reparse(&Indel::delete(range), span::Edition::CURRENT_FIXME);
+    let file = file.reparse(range, "", span::Edition::CURRENT_FIXME);
 
     if let Some(edit) = bracket_expr(&file.tree(), offset, opening_bracket, closing_bracket) {
         return Some(edit);
diff --git a/src/tools/rust-analyzer/crates/ide/src/typing/on_enter.rs b/src/tools/rust-analyzer/crates/ide/src/typing/on_enter.rs
index 6e56bd6..773e352 100644
--- a/src/tools/rust-analyzer/crates/ide/src/typing/on_enter.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/typing/on_enter.rs
@@ -12,7 +12,7 @@
     SyntaxNode, SyntaxToken, TextRange, TextSize, TokenAtOffset,
 };
 
-use text_edit::TextEdit;
+use ide_db::text_edit::TextEdit;
 
 // Feature: On Enter
 //
diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model.txt b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model.txt
index 3401d7f..880e90c 100644
--- a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model.txt
+++ b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model.txt
@@ -19,6 +19,7 @@
             [
                 "rust_analyzer",
                 "test",
+                "true",
             ],
         ),
         potential_cfg_options: None,
@@ -81,6 +82,7 @@
             [
                 "rust_analyzer",
                 "test",
+                "true",
             ],
         ),
         potential_cfg_options: None,
@@ -151,6 +153,7 @@
             [
                 "rust_analyzer",
                 "test",
+                "true",
             ],
         ),
         potential_cfg_options: None,
@@ -221,6 +224,7 @@
             [
                 "rust_analyzer",
                 "test",
+                "true",
             ],
         ),
         potential_cfg_options: None,
@@ -291,6 +295,7 @@
             [
                 "feature=default",
                 "feature=std",
+                "true",
             ],
         ),
         potential_cfg_options: Some(
@@ -303,6 +308,7 @@
                     "feature=rustc-dep-of-std",
                     "feature=std",
                     "feature=use_std",
+                    "true",
                 ],
             ),
         ),
diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt
index 3401d7f..880e90c 100644
--- a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt
+++ b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt
@@ -19,6 +19,7 @@
             [
                 "rust_analyzer",
                 "test",
+                "true",
             ],
         ),
         potential_cfg_options: None,
@@ -81,6 +82,7 @@
             [
                 "rust_analyzer",
                 "test",
+                "true",
             ],
         ),
         potential_cfg_options: None,
@@ -151,6 +153,7 @@
             [
                 "rust_analyzer",
                 "test",
+                "true",
             ],
         ),
         potential_cfg_options: None,
@@ -221,6 +224,7 @@
             [
                 "rust_analyzer",
                 "test",
+                "true",
             ],
         ),
         potential_cfg_options: None,
@@ -291,6 +295,7 @@
             [
                 "feature=default",
                 "feature=std",
+                "true",
             ],
         ),
         potential_cfg_options: Some(
@@ -303,6 +308,7 @@
                     "feature=rustc-dep-of-std",
                     "feature=std",
                     "feature=use_std",
+                    "true",
                 ],
             ),
         ),
diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt
index 491568d..7746acd 100644
--- a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt
+++ b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt
@@ -18,6 +18,7 @@
         cfg_options: CfgOptions(
             [
                 "rust_analyzer",
+                "true",
             ],
         ),
         potential_cfg_options: None,
@@ -79,6 +80,7 @@
         cfg_options: CfgOptions(
             [
                 "rust_analyzer",
+                "true",
             ],
         ),
         potential_cfg_options: None,
@@ -148,6 +150,7 @@
         cfg_options: CfgOptions(
             [
                 "rust_analyzer",
+                "true",
             ],
         ),
         potential_cfg_options: None,
@@ -217,6 +220,7 @@
         cfg_options: CfgOptions(
             [
                 "rust_analyzer",
+                "true",
             ],
         ),
         potential_cfg_options: None,
@@ -287,6 +291,7 @@
             [
                 "feature=default",
                 "feature=std",
+                "true",
             ],
         ),
         potential_cfg_options: Some(
@@ -299,6 +304,7 @@
                     "feature=rustc-dep-of-std",
                     "feature=std",
                     "feature=use_std",
+                    "true",
                 ],
             ),
         ),
diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_cfg_groups.txt b/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_cfg_groups.txt
index 8261e5a..90f41a9 100644
--- a/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_cfg_groups.txt
+++ b/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_cfg_groups.txt
@@ -17,6 +17,7 @@
             [
                 "debug_assertions",
                 "miri",
+                "true",
             ],
         ),
         potential_cfg_options: None,
@@ -56,6 +57,7 @@
             [
                 "debug_assertions",
                 "miri",
+                "true",
             ],
         ),
         potential_cfg_options: None,
@@ -86,6 +88,7 @@
             [
                 "debug_assertions",
                 "miri",
+                "true",
             ],
         ),
         potential_cfg_options: None,
@@ -116,6 +119,7 @@
             [
                 "debug_assertions",
                 "miri",
+                "true",
             ],
         ),
         potential_cfg_options: None,
@@ -146,6 +150,7 @@
             [
                 "debug_assertions",
                 "miri",
+                "true",
             ],
         ),
         potential_cfg_options: None,
@@ -193,6 +198,7 @@
             [
                 "debug_assertions",
                 "miri",
+                "true",
             ],
         ),
         potential_cfg_options: None,
@@ -223,6 +229,7 @@
             [
                 "debug_assertions",
                 "miri",
+                "true",
             ],
         ),
         potential_cfg_options: None,
@@ -318,6 +325,7 @@
             [
                 "debug_assertions",
                 "miri",
+                "true",
             ],
         ),
         potential_cfg_options: None,
@@ -348,6 +356,7 @@
             [
                 "debug_assertions",
                 "miri",
+                "true",
             ],
         ),
         potential_cfg_options: None,
@@ -378,6 +387,7 @@
             [
                 "debug_assertions",
                 "miri",
+                "true",
             ],
         ),
         potential_cfg_options: None,
@@ -410,6 +420,7 @@
                 "group1_other_cfg=other_config",
                 "group2_cfg=yet_another_config",
                 "rust_analyzer",
+                "true",
             ],
         ),
         potential_cfg_options: None,
@@ -485,6 +496,7 @@
                 "group2_cfg=fourth_config",
                 "group2_cfg=yet_another_config",
                 "rust_analyzer",
+                "true",
                 "unrelated_cfg",
             ],
         ),
diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt b/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt
index c123df8..a0e14b8 100644
--- a/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt
+++ b/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt
@@ -17,6 +17,7 @@
             [
                 "debug_assertions",
                 "miri",
+                "true",
             ],
         ),
         potential_cfg_options: None,
@@ -56,6 +57,7 @@
             [
                 "debug_assertions",
                 "miri",
+                "true",
             ],
         ),
         potential_cfg_options: None,
@@ -86,6 +88,7 @@
             [
                 "debug_assertions",
                 "miri",
+                "true",
             ],
         ),
         potential_cfg_options: None,
@@ -116,6 +119,7 @@
             [
                 "debug_assertions",
                 "miri",
+                "true",
             ],
         ),
         potential_cfg_options: None,
@@ -146,6 +150,7 @@
             [
                 "debug_assertions",
                 "miri",
+                "true",
             ],
         ),
         potential_cfg_options: None,
@@ -193,6 +198,7 @@
             [
                 "debug_assertions",
                 "miri",
+                "true",
             ],
         ),
         potential_cfg_options: None,
@@ -223,6 +229,7 @@
             [
                 "debug_assertions",
                 "miri",
+                "true",
             ],
         ),
         potential_cfg_options: None,
@@ -318,6 +325,7 @@
             [
                 "debug_assertions",
                 "miri",
+                "true",
             ],
         ),
         potential_cfg_options: None,
@@ -348,6 +356,7 @@
             [
                 "debug_assertions",
                 "miri",
+                "true",
             ],
         ),
         potential_cfg_options: None,
@@ -378,6 +387,7 @@
             [
                 "debug_assertions",
                 "miri",
+                "true",
             ],
         ),
         potential_cfg_options: None,
@@ -407,6 +417,7 @@
         cfg_options: CfgOptions(
             [
                 "rust_analyzer",
+                "true",
             ],
         ),
         potential_cfg_options: None,
diff --git a/src/tools/rust-analyzer/crates/syntax/Cargo.toml b/src/tools/rust-analyzer/crates/syntax/Cargo.toml
index fcb9b0e..51eaea5 100644
--- a/src/tools/rust-analyzer/crates/syntax/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/syntax/Cargo.toml
@@ -27,7 +27,6 @@
 
 parser.workspace = true
 stdx.workspace = true
-text-edit.workspace = true
 
 [dev-dependencies]
 rayon.workspace = true
diff --git a/src/tools/rust-analyzer/crates/syntax/src/algo.rs b/src/tools/rust-analyzer/crates/syntax/src/algo.rs
index 8dc6d36..2acb215 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/algo.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/algo.rs
@@ -1,11 +1,6 @@
 //! Collection of assorted algorithms for syntax trees.
 
-use std::hash::BuildHasherDefault;
-
-use indexmap::IndexMap;
 use itertools::Itertools;
-use rustc_hash::FxHashMap;
-use text_edit::TextEditBuilder;
 
 use crate::{
     AstNode, Direction, NodeOrToken, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken, TextRange,
@@ -101,559 +96,3 @@
 pub fn has_errors(node: &SyntaxNode) -> bool {
     node.children().any(|it| it.kind() == SyntaxKind::ERROR)
 }
-
-type FxIndexMap<K, V> = IndexMap<K, V, BuildHasherDefault<rustc_hash::FxHasher>>;
-
-#[derive(Debug, Hash, PartialEq, Eq)]
-enum TreeDiffInsertPos {
-    After(SyntaxElement),
-    AsFirstChild(SyntaxElement),
-}
-
-#[derive(Debug)]
-pub struct TreeDiff {
-    replacements: FxHashMap<SyntaxElement, SyntaxElement>,
-    deletions: Vec<SyntaxElement>,
-    // the vec as well as the indexmap are both here to preserve order
-    insertions: FxIndexMap<TreeDiffInsertPos, Vec<SyntaxElement>>,
-}
-
-impl TreeDiff {
-    pub fn into_text_edit(&self, builder: &mut TextEditBuilder) {
-        let _p = tracing::info_span!("into_text_edit").entered();
-
-        for (anchor, to) in &self.insertions {
-            let offset = match anchor {
-                TreeDiffInsertPos::After(it) => it.text_range().end(),
-                TreeDiffInsertPos::AsFirstChild(it) => it.text_range().start(),
-            };
-            to.iter().for_each(|to| builder.insert(offset, to.to_string()));
-        }
-        for (from, to) in &self.replacements {
-            builder.replace(from.text_range(), to.to_string());
-        }
-        for text_range in self.deletions.iter().map(SyntaxElement::text_range) {
-            builder.delete(text_range);
-        }
-    }
-
-    pub fn is_empty(&self) -> bool {
-        self.replacements.is_empty() && self.deletions.is_empty() && self.insertions.is_empty()
-    }
-}
-
-/// Finds a (potentially minimal) diff, which, applied to `from`, will result in `to`.
-///
-/// Specifically, returns a structure that consists of a replacements, insertions and deletions
-/// such that applying this map on `from` will result in `to`.
-///
-/// This function tries to find a fine-grained diff.
-pub fn diff(from: &SyntaxNode, to: &SyntaxNode) -> TreeDiff {
-    let _p = tracing::info_span!("diff").entered();
-
-    let mut diff = TreeDiff {
-        replacements: FxHashMap::default(),
-        insertions: FxIndexMap::default(),
-        deletions: Vec::new(),
-    };
-    let (from, to) = (from.clone().into(), to.clone().into());
-
-    if !syntax_element_eq(&from, &to) {
-        go(&mut diff, from, to);
-    }
-    return diff;
-
-    fn syntax_element_eq(lhs: &SyntaxElement, rhs: &SyntaxElement) -> bool {
-        lhs.kind() == rhs.kind()
-            && lhs.text_range().len() == rhs.text_range().len()
-            && match (&lhs, &rhs) {
-                (NodeOrToken::Node(lhs), NodeOrToken::Node(rhs)) => {
-                    lhs == rhs || lhs.text() == rhs.text()
-                }
-                (NodeOrToken::Token(lhs), NodeOrToken::Token(rhs)) => lhs.text() == rhs.text(),
-                _ => false,
-            }
-    }
-
-    // FIXME: this is horribly inefficient. I bet there's a cool algorithm to diff trees properly.
-    fn go(diff: &mut TreeDiff, lhs: SyntaxElement, rhs: SyntaxElement) {
-        let (lhs, rhs) = match lhs.as_node().zip(rhs.as_node()) {
-            Some((lhs, rhs)) => (lhs, rhs),
-            _ => {
-                cov_mark::hit!(diff_node_token_replace);
-                diff.replacements.insert(lhs, rhs);
-                return;
-            }
-        };
-
-        let mut look_ahead_scratch = Vec::default();
-
-        let mut rhs_children = rhs.children_with_tokens();
-        let mut lhs_children = lhs.children_with_tokens();
-        let mut last_lhs = None;
-        loop {
-            let lhs_child = lhs_children.next();
-            match (lhs_child.clone(), rhs_children.next()) {
-                (None, None) => break,
-                (None, Some(element)) => {
-                    let insert_pos = match last_lhs.clone() {
-                        Some(prev) => {
-                            cov_mark::hit!(diff_insert);
-                            TreeDiffInsertPos::After(prev)
-                        }
-                        // first iteration, insert into out parent as the first child
-                        None => {
-                            cov_mark::hit!(diff_insert_as_first_child);
-                            TreeDiffInsertPos::AsFirstChild(lhs.clone().into())
-                        }
-                    };
-                    diff.insertions.entry(insert_pos).or_default().push(element);
-                }
-                (Some(element), None) => {
-                    cov_mark::hit!(diff_delete);
-                    diff.deletions.push(element);
-                }
-                (Some(ref lhs_ele), Some(ref rhs_ele)) if syntax_element_eq(lhs_ele, rhs_ele) => {}
-                (Some(lhs_ele), Some(rhs_ele)) => {
-                    // nodes differ, look for lhs_ele in rhs, if its found we can mark everything up
-                    // until that element as insertions. This is important to keep the diff minimal
-                    // in regards to insertions that have been actually done, this is important for
-                    // use insertions as we do not want to replace the entire module node.
-                    look_ahead_scratch.push(rhs_ele.clone());
-                    let mut rhs_children_clone = rhs_children.clone();
-                    let mut insert = false;
-                    for rhs_child in &mut rhs_children_clone {
-                        if syntax_element_eq(&lhs_ele, &rhs_child) {
-                            cov_mark::hit!(diff_insertions);
-                            insert = true;
-                            break;
-                        }
-                        look_ahead_scratch.push(rhs_child);
-                    }
-                    let drain = look_ahead_scratch.drain(..);
-                    if insert {
-                        let insert_pos = if let Some(prev) = last_lhs.clone().filter(|_| insert) {
-                            TreeDiffInsertPos::After(prev)
-                        } else {
-                            cov_mark::hit!(insert_first_child);
-                            TreeDiffInsertPos::AsFirstChild(lhs.clone().into())
-                        };
-
-                        diff.insertions.entry(insert_pos).or_default().extend(drain);
-                        rhs_children = rhs_children_clone;
-                    } else {
-                        go(diff, lhs_ele, rhs_ele);
-                    }
-                }
-            }
-            last_lhs = lhs_child.or(last_lhs);
-        }
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use expect_test::{expect, Expect};
-    use itertools::Itertools;
-    use parser::{Edition, SyntaxKind};
-    use text_edit::TextEdit;
-
-    use crate::{AstNode, SyntaxElement};
-
-    #[test]
-    fn replace_node_token() {
-        cov_mark::check!(diff_node_token_replace);
-        check_diff(
-            r#"use node;"#,
-            r#"ident"#,
-            expect![[r#"
-                insertions:
-
-
-
-                replacements:
-
-                Line 0: Token(USE_KW@0..3 "use") -> ident
-
-                deletions:
-
-                Line 1: " "
-                Line 1: node
-                Line 1: ;
-            "#]],
-        );
-    }
-
-    #[test]
-    fn replace_parent() {
-        cov_mark::check!(diff_insert_as_first_child);
-        check_diff(
-            r#""#,
-            r#"use foo::bar;"#,
-            expect![[r#"
-                insertions:
-
-                Line 0: AsFirstChild(Node(SOURCE_FILE@0..0))
-                -> use foo::bar;
-
-                replacements:
-
-
-
-                deletions:
-
-
-            "#]],
-        );
-    }
-
-    #[test]
-    fn insert_last() {
-        cov_mark::check!(diff_insert);
-        check_diff(
-            r#"
-use foo;
-use bar;"#,
-            r#"
-use foo;
-use bar;
-use baz;"#,
-            expect![[r#"
-                insertions:
-
-                Line 2: After(Node(USE@10..18))
-                -> "\n"
-                -> use baz;
-
-                replacements:
-
-
-
-                deletions:
-
-
-            "#]],
-        );
-    }
-
-    #[test]
-    fn insert_middle() {
-        check_diff(
-            r#"
-use foo;
-use baz;"#,
-            r#"
-use foo;
-use bar;
-use baz;"#,
-            expect![[r#"
-                insertions:
-
-                Line 2: After(Token(WHITESPACE@9..10 "\n"))
-                -> use bar;
-                -> "\n"
-
-                replacements:
-
-
-
-                deletions:
-
-
-            "#]],
-        )
-    }
-
-    #[test]
-    fn insert_first() {
-        check_diff(
-            r#"
-use bar;
-use baz;"#,
-            r#"
-use foo;
-use bar;
-use baz;"#,
-            expect![[r#"
-                insertions:
-
-                Line 0: After(Token(WHITESPACE@0..1 "\n"))
-                -> use foo;
-                -> "\n"
-
-                replacements:
-
-
-
-                deletions:
-
-
-            "#]],
-        )
-    }
-
-    #[test]
-    fn first_child_insertion() {
-        cov_mark::check!(insert_first_child);
-        check_diff(
-            r#"fn main() {
-        stdi
-    }"#,
-            r#"use foo::bar;
-
-    fn main() {
-        stdi
-    }"#,
-            expect![[r#"
-                insertions:
-
-                Line 0: AsFirstChild(Node(SOURCE_FILE@0..30))
-                -> use foo::bar;
-                -> "\n\n    "
-
-                replacements:
-
-
-
-                deletions:
-
-
-            "#]],
-        );
-    }
-
-    #[test]
-    fn delete_last() {
-        cov_mark::check!(diff_delete);
-        check_diff(
-            r#"use foo;
-            use bar;"#,
-            r#"use foo;"#,
-            expect![[r#"
-                insertions:
-
-
-
-                replacements:
-
-
-
-                deletions:
-
-                Line 1: "\n            "
-                Line 2: use bar;
-            "#]],
-        );
-    }
-
-    #[test]
-    fn delete_middle() {
-        cov_mark::check!(diff_insertions);
-        check_diff(
-            r#"
-use expect_test::{expect, Expect};
-use text_edit::TextEdit;
-
-use crate::AstNode;
-"#,
-            r#"
-use expect_test::{expect, Expect};
-
-use crate::AstNode;
-"#,
-            expect![[r#"
-                insertions:
-
-                Line 1: After(Node(USE@1..35))
-                -> "\n\n"
-                -> use crate::AstNode;
-
-                replacements:
-
-
-
-                deletions:
-
-                Line 2: use text_edit::TextEdit;
-                Line 3: "\n\n"
-                Line 4: use crate::AstNode;
-                Line 5: "\n"
-            "#]],
-        )
-    }
-
-    #[test]
-    fn delete_first() {
-        check_diff(
-            r#"
-use text_edit::TextEdit;
-
-use crate::AstNode;
-"#,
-            r#"
-use crate::AstNode;
-"#,
-            expect![[r#"
-                insertions:
-
-
-
-                replacements:
-
-                Line 2: Token(IDENT@5..14 "text_edit") -> crate
-                Line 2: Token(IDENT@16..24 "TextEdit") -> AstNode
-                Line 2: Token(WHITESPACE@25..27 "\n\n") -> "\n"
-
-                deletions:
-
-                Line 3: use crate::AstNode;
-                Line 4: "\n"
-            "#]],
-        )
-    }
-
-    #[test]
-    fn merge_use() {
-        check_diff(
-            r#"
-use std::{
-    fmt,
-    hash::BuildHasherDefault,
-    ops::{self, RangeInclusive},
-};
-"#,
-            r#"
-use std::fmt;
-use std::hash::BuildHasherDefault;
-use std::ops::{self, RangeInclusive};
-"#,
-            expect![[r#"
-                insertions:
-
-                Line 2: After(Node(PATH_SEGMENT@5..8))
-                -> ::
-                -> fmt
-                Line 6: After(Token(WHITESPACE@86..87 "\n"))
-                -> use std::hash::BuildHasherDefault;
-                -> "\n"
-                -> use std::ops::{self, RangeInclusive};
-                -> "\n"
-
-                replacements:
-
-                Line 2: Token(IDENT@5..8 "std") -> std
-
-                deletions:
-
-                Line 2: ::
-                Line 2: {
-                    fmt,
-                    hash::BuildHasherDefault,
-                    ops::{self, RangeInclusive},
-                }
-            "#]],
-        )
-    }
-
-    #[test]
-    fn early_return_assist() {
-        check_diff(
-            r#"
-fn main() {
-    if let Ok(x) = Err(92) {
-        foo(x);
-    }
-}
-            "#,
-            r#"
-fn main() {
-    let x = match Err(92) {
-        Ok(it) => it,
-        _ => return,
-    };
-    foo(x);
-}
-            "#,
-            expect![[r#"
-                insertions:
-
-                Line 3: After(Node(BLOCK_EXPR@40..63))
-                -> " "
-                -> match Err(92) {
-                        Ok(it) => it,
-                        _ => return,
-                    }
-                -> ;
-                Line 3: After(Node(IF_EXPR@17..63))
-                -> "\n    "
-                -> foo(x);
-
-                replacements:
-
-                Line 3: Token(IF_KW@17..19 "if") -> let
-                Line 3: Token(LET_KW@20..23 "let") -> x
-                Line 3: Node(BLOCK_EXPR@40..63) -> =
-
-                deletions:
-
-                Line 3: " "
-                Line 3: Ok(x)
-                Line 3: " "
-                Line 3: =
-                Line 3: " "
-                Line 3: Err(92)
-            "#]],
-        )
-    }
-
-    fn check_diff(from: &str, to: &str, expected_diff: Expect) {
-        let from_node = crate::SourceFile::parse(from, Edition::CURRENT).tree().syntax().clone();
-        let to_node = crate::SourceFile::parse(to, Edition::CURRENT).tree().syntax().clone();
-        let diff = super::diff(&from_node, &to_node);
-
-        let line_number =
-            |syn: &SyntaxElement| from[..syn.text_range().start().into()].lines().count();
-
-        let fmt_syntax = |syn: &SyntaxElement| match syn.kind() {
-            SyntaxKind::WHITESPACE => format!("{:?}", syn.to_string()),
-            _ => format!("{syn}"),
-        };
-
-        let insertions =
-            diff.insertions.iter().format_with("\n", |(k, v), f| -> Result<(), std::fmt::Error> {
-                f(&format!(
-                    "Line {}: {:?}\n-> {}",
-                    line_number(match k {
-                        super::TreeDiffInsertPos::After(syn) => syn,
-                        super::TreeDiffInsertPos::AsFirstChild(syn) => syn,
-                    }),
-                    k,
-                    v.iter().format_with("\n-> ", |v, f| f(&fmt_syntax(v)))
-                ))
-            });
-
-        let replacements = diff
-            .replacements
-            .iter()
-            .sorted_by_key(|(syntax, _)| syntax.text_range().start())
-            .format_with("\n", |(k, v), f| {
-                f(&format!("Line {}: {k:?} -> {}", line_number(k), fmt_syntax(v)))
-            });
-
-        let deletions = diff
-            .deletions
-            .iter()
-            .format_with("\n", |v, f| f(&format!("Line {}: {}", line_number(v), fmt_syntax(v))));
-
-        let actual = format!(
-            "insertions:\n\n{insertions}\n\nreplacements:\n\n{replacements}\n\ndeletions:\n\n{deletions}\n"
-        );
-        expected_diff.assert_eq(&actual);
-
-        let mut from = from.to_owned();
-        let mut text_edit = TextEdit::builder();
-        diff.into_text_edit(&mut text_edit);
-        text_edit.finish().apply(&mut from);
-        assert_eq!(&*from, to, "diff did not turn `from` to `to`");
-    }
-}
diff --git a/src/tools/rust-analyzer/crates/syntax/src/fuzz.rs b/src/tools/rust-analyzer/crates/syntax/src/fuzz.rs
index 682dcd7..fd20e60 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/fuzz.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/fuzz.rs
@@ -5,7 +5,6 @@
 use std::str::{self, FromStr};
 
 use parser::Edition;
-use text_edit::Indel;
 
 use crate::{validation, AstNode, SourceFile, TextRange};
 
@@ -22,7 +21,8 @@
 #[derive(Debug, Clone)]
 pub struct CheckReparse {
     text: String,
-    edit: Indel,
+    delete: TextRange,
+    insert: String,
     edited_text: String,
 }
 
@@ -43,14 +43,13 @@
             TextRange::at(delete_start.try_into().unwrap(), delete_len.try_into().unwrap());
         let edited_text =
             format!("{}{}{}", &text[..delete_start], &insert, &text[delete_start + delete_len..]);
-        let edit = Indel { insert, delete };
-        Some(CheckReparse { text, edit, edited_text })
+        Some(CheckReparse { text, insert, delete, edited_text })
     }
 
     #[allow(clippy::print_stderr)]
     pub fn run(&self) {
         let parse = SourceFile::parse(&self.text, Edition::CURRENT);
-        let new_parse = parse.reparse(&self.edit, Edition::CURRENT);
+        let new_parse = parse.reparse(self.delete, &self.insert, Edition::CURRENT);
         check_file_invariants(&new_parse.tree());
         assert_eq!(&new_parse.tree().syntax().text().to_string(), &self.edited_text);
         let full_reparse = SourceFile::parse(&self.edited_text, Edition::CURRENT);
diff --git a/src/tools/rust-analyzer/crates/syntax/src/lib.rs b/src/tools/rust-analyzer/crates/syntax/src/lib.rs
index c1554c4..c9e9f46 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/lib.rs
@@ -44,10 +44,9 @@
 pub mod ted;
 pub mod utils;
 
-use std::marker::PhantomData;
+use std::{marker::PhantomData, ops::Range};
 
 use stdx::format_to;
-use text_edit::Indel;
 use triomphe::Arc;
 
 pub use crate::{
@@ -150,16 +149,22 @@
         buf
     }
 
-    pub fn reparse(&self, indel: &Indel, edition: Edition) -> Parse<SourceFile> {
-        self.incremental_reparse(indel, edition)
-            .unwrap_or_else(|| self.full_reparse(indel, edition))
+    pub fn reparse(&self, delete: TextRange, insert: &str, edition: Edition) -> Parse<SourceFile> {
+        self.incremental_reparse(delete, insert, edition)
+            .unwrap_or_else(|| self.full_reparse(delete, insert, edition))
     }
 
-    fn incremental_reparse(&self, indel: &Indel, edition: Edition) -> Option<Parse<SourceFile>> {
+    fn incremental_reparse(
+        &self,
+        delete: TextRange,
+        insert: &str,
+        edition: Edition,
+    ) -> Option<Parse<SourceFile>> {
         // FIXME: validation errors are not handled here
         parsing::incremental_reparse(
             self.tree().syntax(),
-            indel,
+            delete,
+            insert,
             self.errors.as_deref().unwrap_or_default().iter().cloned(),
             edition,
         )
@@ -170,9 +175,9 @@
         })
     }
 
-    fn full_reparse(&self, indel: &Indel, edition: Edition) -> Parse<SourceFile> {
+    fn full_reparse(&self, delete: TextRange, insert: &str, edition: Edition) -> Parse<SourceFile> {
         let mut text = self.tree().syntax().text().to_string();
-        indel.apply(&mut text);
+        text.replace_range(Range::<usize>::from(delete), insert);
         SourceFile::parse(&text, edition)
     }
 }
diff --git a/src/tools/rust-analyzer/crates/syntax/src/parsing/reparsing.rs b/src/tools/rust-analyzer/crates/syntax/src/parsing/reparsing.rs
index a5cc4e9..f2eab18 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/parsing/reparsing.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/parsing/reparsing.rs
@@ -6,8 +6,9 @@
 //!   - otherwise, we search for the nearest `{}` block which contains the edit
 //!     and try to parse only this block.
 
+use std::ops::Range;
+
 use parser::{Edition, Reparser};
-use text_edit::Indel;
 
 use crate::{
     parsing::build_tree,
@@ -19,38 +20,48 @@
 
 pub(crate) fn incremental_reparse(
     node: &SyntaxNode,
-    edit: &Indel,
+    delete: TextRange,
+    insert: &str,
     errors: impl IntoIterator<Item = SyntaxError>,
     edition: Edition,
 ) -> Option<(GreenNode, Vec<SyntaxError>, TextRange)> {
-    if let Some((green, new_errors, old_range)) = reparse_token(node, edit, edition) {
-        return Some((green, merge_errors(errors, new_errors, old_range, edit), old_range));
+    if let Some((green, new_errors, old_range)) = reparse_token(node, delete, insert, edition) {
+        return Some((
+            green,
+            merge_errors(errors, new_errors, old_range, delete, insert),
+            old_range,
+        ));
     }
 
-    if let Some((green, new_errors, old_range)) = reparse_block(node, edit, edition) {
-        return Some((green, merge_errors(errors, new_errors, old_range, edit), old_range));
+    if let Some((green, new_errors, old_range)) = reparse_block(node, delete, insert, edition) {
+        return Some((
+            green,
+            merge_errors(errors, new_errors, old_range, delete, insert),
+            old_range,
+        ));
     }
     None
 }
 
 fn reparse_token(
     root: &SyntaxNode,
-    edit: &Indel,
+    delete: TextRange,
+    insert: &str,
     edition: Edition,
 ) -> Option<(GreenNode, Vec<SyntaxError>, TextRange)> {
-    let prev_token = root.covering_element(edit.delete).as_token()?.clone();
+    let prev_token = root.covering_element(delete).as_token()?.clone();
     let prev_token_kind = prev_token.kind();
     match prev_token_kind {
         WHITESPACE | COMMENT | IDENT | STRING | BYTE_STRING | C_STRING => {
             if prev_token_kind == WHITESPACE || prev_token_kind == COMMENT {
                 // removing a new line may extends previous token
-                let deleted_range = edit.delete - prev_token.text_range().start();
+                let deleted_range = delete - prev_token.text_range().start();
                 if prev_token.text()[deleted_range].contains('\n') {
                     return None;
                 }
             }
 
-            let mut new_text = get_text_after_edit(prev_token.clone().into(), edit);
+            let mut new_text = get_text_after_edit(prev_token.clone().into(), delete, insert);
             let (new_token_kind, new_err) = parser::LexedStr::single_token(edition, &new_text)?;
 
             if new_token_kind != prev_token_kind
@@ -85,11 +96,12 @@
 
 fn reparse_block(
     root: &SyntaxNode,
-    edit: &Indel,
+    delete: TextRange,
+    insert: &str,
     edition: parser::Edition,
 ) -> Option<(GreenNode, Vec<SyntaxError>, TextRange)> {
-    let (node, reparser) = find_reparsable_node(root, edit.delete)?;
-    let text = get_text_after_edit(node.clone().into(), edit);
+    let (node, reparser) = find_reparsable_node(root, delete)?;
+    let text = get_text_after_edit(node.clone().into(), delete, insert);
 
     let lexed = parser::LexedStr::new(edition, text.as_str());
     let parser_input = lexed.to_input(edition);
@@ -104,14 +116,14 @@
     Some((node.replace_with(green), new_parser_errors, node.text_range()))
 }
 
-fn get_text_after_edit(element: SyntaxElement, edit: &Indel) -> String {
-    let edit = Indel::replace(edit.delete - element.text_range().start(), edit.insert.clone());
+fn get_text_after_edit(element: SyntaxElement, mut delete: TextRange, insert: &str) -> String {
+    delete -= element.text_range().start();
 
     let mut text = match element {
         NodeOrToken::Token(token) => token.text().to_owned(),
         NodeOrToken::Node(node) => node.text().to_string(),
     };
-    edit.apply(&mut text);
+    text.replace_range(Range::<usize>::from(delete), insert);
     text
 }
 
@@ -153,7 +165,8 @@
     old_errors: impl IntoIterator<Item = SyntaxError>,
     new_errors: Vec<SyntaxError>,
     range_before_reparse: TextRange,
-    edit: &Indel,
+    delete: TextRange,
+    insert: &str,
 ) -> Vec<SyntaxError> {
     let mut res = Vec::new();
 
@@ -162,8 +175,8 @@
         if old_err_range.end() <= range_before_reparse.start() {
             res.push(old_err);
         } else if old_err_range.start() >= range_before_reparse.end() {
-            let inserted_len = TextSize::of(&edit.insert);
-            res.push(old_err.with_range((old_err_range + inserted_len) - edit.delete.len()));
+            let inserted_len = TextSize::of(insert);
+            res.push(old_err.with_range((old_err_range + inserted_len) - delete.len()));
             // Note: extra parens are intentional to prevent uint underflow, HWAB (here was a bug)
         }
     }
@@ -177,6 +190,8 @@
 
 #[cfg(test)]
 mod tests {
+    use std::ops::Range;
+
     use parser::Edition;
     use test_utils::{assert_eq_text, extract_range};
 
@@ -185,10 +200,9 @@
 
     fn do_check(before: &str, replace_with: &str, reparsed_len: u32) {
         let (range, before) = extract_range(before);
-        let edit = Indel::replace(range, replace_with.to_owned());
         let after = {
             let mut after = before.clone();
-            edit.apply(&mut after);
+            after.replace_range(Range::<usize>::from(range), replace_with);
             after
         };
 
@@ -197,7 +211,8 @@
             let before = SourceFile::parse(&before, Edition::CURRENT);
             let (green, new_errors, range) = incremental_reparse(
                 before.tree().syntax(),
-                &edit,
+                range,
+                replace_with,
                 before.errors.as_deref().unwrap_or_default().iter().cloned(),
                 Edition::CURRENT,
             )
diff --git a/src/tools/rust-analyzer/crates/text-edit/Cargo.toml b/src/tools/rust-analyzer/crates/text-edit/Cargo.toml
deleted file mode 100644
index dc6b3d3..0000000
--- a/src/tools/rust-analyzer/crates/text-edit/Cargo.toml
+++ /dev/null
@@ -1,20 +0,0 @@
-[package]
-name = "text-edit"
-version = "0.0.0"
-repository.workspace = true
-description = "Representation of a `TextEdit` for rust-analyzer."
-
-authors.workspace = true
-edition.workspace = true
-license.workspace = true
-rust-version.workspace = true
-
-[lib]
-doctest = false
-
-[dependencies]
-itertools.workspace = true
-text-size.workspace = true
-
-[lints]
-workspace = true
\ No newline at end of file
diff --git a/src/tools/rust-analyzer/rust-version b/src/tools/rust-analyzer/rust-version
index bc32440..ffb312d 100644
--- a/src/tools/rust-analyzer/rust-version
+++ b/src/tools/rust-analyzer/rust-version
@@ -1 +1 @@
-1de57a5ce952c722f7053aeacfc6c90bc139b678
+a9d17627d241645a54c1134a20f1596127fedb60
diff --git a/src/tools/rustbook/Cargo.lock b/src/tools/rustbook/Cargo.lock
index 060deb1..27ccb20 100644
--- a/src/tools/rustbook/Cargo.lock
+++ b/src/tools/rustbook/Cargo.lock
@@ -1,6 +1,6 @@
 # This file is automatically @generated by Cargo.
 # It is not intended for manual editing.
-version = 3
+version = 4
 
 [[package]]
 name = "adler2"
@@ -704,6 +704,7 @@
  "semver",
  "serde_json",
  "tempfile",
+ "walkdir",
 ]
 
 [[package]]
diff --git a/src/tools/rustbook/src/main.rs b/src/tools/rustbook/src/main.rs
index 2118af6..f905b92 100644
--- a/src/tools/rustbook/src/main.rs
+++ b/src/tools/rustbook/src/main.rs
@@ -22,6 +22,11 @@
     .required(false)
     .value_parser(clap::value_parser!(String));
 
+    let root_arg = arg!(--"rust-root" <ROOT_DIR>
+"Path to the root of the rust source tree")
+    .required(false)
+    .value_parser(clap::value_parser!(PathBuf));
+
     let dir_arg = arg!([dir] "Root directory for the book\n\
                               (Defaults to the current directory when omitted)")
     .value_parser(clap::value_parser!(PathBuf));
@@ -37,6 +42,7 @@
                 .about("Build the book from the markdown files")
                 .arg(d_arg)
                 .arg(l_arg)
+                .arg(root_arg)
                 .arg(&dir_arg),
         )
         .subcommand(
@@ -96,7 +102,8 @@
     }
 
     if book.config.get_preprocessor("spec").is_some() {
-        book.with_preprocessor(Spec::new());
+        let rust_root = args.get_one::<PathBuf>("rust-root").cloned();
+        book.with_preprocessor(Spec::new(rust_root)?);
     }
 
     book.build()?;
diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt
index 7a0f98d..0e156b9 100644
--- a/src/tools/tidy/src/allowed_run_make_makefiles.txt
+++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt
@@ -2,7 +2,6 @@
 run-make/cat-and-grep-sanity-check/Makefile
 run-make/extern-fn-reachable/Makefile
 run-make/incr-add-rust-src-component/Makefile
-run-make/issue-84395-lto-embed-bitcode/Makefile
 run-make/jobserver-error/Makefile
 run-make/libs-through-symlinks/Makefile
 run-make/split-debuginfo/Makefile
diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt
index 97c4275..94f8d23 100644
--- a/src/tools/tidy/src/issues.txt
+++ b/src/tools/tidy/src/issues.txt
@@ -3720,16 +3720,6 @@
 ui/rfcs/rfc-2528-type-changing-struct-update/issue-92010-trait-bound-not-satisfied.rs
 ui/rfcs/rfc-2528-type-changing-struct-update/issue-96878.rs
 ui/rfcs/rfc-2565-param-attrs/issue-64682-dropping-first-attrs-in-impl-fns.rs
-ui/rfcs/rfc-2632-const-trait-impl/issue-100222.rs
-ui/rfcs/rfc-2632-const-trait-impl/issue-102156.rs
-ui/rfcs/rfc-2632-const-trait-impl/issue-102985.rs
-ui/rfcs/rfc-2632-const-trait-impl/issue-103677.rs
-ui/rfcs/rfc-2632-const-trait-impl/issue-79450.rs
-ui/rfcs/rfc-2632-const-trait-impl/issue-88155.rs
-ui/rfcs/rfc-2632-const-trait-impl/issue-92111.rs
-ui/rfcs/rfc-2632-const-trait-impl/issue-92230-wf-super-trait-env.rs
-ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95186-specialize-on-tilde-const.rs
-ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95187-same-trait-bound-different-constness.rs
 ui/rust-2018/issue-51008-1.rs
 ui/rust-2018/issue-51008.rs
 ui/rust-2018/issue-52202-use-suggestions.rs
@@ -3983,6 +3973,16 @@
 ui/traits/alias/issue-83613.rs
 ui/traits/associated_type_bound/issue-51446.rs
 ui/traits/auxiliary/issue_89119_intercrate_caching.rs
+ui/traits/const-traits/issue-100222.rs
+ui/traits/const-traits/issue-102156.rs
+ui/traits/const-traits/issue-102985.rs
+ui/traits/const-traits/issue-103677.rs
+ui/traits/const-traits/issue-79450.rs
+ui/traits/const-traits/issue-88155.rs
+ui/traits/const-traits/issue-92111.rs
+ui/traits/const-traits/issue-92230-wf-super-trait-env.rs
+ui/traits/const-traits/specialization/issue-95186-specialize-on-tilde-const.rs
+ui/traits/const-traits/specialization/issue-95187-same-trait-bound-different-constness.rs
 ui/traits/issue-103563.rs
 ui/traits/issue-104322.rs
 ui/traits/issue-105231.rs
diff --git a/tests/assembly/riscv-soft-abi-with-float-features.rs b/tests/assembly/riscv-soft-abi-with-float-features.rs
new file mode 100644
index 0000000..733137f
--- /dev/null
+++ b/tests/assembly/riscv-soft-abi-with-float-features.rs
@@ -0,0 +1,46 @@
+//@ assembly-output: emit-asm
+//@ compile-flags: --target riscv64imac-unknown-none-elf -Ctarget-feature=+f,+d
+//@ needs-llvm-components: riscv
+
+#![feature(no_core, lang_items, f16)]
+#![crate_type = "lib"]
+#![no_core]
+
+#[lang = "sized"]
+trait Sized {}
+
+#[lang = "copy"]
+trait Copy {}
+
+impl Copy for f16 {}
+impl Copy for f32 {}
+impl Copy for f64 {}
+
+// This test checks that the floats are all returned in `a0` as required by the `lp64` ABI.
+
+// CHECK-LABEL: read_f16
+#[no_mangle]
+pub extern "C" fn read_f16(x: &f16) -> f16 {
+    // CHECK: lh a0, 0(a0)
+    // CHECK-NEXT: lui a1, 1048560
+    // CHECK-NEXT: or a0, a0, a1
+    // CHECK-NEXT: ret
+    *x
+}
+
+// CHECK-LABEL: read_f32
+#[no_mangle]
+pub extern "C" fn read_f32(x: &f32) -> f32 {
+    // CHECK: flw fa5, 0(a0)
+    // CHECK-NEXT: fmv.x.w a0, fa5
+    // CHECK-NEXT: ret
+    *x
+}
+
+// CHECK-LABEL: read_f64
+#[no_mangle]
+pub extern "C" fn read_f64(x: &f64) -> f64 {
+    // CHECK: ld a0, 0(a0)
+    // CHECK-NEXT: ret
+    *x
+}
diff --git a/tests/assembly/rust-abi-arg-attr.rs b/tests/assembly/rust-abi-arg-attr.rs
new file mode 100644
index 0000000..2a113ee
--- /dev/null
+++ b/tests/assembly/rust-abi-arg-attr.rs
@@ -0,0 +1,108 @@
+//@ assembly-output: emit-asm
+//@ revisions: riscv64 riscv64-zbb loongarch64
+//@ compile-flags: -C opt-level=3
+//@ [riscv64] compile-flags: --target riscv64gc-unknown-linux-gnu
+//@ [riscv64] needs-llvm-components: riscv
+//@ [riscv64-zbb] compile-flags: --target riscv64gc-unknown-linux-gnu
+//@ [riscv64-zbb] compile-flags: -C target-feature=+zbb
+//@ [riscv64-zbb] needs-llvm-components: riscv
+//@ [loongarch64] compile-flags: --target loongarch64-unknown-linux-gnu
+//@ [loongarch64] needs-llvm-components: loongarch
+
+#![feature(no_core, lang_items, intrinsics, rustc_attrs)]
+#![crate_type = "lib"]
+#![no_std]
+#![no_core]
+
+// FIXME: Migrate these code after PR #130693 is landed.
+// vvvvv core
+
+#[lang = "sized"]
+trait Sized {}
+
+#[lang = "copy"]
+trait Copy {}
+
+impl Copy for i8 {}
+impl Copy for u32 {}
+impl Copy for i32 {}
+
+#[lang = "neg"]
+trait Neg {
+    type Output;
+
+    fn neg(self) -> Self::Output;
+}
+
+impl Neg for i8 {
+    type Output = i8;
+
+    fn neg(self) -> Self::Output {
+        -self
+    }
+}
+
+#[lang = "Ordering"]
+#[repr(i8)]
+enum Ordering {
+    Less = -1,
+    Equal = 0,
+    Greater = 1,
+}
+
+extern "rust-intrinsic" {
+    #[rustc_safe_intrinsic]
+    fn three_way_compare<T: Copy>(lhs: T, rhs: T) -> Ordering;
+}
+
+// ^^^^^ core
+
+// Reimplementation of function `{integer}::max`.
+macro_rules! max {
+    ($a:expr, $b:expr) => {
+        match three_way_compare($a, $b) {
+            Ordering::Less | Ordering::Equal => $b,
+            Ordering::Greater => $a,
+        }
+    };
+}
+
+#[no_mangle]
+// CHECK-LABEL: issue_114508_u32:
+pub fn issue_114508_u32(a: u32, b: u32) -> u32 {
+    // CHECK-NEXT:       .cfi_startproc
+
+    // riscv64-NEXT:     bltu a1, a0, .[[RET:.+]]
+    // riscv64-NEXT:     mv a0, a1
+    // riscv64-NEXT: .[[RET]]:
+
+    // riscv64-zbb-NEXT: maxu a0, a0, a1
+
+    // loongarch64-NEXT: sltu $a2, $a1, $a0
+    // loongarch64-NEXT: masknez $a1, $a1, $a2
+    // loongarch64-NEXT: maskeqz $a0, $a0, $a2
+    // loongarch64-NEXT: or $a0, $a0, $a1
+
+    // CHECK-NEXT:       ret
+    max!(a, b)
+}
+
+#[no_mangle]
+// CHECK-LABEL: issue_114508_i32:
+pub fn issue_114508_i32(a: i32, b: i32) -> i32 {
+    // CHECK-NEXT:       .cfi_startproc
+
+    // riscv64-NEXT:     blt a1, a0, .[[RET:.+]]
+    // riscv64-NEXT:     mv a0, a1
+    // riscv64-NEXT: .[[RET]]:
+
+    // riscv64-zbb-NEXT: max a0, a0, a1
+
+    // loongarch64-NEXT: slt $a2, $a1, $a0
+    // loongarch64-NEXT: masknez $a1, $a1, $a2
+    // loongarch64-NEXT: maskeqz $a0, $a0, $a2
+    // loongarch64-NEXT: or $a0, $a0, $a1
+
+    // CHECK-NEXT:       ret
+    max!(a, b)
+}
diff --git a/tests/assembly/targets/targets-elf.rs b/tests/assembly/targets/targets-elf.rs
index f26d06a..1857633 100644
--- a/tests/assembly/targets/targets-elf.rs
+++ b/tests/assembly/targets/targets-elf.rs
@@ -522,6 +522,9 @@
 //@ revisions: wasm32_unknown_unknown
 //@ [wasm32_unknown_unknown] compile-flags: --target wasm32-unknown-unknown
 //@ [wasm32_unknown_unknown] needs-llvm-components: webassembly
+//@ revisions: wasm32v1_none
+//@ [wasm32v1_none] compile-flags: --target wasm32v1-none
+//@ [wasm32v1_none] needs-llvm-components: webassembly
 //@ revisions: wasm32_wasi
 //@ [wasm32_wasi] compile-flags: --target wasm32-wasi
 //@ [wasm32_wasi] needs-llvm-components: webassembly
diff --git a/tests/assembly/x86-return-float.rs b/tests/assembly/x86-return-float.rs
index 30c5e86..acd1af8 100644
--- a/tests/assembly/x86-return-float.rs
+++ b/tests/assembly/x86-return-float.rs
@@ -305,8 +305,10 @@
 // CHECK-LABEL: return_f16:
 #[no_mangle]
 pub fn return_f16(x: f16) -> f16 {
-    // CHECK: pinsrw $0, {{.*}}(%ebp), %xmm0
-    // CHECK-NOT: xmm0
+    // CHECK: pushl %ebp
+    // CHECK: movl %esp, %ebp
+    // CHECK: movzwl 8(%ebp), %eax
+    // CHECK: popl %ebp
     // CHECK: retl
     x
 }
diff --git a/tests/codegen/avr/avr-func-addrspace.rs b/tests/codegen/avr/avr-func-addrspace.rs
index 7f9a7e6..a2dcb1c 100644
--- a/tests/codegen/avr/avr-func-addrspace.rs
+++ b/tests/codegen/avr/avr-func-addrspace.rs
@@ -18,8 +18,8 @@
 #[lang = "copy"]
 pub trait Copy {}
 impl<T: ?Sized> Copy for *const T {}
-#[lang = "receiver"]
-pub trait Receiver {}
+#[lang = "legacy_receiver"]
+pub trait LegacyReceiver {}
 #[lang = "tuple_trait"]
 pub trait Tuple {}
 
diff --git a/tests/codegen/checked_ilog.rs b/tests/codegen/checked_ilog.rs
index 8f3c071..d7dfc7c 100644
--- a/tests/codegen/checked_ilog.rs
+++ b/tests/codegen/checked_ilog.rs
@@ -5,7 +5,7 @@
 // Ensure that when val < base, we do not divide or multiply.
 
 // CHECK-LABEL: @checked_ilog
-// CHECK-SAME: (i16 noundef %val, i16 noundef %base)
+// CHECK-SAME: (i16{{.*}} %val, i16{{.*}} %base)
 #[no_mangle]
 pub fn checked_ilog(val: u16, base: u16) -> Option<u32> {
     // CHECK-NOT: udiv
diff --git a/tests/codegen/checked_math.rs b/tests/codegen/checked_math.rs
index 75df586..63f5c3d 100644
--- a/tests/codegen/checked_math.rs
+++ b/tests/codegen/checked_math.rs
@@ -8,7 +8,7 @@
 // Thanks to poison semantics, this doesn't even need branches.
 
 // CHECK-LABEL: @checked_sub_unsigned
-// CHECK-SAME: (i16 noundef %a, i16 noundef %b)
+// CHECK-SAME: (i16{{.*}} %a, i16{{.*}} %b)
 #[no_mangle]
 pub fn checked_sub_unsigned(a: u16, b: u16) -> Option<u16> {
     // CHECK-DAG: %[[IS_SOME:.+]] = icmp uge i16 %a, %b
@@ -26,7 +26,7 @@
 // looking for no-wrap flags, we just need there to not be any masking.
 
 // CHECK-LABEL: @checked_shl_unsigned
-// CHECK-SAME: (i32 noundef %a, i32 noundef %b)
+// CHECK-SAME: (i32{{.*}} %a, i32{{.*}} %b)
 #[no_mangle]
 pub fn checked_shl_unsigned(a: u32, b: u32) -> Option<u32> {
     // CHECK-DAG: %[[IS_SOME:.+]] = icmp ult i32 %b, 32
@@ -41,7 +41,7 @@
 }
 
 // CHECK-LABEL: @checked_shr_unsigned
-// CHECK-SAME: (i32 noundef %a, i32 noundef %b)
+// CHECK-SAME: (i32{{.*}} %a, i32{{.*}} %b)
 #[no_mangle]
 pub fn checked_shr_unsigned(a: u32, b: u32) -> Option<u32> {
     // CHECK-DAG: %[[IS_SOME:.+]] = icmp ult i32 %b, 32
@@ -56,7 +56,7 @@
 }
 
 // CHECK-LABEL: @checked_shl_signed
-// CHECK-SAME: (i32 noundef %a, i32 noundef %b)
+// CHECK-SAME: (i32{{.*}} %a, i32{{.*}} %b)
 #[no_mangle]
 pub fn checked_shl_signed(a: i32, b: u32) -> Option<i32> {
     // CHECK-DAG: %[[IS_SOME:.+]] = icmp ult i32 %b, 32
@@ -71,7 +71,7 @@
 }
 
 // CHECK-LABEL: @checked_shr_signed
-// CHECK-SAME: (i32 noundef %a, i32 noundef %b)
+// CHECK-SAME: (i32{{.*}} %a, i32{{.*}} %b)
 #[no_mangle]
 pub fn checked_shr_signed(a: i32, b: u32) -> Option<i32> {
     // CHECK-DAG: %[[IS_SOME:.+]] = icmp ult i32 %b, 32
@@ -86,7 +86,7 @@
 }
 
 // CHECK-LABEL: @checked_add_one_unwrap_unsigned
-// CHECK-SAME: (i32 noundef %x)
+// CHECK-SAME: (i32{{.*}} %x)
 #[no_mangle]
 pub fn checked_add_one_unwrap_unsigned(x: u32) -> u32 {
     // CHECK: %[[IS_MAX:.+]] = icmp eq i32 %x, -1
diff --git a/tests/codegen/comparison-operators-newtype.rs b/tests/codegen/comparison-operators-newtype.rs
index d336c4e..acce0cb 100644
--- a/tests/codegen/comparison-operators-newtype.rs
+++ b/tests/codegen/comparison-operators-newtype.rs
@@ -12,7 +12,7 @@
 pub struct Foo(u16);
 
 // CHECK-LABEL: @check_lt
-// CHECK-SAME: (i16 noundef %[[A:.+]], i16 noundef %[[B:.+]])
+// CHECK-SAME: (i16{{.*}} %[[A:.+]], i16{{.*}} %[[B:.+]])
 #[no_mangle]
 pub fn check_lt(a: Foo, b: Foo) -> bool {
     // CHECK: %[[R:.+]] = icmp ult i16 %[[A]], %[[B]]
@@ -21,7 +21,7 @@
 }
 
 // CHECK-LABEL: @check_le
-// CHECK-SAME: (i16 noundef %[[A:.+]], i16 noundef %[[B:.+]])
+// CHECK-SAME: (i16{{.*}} %[[A:.+]], i16{{.*}} %[[B:.+]])
 #[no_mangle]
 pub fn check_le(a: Foo, b: Foo) -> bool {
     // CHECK: %[[R:.+]] = icmp ule i16 %[[A]], %[[B]]
@@ -30,7 +30,7 @@
 }
 
 // CHECK-LABEL: @check_gt
-// CHECK-SAME: (i16 noundef %[[A:.+]], i16 noundef %[[B:.+]])
+// CHECK-SAME: (i16{{.*}} %[[A:.+]], i16{{.*}} %[[B:.+]])
 #[no_mangle]
 pub fn check_gt(a: Foo, b: Foo) -> bool {
     // CHECK: %[[R:.+]] = icmp ugt i16 %[[A]], %[[B]]
@@ -39,7 +39,7 @@
 }
 
 // CHECK-LABEL: @check_ge
-// CHECK-SAME: (i16 noundef %[[A:.+]], i16 noundef %[[B:.+]])
+// CHECK-SAME: (i16{{.*}} %[[A:.+]], i16{{.*}} %[[B:.+]])
 #[no_mangle]
 pub fn check_ge(a: Foo, b: Foo) -> bool {
     // CHECK: %[[R:.+]] = icmp uge i16 %[[A]], %[[B]]
diff --git a/tests/codegen/fewer-names.rs b/tests/codegen/fewer-names.rs
index b14dd30..a171629 100644
--- a/tests/codegen/fewer-names.rs
+++ b/tests/codegen/fewer-names.rs
@@ -6,11 +6,11 @@
 
 #[no_mangle]
 pub fn sum(x: u32, y: u32) -> u32 {
-    // YES-LABEL: define{{.*}}i32 @sum(i32 noundef %0, i32 noundef %1)
+    // YES-LABEL: define{{.*}}i32 @sum(i32{{.*}} %0, i32{{.*}} %1)
     // YES-NEXT:    %3 = add i32 %1, %0
     // YES-NEXT:    ret i32 %3
 
-    // NO-LABEL: define{{.*}}i32 @sum(i32 noundef %x, i32 noundef %y)
+    // NO-LABEL: define{{.*}}i32 @sum(i32{{.*}} %x, i32{{.*}} %y)
     // NO-NEXT:  start:
     // NO-NEXT:    %z = add i32 %y, %x
     // NO-NEXT:    ret i32 %z
diff --git a/tests/codegen/float/f128.rs b/tests/codegen/float/f128.rs
index 4af2641..514d354 100644
--- a/tests/codegen/float/f128.rs
+++ b/tests/codegen/float/f128.rs
@@ -1,4 +1,4 @@
-// 32-bit x86 returns `f32` and `f64` differently to avoid the x87 stack.
+// 32-bit x86 returns float types differently to avoid the x87 stack.
 // 32-bit systems will return 128bit values using a return area pointer.
 //@ revisions: x86 bit32 bit64
 //@[x86] only-x86
@@ -152,7 +152,9 @@
 
 /* float to float conversions */
 
-// CHECK-LABEL: half @f128_as_f16(
+// x86-LABEL: i16 @f128_as_f16(
+// bits32-LABEL: half @f128_as_f16(
+// bits64-LABEL: half @f128_as_f16(
 #[no_mangle]
 pub fn f128_as_f16(a: f128) -> f16 {
     // CHECK: fptrunc fp128 %{{.+}} to half
diff --git a/tests/codegen/float/f16.rs b/tests/codegen/float/f16.rs
index 8093105..5c3a589 100644
--- a/tests/codegen/float/f16.rs
+++ b/tests/codegen/float/f16.rs
@@ -1,4 +1,4 @@
-// 32-bit x86 returns `f32` and `f64` differently to avoid the x87 stack.
+// 32-bit x86 returns float types differently to avoid the x87 stack.
 // 32-bit systems will return 128bit values using a return area pointer.
 //@ revisions: x86 bit32 bit64
 //@[x86] only-x86
@@ -58,42 +58,44 @@
     a <= b
 }
 
-// CHECK-LABEL: half @f16_neg(
+// This is where we check the argument and return ABI for f16.
+// other-LABEL: half @f16_neg(half
+// x86-LABEL: i16 @f16_neg(half
 #[no_mangle]
 pub fn f16_neg(a: f16) -> f16 {
     // CHECK: fneg half %{{.+}}
     -a
 }
 
-// CHECK-LABEL: half @f16_add(
+// CHECK-LABEL: @f16_add
 #[no_mangle]
 pub fn f16_add(a: f16, b: f16) -> f16 {
     // CHECK: fadd half %{{.+}}, %{{.+}}
     a + b
 }
 
-// CHECK-LABEL: half @f16_sub(
+// CHECK-LABEL: @f16_sub
 #[no_mangle]
 pub fn f16_sub(a: f16, b: f16) -> f16 {
     // CHECK: fsub half %{{.+}}, %{{.+}}
     a - b
 }
 
-// CHECK-LABEL: half @f16_mul(
+// CHECK-LABEL: @f16_mul
 #[no_mangle]
 pub fn f16_mul(a: f16, b: f16) -> f16 {
     // CHECK: fmul half %{{.+}}, %{{.+}}
     a * b
 }
 
-// CHECK-LABEL: half @f16_div(
+// CHECK-LABEL: @f16_div
 #[no_mangle]
 pub fn f16_div(a: f16, b: f16) -> f16 {
     // CHECK: fdiv half %{{.+}}, %{{.+}}
     a / b
 }
 
-// CHECK-LABEL: half @f16_rem(
+// CHECK-LABEL: @f16_rem
 #[no_mangle]
 pub fn f16_rem(a: f16, b: f16) -> f16 {
     // CHECK: frem half %{{.+}}, %{{.+}}
@@ -142,10 +144,13 @@
 
 /* float to float conversions */
 
-// CHECK-LABEL: half @f16_as_self(
+// other-LABEL: half @f16_as_self(
+// x86-LABEL: i16 @f16_as_self(
 #[no_mangle]
 pub fn f16_as_self(a: f16) -> f16 {
-    // CHECK: ret half %{{.+}}
+    // other-CHECK: ret half %{{.+}}
+    // x86-CHECK: bitcast half
+    // x86-CHECK: ret i16
     a as f16
 }
 
@@ -176,21 +181,21 @@
     a as f128
 }
 
-// CHECK-LABEL: half @f32_as_f16(
+// CHECK-LABEL: @f32_as_f16
 #[no_mangle]
 pub fn f32_as_f16(a: f32) -> f16 {
     // CHECK: fptrunc float %{{.+}} to half
     a as f16
 }
 
-// CHECK-LABEL: half @f64_as_f16(
+// CHECK-LABEL: @f64_as_f16
 #[no_mangle]
 pub fn f64_as_f16(a: f64) -> f16 {
     // CHECK: fptrunc double %{{.+}} to half
     a as f16
 }
 
-// CHECK-LABEL: half @f128_as_f16(
+// CHECK-LABEL: @f128_as_f16
 #[no_mangle]
 pub fn f128_as_f16(a: f128) -> f16 {
     // CHECK: fptrunc fp128 %{{.+}} to half
@@ -273,70 +278,70 @@
 
 /* int to float conversions */
 
-// CHECK-LABEL: half @u8_as_f16(
+// CHECK-LABEL: @u8_as_f16
 #[no_mangle]
 pub fn u8_as_f16(a: u8) -> f16 {
     // CHECK: uitofp i8 %{{.+}} to half
     a as f16
 }
 
-// CHECK-LABEL: half @u16_as_f16(
+// CHECK-LABEL: @u16_as_f16
 #[no_mangle]
 pub fn u16_as_f16(a: u16) -> f16 {
     // CHECK: uitofp i16 %{{.+}} to half
     a as f16
 }
 
-// CHECK-LABEL: half @u32_as_f16(
+// CHECK-LABEL: @u32_as_f16
 #[no_mangle]
 pub fn u32_as_f16(a: u32) -> f16 {
     // CHECK: uitofp i32 %{{.+}} to half
     a as f16
 }
 
-// CHECK-LABEL: half @u64_as_f16(
+// CHECK-LABEL: @u64_as_f16
 #[no_mangle]
 pub fn u64_as_f16(a: u64) -> f16 {
     // CHECK: uitofp i64 %{{.+}} to half
     a as f16
 }
 
-// CHECK-LABEL: half @u128_as_f16(
+// CHECK-LABEL: @u128_as_f16
 #[no_mangle]
 pub fn u128_as_f16(a: u128) -> f16 {
     // CHECK: uitofp i128 %{{.+}} to half
     a as f16
 }
 
-// CHECK-LABEL: half @i8_as_f16(
+// CHECK-LABEL: @i8_as_f16
 #[no_mangle]
 pub fn i8_as_f16(a: i8) -> f16 {
     // CHECK: sitofp i8 %{{.+}} to half
     a as f16
 }
 
-// CHECK-LABEL: half @i16_as_f16(
+// CHECK-LABEL: @i16_as_f16
 #[no_mangle]
 pub fn i16_as_f16(a: i16) -> f16 {
     // CHECK: sitofp i16 %{{.+}} to half
     a as f16
 }
 
-// CHECK-LABEL: half @i32_as_f16(
+// CHECK-LABEL: @i32_as_f16
 #[no_mangle]
 pub fn i32_as_f16(a: i32) -> f16 {
     // CHECK: sitofp i32 %{{.+}} to half
     a as f16
 }
 
-// CHECK-LABEL: half @i64_as_f16(
+// CHECK-LABEL: @i64_as_f16
 #[no_mangle]
 pub fn i64_as_f16(a: i64) -> f16 {
     // CHECK: sitofp i64 %{{.+}} to half
     a as f16
 }
 
-// CHECK-LABEL: half @i128_as_f16(
+// CHECK-LABEL: @i128_as_f16
 #[no_mangle]
 pub fn i128_as_f16(a: i128) -> f16 {
     // CHECK: sitofp i128 %{{.+}} to half
diff --git a/tests/codegen/function-arguments.rs b/tests/codegen/function-arguments.rs
index bf9f405..7fa1d65 100644
--- a/tests/codegen/function-arguments.rs
+++ b/tests/codegen/function-arguments.rs
@@ -32,7 +32,7 @@
     x
 }
 
-// CHECK: i8 @maybeuninit_boolean(i8 %x)
+// CHECK: i8 @maybeuninit_boolean(i8{{.*}} %x)
 #[no_mangle]
 pub fn maybeuninit_boolean(x: MaybeUninit<bool>) -> MaybeUninit<bool> {
     x
@@ -44,19 +44,19 @@
     x
 }
 
-// CHECK: i8 @maybeuninit_enum_bool(i8 %x)
+// CHECK: i8 @maybeuninit_enum_bool(i8{{.*}} %x)
 #[no_mangle]
 pub fn maybeuninit_enum_bool(x: MaybeUninit<MyBool>) -> MaybeUninit<MyBool> {
     x
 }
 
-// CHECK: noundef{{( range\(i32 0, 1114112\))?}} i32 @char(i32 noundef{{( range\(i32 0, 1114112\))?}} %x)
+// CHECK: noundef{{( range\(i32 0, 1114112\))?}} i32 @char(i32{{.*}}{{( range\(i32 0, 1114112\))?}} %x)
 #[no_mangle]
 pub fn char(x: char) -> char {
     x
 }
 
-// CHECK: i32 @maybeuninit_char(i32 %x)
+// CHECK: i32 @maybeuninit_char(i32{{.*}} %x)
 #[no_mangle]
 pub fn maybeuninit_char(x: MaybeUninit<char>) -> MaybeUninit<char> {
     x
diff --git a/tests/codegen/intrinsics/three_way_compare.rs b/tests/codegen/intrinsics/three_way_compare.rs
index f3b631a..9a476ab 100644
--- a/tests/codegen/intrinsics/three_way_compare.rs
+++ b/tests/codegen/intrinsics/three_way_compare.rs
@@ -10,8 +10,7 @@
 
 #[no_mangle]
 // CHECK-LABEL: @signed_cmp
-// DEBUG-SAME: (i16 %a, i16 %b)
-// OPTIM-SAME: (i16 noundef %a, i16 noundef %b)
+// CHECK-SAME: (i16{{.*}} %a, i16{{.*}} %b)
 pub fn signed_cmp(a: i16, b: i16) -> std::cmp::Ordering {
     // DEBUG: %[[GT:.+]] = icmp sgt i16 %a, %b
     // DEBUG: %[[ZGT:.+]] = zext i1 %[[GT]] to i8
@@ -29,8 +28,7 @@
 
 #[no_mangle]
 // CHECK-LABEL: @unsigned_cmp
-// DEBUG-SAME: (i16 %a, i16 %b)
-// OPTIM-SAME: (i16 noundef %a, i16 noundef %b)
+// CHECK-SAME: (i16{{.*}} %a, i16{{.*}} %b)
 pub fn unsigned_cmp(a: u16, b: u16) -> std::cmp::Ordering {
     // DEBUG: %[[GT:.+]] = icmp ugt i16 %a, %b
     // DEBUG: %[[ZGT:.+]] = zext i1 %[[GT]] to i8
diff --git a/tests/codegen/mir-aggregate-no-alloca.rs b/tests/codegen/mir-aggregate-no-alloca.rs
index 04ffb07..37b024a 100644
--- a/tests/codegen/mir-aggregate-no-alloca.rs
+++ b/tests/codegen/mir-aggregate-no-alloca.rs
@@ -9,7 +9,7 @@
 #[repr(transparent)]
 pub struct Transparent32(u32);
 
-// CHECK: i32 @make_transparent(i32 noundef %x)
+// CHECK: i32 @make_transparent(i32{{.*}} %x)
 #[no_mangle]
 pub fn make_transparent(x: u32) -> Transparent32 {
     // CHECK-NOT: alloca
@@ -18,7 +18,7 @@
     a
 }
 
-// CHECK: i32 @make_closure(i32 noundef %x)
+// CHECK: i32 @make_closure(i32{{.*}} %x)
 #[no_mangle]
 pub fn make_closure(x: i32) -> impl Fn(i32) -> i32 {
     // CHECK-NOT: alloca
@@ -40,7 +40,7 @@
     a
 }
 
-// CHECK-LABEL: { i32, i32 } @make_2_tuple(i32 noundef %x)
+// CHECK-LABEL: { i32, i32 } @make_2_tuple(i32{{.*}} %x)
 #[no_mangle]
 pub fn make_2_tuple(x: u32) -> (u32, u32) {
     // CHECK-NOT: alloca
@@ -59,7 +59,7 @@
     std::cell::Cell::new(b)
 }
 
-// CHECK-LABEL: { i8, i16 } @make_cell_of_bool_and_short(i1 noundef zeroext %b, i16 noundef %s)
+// CHECK-LABEL: { i8, i16 } @make_cell_of_bool_and_short(i1 noundef zeroext %b, i16{{.*}} %s)
 #[no_mangle]
 pub fn make_cell_of_bool_and_short(b: bool, s: u16) -> std::cell::Cell<(bool, u16)> {
     // CHECK-NOT: alloca
@@ -92,7 +92,7 @@
 
 pub struct Struct1(i32);
 
-// CHECK-LABEL: i32 @make_struct_1(i32 noundef %a)
+// CHECK-LABEL: i32 @make_struct_1(i32{{.*}} %a)
 #[no_mangle]
 pub fn make_struct_1(a: i32) -> Struct1 {
     // CHECK: ret i32 %a
@@ -104,7 +104,7 @@
 
 // bit32-LABEL: void @make_struct_2_asc({{.*}} sret({{[^,]*}}) {{.*}} %s,
 // bit64-LABEL: { i64, i16 } @make_struct_2_asc(
-// CHECK-SAME: i16 noundef %a, i64 noundef %b)
+// CHECK-SAME: i16{{.*}} %a, i64 noundef %b)
 #[no_mangle]
 pub fn make_struct_2_asc(a: i16, b: i64) -> Struct2Asc {
     // CHECK-NOT: alloca
@@ -122,7 +122,7 @@
 
 // bit32-LABEL: void @make_struct_2_desc({{.*}} sret({{[^,]*}}) {{.*}} %s,
 // bit64-LABEL: { i64, i16 } @make_struct_2_desc(
-// CHECK-SAME: i64 noundef %a, i16 noundef %b)
+// CHECK-SAME: i64 noundef %a, i16{{.*}} %b)
 #[no_mangle]
 pub fn make_struct_2_desc(a: i64, b: i16) -> Struct2Desc {
     // CHECK-NOT: alloca
diff --git a/tests/codegen/placement-new.rs b/tests/codegen/placement-new.rs
index edb25df..0ec2b6a 100644
--- a/tests/codegen/placement-new.rs
+++ b/tests/codegen/placement-new.rs
@@ -1,9 +1,11 @@
 //@ compile-flags: -O
+//@ compile-flags: -Zmerge-functions=disabled
 #![crate_type = "lib"]
 
 // Test to check that types with "complex" destructors, but trivial `Default` impls
 // are constructed directly into the allocation in `Box::default` and `Arc::default`.
 
+use std::rc::Rc;
 use std::sync::Arc;
 
 // CHECK-LABEL: @box_default_inplace
@@ -16,6 +18,16 @@
     Box::default()
 }
 
+// CHECK-LABEL: @rc_default_inplace
+#[no_mangle]
+pub fn rc_default_inplace() -> Rc<(String, String)> {
+    // CHECK-NOT: alloca
+    // CHECK: [[RC:%.*]] = {{.*}}call {{.*}}__rust_alloc(
+    // CHECK-NOT: call void @llvm.memcpy
+    // CHECK: ret ptr [[RC]]
+    Rc::default()
+}
+
 // CHECK-LABEL: @arc_default_inplace
 #[no_mangle]
 pub fn arc_default_inplace() -> Arc<(String, String)> {
diff --git a/tests/codegen/range-attribute.rs b/tests/codegen/range-attribute.rs
index 8972fc7..a44ec10 100644
--- a/tests/codegen/range-attribute.rs
+++ b/tests/codegen/range-attribute.rs
@@ -24,7 +24,7 @@
     x
 }
 
-// CHECK: noundef range(i8 0, 3) i8 @optional_bool(i8 noundef range(i8 0, 3) %x)
+// CHECK: noundef range(i8 0, 3) i8 @optional_bool(i8{{.*}} range(i8 0, 3) %x)
 #[no_mangle]
 pub fn optional_bool(x: Option<bool>) -> Option<bool> {
     x
@@ -36,7 +36,7 @@
     C,
 }
 
-// CHECK: noundef range(i8 0, 4) i8 @enum0_value(i8 noundef range(i8 0, 4) %x)
+// CHECK: noundef range(i8 0, 4) i8 @enum0_value(i8{{.*}} range(i8 0, 4) %x)
 #[no_mangle]
 pub fn enum0_value(x: Enum0) -> Enum0 {
     x
diff --git a/tests/codegen/regparm-inreg.rs b/tests/codegen/regparm-inreg.rs
new file mode 100644
index 0000000..c8c647b
--- /dev/null
+++ b/tests/codegen/regparm-inreg.rs
@@ -0,0 +1,125 @@
+// Checks how `regparm` flag works with different calling conventions:
+// marks function arguments as "inreg" like the C/C++ compilers for the platforms.
+// x86 only.
+
+//@ compile-flags: --target i686-unknown-linux-gnu -O -C no-prepopulate-passes
+//@ needs-llvm-components: x86
+
+//@ revisions:regparm0 regparm1 regparm2 regparm3
+//@[regparm0] compile-flags: -Zregparm=0
+//@[regparm1] compile-flags: -Zregparm=1
+//@[regparm2] compile-flags: -Zregparm=2
+//@[regparm3] compile-flags: -Zregparm=3
+
+#![crate_type = "lib"]
+#![no_core]
+#![feature(no_core, lang_items, repr_simd)]
+#[lang = "sized"]
+trait Sized {}
+#[lang = "copy"]
+trait Copy {}
+
+pub mod tests {
+    // regparm doesn't work for "fastcall" calling conv (only 2 inregs)
+    // CHECK: @f1(i32 inreg noundef %_1, i32 inreg noundef %_2, i32 noundef %_3)
+    #[no_mangle]
+    pub extern "fastcall" fn f1(_: i32, _: i32, _: i32) {}
+
+    // regparm0: @f3(i32 noundef %_1, i32 noundef %_2, i32 noundef %_3)
+    // regparm1: @f3(i32 inreg noundef %_1, i32 noundef %_2, i32 noundef %_3)
+    // regparm2: @f3(i32 inreg noundef %_1, i32 inreg noundef %_2, i32 noundef %_3)
+    // regparm3: @f3(i32 inreg noundef %_1, i32 inreg noundef %_2, i32 inreg noundef %_3)
+    #[no_mangle]
+    pub extern "C" fn f3(_: i32, _: i32, _: i32) {}
+
+    // regparm0: @f4(i32 noundef %_1, i32 noundef %_2, i32 noundef %_3)
+    // regparm1: @f4(i32 inreg noundef %_1, i32 noundef %_2, i32 noundef %_3)
+    // regparm2: @f4(i32 inreg noundef %_1, i32 inreg noundef %_2, i32 noundef %_3)
+    // regparm3: @f4(i32 inreg noundef %_1, i32 inreg noundef %_2, i32 inreg noundef %_3)
+    #[no_mangle]
+    pub extern "cdecl" fn f4(_: i32, _: i32, _: i32) {}
+
+    // regparm0: @f5(i32 noundef %_1, i32 noundef %_2, i32 noundef %_3)
+    // regparm1: @f5(i32 inreg noundef %_1, i32 noundef %_2, i32 noundef %_3)
+    // regparm2: @f5(i32 inreg noundef %_1, i32 inreg noundef %_2, i32 noundef %_3)
+    // regparm3: @f5(i32 inreg noundef %_1, i32 inreg noundef %_2, i32 inreg noundef %_3)
+    #[no_mangle]
+    pub extern "stdcall" fn f5(_: i32, _: i32, _: i32) {}
+
+    // regparm doesn't work for thiscall
+    // CHECK: @f6(i32 noundef %_1, i32 noundef %_2, i32 noundef %_3)
+    #[no_mangle]
+    pub extern "thiscall" fn f6(_: i32, _: i32, _: i32) {}
+
+    struct S1 {
+        x1: i32,
+    }
+    // regparm0: @f7(i32 noundef %_1, i32 noundef %_2, i32 noundef %_3, i32 noundef %_4)
+    // regparm1: @f7(i32 inreg noundef %_1, i32 noundef %_2, i32 noundef %_3, i32 noundef %_4)
+    // regparm2: @f7(i32 inreg noundef %_1, i32 inreg noundef %_2, i32 noundef %_3, i32 noundef %_4)
+    // regparm3: @f7(i32 inreg noundef %_1, i32 inreg noundef %_2, i32 inreg noundef %_3,
+    // regparm3-SAME: i32 noundef %_4)
+    #[no_mangle]
+    pub extern "C" fn f7(_: i32, _: i32, _: S1, _: i32) {}
+
+    #[repr(C)]
+    struct S2 {
+        x1: i32,
+        x2: i32,
+    }
+    // regparm0: @f8(i32 noundef %_1, i32 noundef %_2, ptr {{.*}} %_3, i32 noundef %_4)
+    // regparm1: @f8(i32 inreg noundef %_1, i32 noundef %_2, ptr {{.*}} %_3, i32 noundef %_4)
+    // regparm2: @f8(i32 inreg noundef %_1, i32 inreg noundef %_2, ptr {{.*}} %_3, i32 noundef %_4)
+    // regparm3: @f8(i32 inreg noundef %_1, i32 inreg noundef %_2, ptr {{.*}} %_3,
+    // regparm3-SAME: i32 inreg noundef %_4)
+    #[no_mangle]
+    pub extern "C" fn f8(_: i32, _: i32, _: S2, _: i32) {}
+
+    // regparm0: @f9(i1 noundef zeroext %_1, i16 noundef signext %_2, i64 noundef %_3,
+    // regparm0-SAME: i128 noundef %_4)
+    // regparm1: @f9(i1 inreg noundef zeroext %_1, i16 noundef signext %_2, i64 noundef %_3,
+    // regparm1-SAME: i128 noundef %_4)
+    // regparm2: @f9(i1 inreg noundef zeroext %_1, i16 inreg noundef signext %_2, i64 noundef %_3,
+    // regparm2-SAME: i128 noundef %_4)
+    // regparm3: @f9(i1 inreg noundef zeroext %_1, i16 inreg noundef signext %_2, i64 noundef %_3,
+    // regparm3-SAME: i128 noundef %_4)
+    #[no_mangle]
+    pub extern "C" fn f9(_: bool, _: i16, _: i64, _: u128) {}
+
+    // regparm0: @f10(float noundef %_1, double noundef %_2, i1 noundef zeroext %_3,
+    // regparm0-SAME: i16 noundef signext %_4)
+    // regparm1: @f10(float noundef %_1, double noundef %_2, i1 inreg noundef zeroext %_3,
+    // regparm1-SAME: i16 noundef signext %_4)
+    // regparm2: @f10(float noundef %_1, double noundef %_2, i1 inreg noundef zeroext %_3,
+    // regparm2-SAME: i16 inreg noundef signext %_4)
+    // regparm3: @f10(float noundef %_1, double noundef %_2, i1 inreg noundef zeroext %_3,
+    // regparm3-SAME: i16 inreg noundef signext %_4)
+    #[no_mangle]
+    pub extern "C" fn f10(_: f32, _: f64, _: bool, _: i16) {}
+
+    #[allow(non_camel_case_types)]
+    #[repr(simd)]
+    pub struct __m128([f32; 4]);
+
+    // regparm0: @f11(i32 noundef %_1, <4 x float> %_2, i32 noundef %_3, i32 noundef %_4)
+    // regparm1: @f11(i32 inreg noundef %_1, <4 x float> %_2, i32 noundef %_3, i32 noundef %_4)
+    // regparm2: @f11(i32 inreg noundef %_1, <4 x float> %_2, i32 inreg noundef %_3,
+    // regparm2-SAME: i32 noundef %_4)
+    // regparm3: @f11(i32 inreg noundef %_1, <4 x float> %_2, i32 inreg noundef %_3,
+    // regparm3-SAME: i32 inreg noundef %_4)
+    #[no_mangle]
+    pub extern "C" fn f11(_: i32, _: __m128, _: i32, _: i32) {}
+
+    #[allow(non_camel_case_types)]
+    #[repr(simd)]
+    pub struct __m256([f32; 8]);
+
+    // regparm0: @f12(i32 noundef %_1, <8 x float> %_2, i32 noundef %_3, i32 noundef %_4)
+    // regparm1: @f12(i32 inreg noundef %_1, <8 x float> %_2, i32 noundef %_3, i32 noundef %_4)
+    // regparm2: @f12(i32 inreg noundef %_1, <8 x float> %_2, i32 inreg noundef %_3,
+    // regparm2-SAME: i32 noundef %_4)
+    // regparm3: @f12(i32 inreg noundef %_1, <8 x float> %_2, i32 inreg noundef %_3,
+    // regparm3-SAME: i32 inreg noundef %_4)
+    #[no_mangle]
+    pub extern "C" fn f12(_: i32, _: __m256, _: i32, _: i32) {}
+}
diff --git a/tests/codegen/riscv-target-abi.rs b/tests/codegen/riscv-target-abi.rs
index 5d545af..88da4ec 100644
--- a/tests/codegen/riscv-target-abi.rs
+++ b/tests/codegen/riscv-target-abi.rs
@@ -10,7 +10,7 @@
 
 //@[riscv32imac] compile-flags: --target=riscv32imac-unknown-none-elf
 //@[riscv32imac] needs-llvm-components: riscv
-// riscv32imac-NOT: !"target-abi"
+// riscv32imac: !{i32 1, !"target-abi", !"ilp32"}
 
 #![feature(no_core, lang_items)]
 #![crate_type = "lib"]
diff --git a/tests/codegen/rust-abi-arch-specific-adjustment.rs b/tests/codegen/rust-abi-arch-specific-adjustment.rs
new file mode 100644
index 0000000..9da10f6
--- /dev/null
+++ b/tests/codegen/rust-abi-arch-specific-adjustment.rs
@@ -0,0 +1,111 @@
+//@ compile-flags: -O -C no-prepopulate-passes
+//@ revisions: riscv64 loongarch64
+
+//@[riscv64] only-riscv64
+//@[riscv64] compile-flags: --target riscv64gc-unknown-linux-gnu
+//@[riscv64] needs-llvm-components: riscv
+
+//@[loongarch64] only-loongarch64
+//@[loongarch64] compile-flags: --target loongarch64-unknown-linux-gnu
+//@[loongarch64] needs-llvm-components: loongarch
+
+#![crate_type = "lib"]
+
+#[no_mangle]
+// riscv64:     define noundef i8 @arg_attr_u8(i8 noundef zeroext %x)
+// loongarch64: define noundef i8 @arg_attr_u8(i8 noundef zeroext %x)
+pub fn arg_attr_u8(x: u8) -> u8 {
+    x
+}
+
+#[no_mangle]
+// riscv64:     define noundef i16 @arg_attr_u16(i16 noundef zeroext %x)
+// loongarch64: define noundef i16 @arg_attr_u16(i16 noundef zeroext %x)
+pub fn arg_attr_u16(x: u16) -> u16 {
+    x
+}
+
+#[no_mangle]
+// riscv64:     define noundef i32 @arg_attr_u32(i32 noundef signext %x)
+// loongarch64: define noundef i32 @arg_attr_u32(i32 noundef signext %x)
+pub fn arg_attr_u32(x: u32) -> u32 {
+    x
+}
+
+#[no_mangle]
+// riscv64:     define noundef i64 @arg_attr_u64(i64 noundef %x)
+// loongarch64: define noundef i64 @arg_attr_u64(i64 noundef %x)
+pub fn arg_attr_u64(x: u64) -> u64 {
+    x
+}
+
+#[no_mangle]
+// riscv64:     define noundef i128 @arg_attr_u128(i128 noundef %x)
+// loongarch64: define noundef i128 @arg_attr_u128(i128 noundef %x)
+pub fn arg_attr_u128(x: u128) -> u128 {
+    x
+}
+
+#[no_mangle]
+// riscv64:     define noundef i8 @arg_attr_i8(i8 noundef signext %x)
+// loongarch64: define noundef i8 @arg_attr_i8(i8 noundef signext %x)
+pub fn arg_attr_i8(x: i8) -> i8 {
+    x
+}
+
+#[no_mangle]
+// riscv64:     define noundef i16 @arg_attr_i16(i16 noundef signext %x)
+// loongarch64: define noundef i16 @arg_attr_i16(i16 noundef signext %x)
+pub fn arg_attr_i16(x: i16) -> i16 {
+    x
+}
+
+#[no_mangle]
+// riscv64:     define noundef i32 @arg_attr_i32(i32 noundef signext %x)
+// loongarch64: define noundef i32 @arg_attr_i32(i32 noundef signext %x)
+pub fn arg_attr_i32(x: i32) -> i32 {
+    x
+}
+
+#[no_mangle]
+// riscv64:     define noundef i64 @arg_attr_i64(i64 noundef %x)
+// loongarch64: define noundef i64 @arg_attr_i64(i64 noundef %x)
+pub fn arg_attr_i64(x: i64) -> i64 {
+    x
+}
+
+#[no_mangle]
+// riscv64:     define noundef i128 @arg_attr_i128(i128 noundef %x)
+// loongarch64: define noundef i128 @arg_attr_i128(i128 noundef %x)
+pub fn arg_attr_i128(x: i128) -> i128 {
+    x
+}
+
+#[no_mangle]
+// riscv64:     define noundef zeroext i1 @arg_attr_bool(i1 noundef zeroext %x)
+// loongarch64: define noundef zeroext i1 @arg_attr_bool(i1 noundef zeroext %x)
+pub fn arg_attr_bool(x: bool) -> bool {
+    x
+}
+
+#[no_mangle]
+// ignore-tidy-linelength
+// riscv64:     define noundef{{( range\(i32 0, 1114112\))?}} i32 @arg_attr_char(i32 noundef signext{{( range\(i32 0, 1114112\))?}} %x)
+// loongarch64: define noundef{{( range\(i32 0, 1114112\))?}} i32 @arg_attr_char(i32 noundef signext{{( range\(i32 0, 1114112\))?}} %x)
+pub fn arg_attr_char(x: char) -> char {
+    x
+}
+
+#[no_mangle]
+// riscv64:     define noundef float @arg_attr_f32(float noundef %x)
+// loongarch64: define noundef float @arg_attr_f32(float noundef %x)
+pub fn arg_attr_f32(x: f32) -> f32 {
+    x
+}
+
+#[no_mangle]
+// riscv64:     define noundef double @arg_attr_f64(double noundef %x)
+// loongarch64: define noundef double @arg_attr_f64(double noundef %x)
+pub fn arg_attr_f64(x: f64) -> f64 {
+    x
+}
diff --git a/tests/codegen/sanitizer/cfi/emit-type-checks-attr-no-sanitize.rs b/tests/codegen/sanitizer/cfi/emit-type-checks-attr-no-sanitize.rs
index 259967e..71ccdc8 100644
--- a/tests/codegen/sanitizer/cfi/emit-type-checks-attr-no-sanitize.rs
+++ b/tests/codegen/sanitizer/cfi/emit-type-checks-attr-no-sanitize.rs
@@ -12,7 +12,7 @@
     // CHECK:       Function Attrs: {{.*}}
     // CHECK-LABEL: define{{.*}}foo{{.*}}!type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
     // CHECK:       start:
-    // CHECK-NEXT:  {{%.+}} = call i32 %f(i32 %arg)
+    // CHECK-NEXT:  {{%.+}} = call i32 %f(i32{{.*}} %arg)
     // CHECK-NEXT:  ret i32 {{%.+}}
     f(arg)
 }
diff --git a/tests/codegen/sanitizer/cfi/emit-type-checks.rs b/tests/codegen/sanitizer/cfi/emit-type-checks.rs
index 37edbef..ebc66a0 100644
--- a/tests/codegen/sanitizer/cfi/emit-type-checks.rs
+++ b/tests/codegen/sanitizer/cfi/emit-type-checks.rs
@@ -11,7 +11,7 @@
     // CHECK:       [[TT:%.+]] = call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"{{[[:print:]]+}}")
     // CHECK-NEXT:  br i1 [[TT]], label %type_test.pass, label %type_test.fail
     // CHECK:       type_test.pass:
-    // CHECK-NEXT:  {{%.+}} = call i32 %f(i32 %arg)
+    // CHECK-NEXT:  {{%.+}} = call i32 %f(i32{{.*}} %arg)
     // CHECK:       type_test.fail:
     // CHECK-NEXT:  call void @llvm.trap()
     // CHECK-NEXT:  unreachable
diff --git a/tests/codegen/sanitizer/kcfi/emit-type-metadata-trait-objects.rs b/tests/codegen/sanitizer/kcfi/emit-type-metadata-trait-objects.rs
index c1967e5..5ab55a4 100644
--- a/tests/codegen/sanitizer/kcfi/emit-type-metadata-trait-objects.rs
+++ b/tests/codegen/sanitizer/kcfi/emit-type-metadata-trait-objects.rs
@@ -16,8 +16,8 @@
 #[lang = "copy"]
 trait Copy {}
 impl<T: ?Sized> Copy for &T {}
-#[lang = "receiver"]
-trait Receiver {}
+#[lang = "legacy_receiver"]
+trait LegacyReceiver {}
 #[lang = "dispatch_from_dyn"]
 trait DispatchFromDyn<T> {}
 impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<&'a U> for &'a T {}
diff --git a/tests/codegen/transmute-scalar.rs b/tests/codegen/transmute-scalar.rs
index caaa709..43da7c1 100644
--- a/tests/codegen/transmute-scalar.rs
+++ b/tests/codegen/transmute-scalar.rs
@@ -25,7 +25,7 @@
     unsafe { std::mem::transmute(b) }
 }
 
-// CHECK-LABEL: define{{.*}}zeroext i1 @byte_to_bool(i8 %byte)
+// CHECK-LABEL: define{{.*}}zeroext i1 @byte_to_bool(i8{{.*}} %byte)
 // CHECK: %_0 = trunc i8 %byte to i1
 // CHECK-NEXT: ret i1 %_0
 #[no_mangle]
diff --git a/tests/codegen/union-abi.rs b/tests/codegen/union-abi.rs
index b3c67a5..2f14682 100644
--- a/tests/codegen/union-abi.rs
+++ b/tests/codegen/union-abi.rs
@@ -131,7 +131,7 @@
 pub union UnionBool {
     b: bool,
 }
-// CHECK: define {{(dso_local )?}}noundef zeroext i1 @test_UnionBool(i8 %b)
+// CHECK: define {{(dso_local )?}}noundef zeroext i1 @test_UnionBool(i8{{.*}} %b)
 #[no_mangle]
 pub fn test_UnionBool(b: UnionBool) -> bool {
     unsafe { b.b }
diff --git a/tests/codegen/var-names.rs b/tests/codegen/var-names.rs
index fd163a5..4ea5b3b 100644
--- a/tests/codegen/var-names.rs
+++ b/tests/codegen/var-names.rs
@@ -2,7 +2,7 @@
 
 #![crate_type = "lib"]
 
-// CHECK-LABEL: define{{.*}}i32 @test(i32 noundef %a, i32 noundef %b)
+// CHECK-LABEL: define{{.*}}i32 @test(i32{{.*}} %a, i32{{.*}} %b)
 #[no_mangle]
 pub fn test(a: u32, b: u32) -> u32 {
     let c = a + b;
diff --git a/tests/crashes/110630.rs b/tests/crashes/110630.rs
deleted file mode 100644
index f17f6f0..0000000
--- a/tests/crashes/110630.rs
+++ /dev/null
@@ -1,28 +0,0 @@
-//@ known-bug: #110630
-
-#![feature(generic_const_exprs)]
-
-use std::ops::Mul;
-
-pub trait Indices<const N: usize> {
-    const NUM_ELEMS: usize = I::NUM_ELEMS * N;
-}
-
-pub trait Concat<J> {
-    type Output;
-}
-
-pub struct Tensor<I: Indices<N>, const N: usize>
-where
-    [u8; I::NUM_ELEMS]: Sized, {}
-
-impl<I: Indices<N>, J: Indices<N>, const N: usize> Mul<Tensor<J, N>> for Tensor<I, N>
-where
-    I: Concat<T>,
-    <I as Concat<J>>::Output: Indices<N>,
-    [u8; I::NUM_ELEMS]: Sized,
-    [u8; J::NUM_ELEMS]: Sized,
-    [u8; <I as Concat<J>>::Output::NUM_ELEMS]: Sized,
-{
-    type Output = Tensor<<I as Concat<J>>::Output, N>;
-}
diff --git a/tests/crashes/115808.rs b/tests/crashes/115808.rs
deleted file mode 100644
index 79196ac..0000000
--- a/tests/crashes/115808.rs
+++ /dev/null
@@ -1,27 +0,0 @@
-//@ known-bug: #115808
-#![feature(generic_const_exprs)]
-
-use std::ops::Mul;
-
-pub trait Indices<const N: usize> {
-    const NUM_ELEMS: usize;
-}
-
-pub trait Concat<J> {
-    type Output;
-}
-
-pub struct Tensor<I: Indices<N>, const N: usize>
-where
-    [u8; I::NUM_ELEMS]: Sized, {}
-
-impl<I: Indices<N>, J: Indices<N>, const N: usize> Mul<Tensor<J, N>> for Tensor<I, N>
-where
-    I: Concat<FN>,
-    <I as Concat<J>>::Output: Indices<N>,
-    [u8; I::NUM_ELEMS]: Sized,
-    [u8; J::NUM_ELEMS]: Sized,
-    [u8; <I as Concat<J>>::Output::NUM_ELEMS]: Sized,
-{
-    type Output = Tensor<<I as Concat<J>>::Output, N>;
-}
diff --git a/tests/crashes/118320.rs b/tests/crashes/118320.rs
deleted file mode 100644
index 093c58e..0000000
--- a/tests/crashes/118320.rs
+++ /dev/null
@@ -1,14 +0,0 @@
-//@ known-bug: #118320
-//@ edition:2021
-#![feature(const_trait_impl, effects, const_closures)]
-
-#[const_trait]
-trait Bar {
-    fn foo(&self);
-}
-
-impl Bar for () {}
-
-const FOO: () = {
-    (const || (()).foo())();
-};
diff --git a/tests/crashes/119924-6.rs b/tests/crashes/119924-6.rs
deleted file mode 100644
index f1cc9d2..0000000
--- a/tests/crashes/119924-6.rs
+++ /dev/null
@@ -1,15 +0,0 @@
-//@ known-bug: #119924
-//@ compile-flags: -Znext-solver
-#![feature(const_trait_impl, effects)]
-
-struct S;
-#[const_trait]
-trait Trait<const N: u32> {}
-
-const fn f<T: Trait<{
-    struct I<U: ~const Trait<0>>(U); // should've gotten rejected during AST validation
-    //~^ ICE no host param id for call in const yet no errors reported
-    0
-}>>() {}
-
-pub fn main() {}
diff --git a/tests/crashes/121052.rs b/tests/crashes/121052.rs
deleted file mode 100644
index 5d16b06..0000000
--- a/tests/crashes/121052.rs
+++ /dev/null
@@ -1,32 +0,0 @@
-//@ known-bug: #121052
-#![feature(generic_const_exprs, with_negative_coherence)]
-
-use std::ops::Mul;
-
-pub trait Indices<const N: usize> {
-    const NUM_ELEMS: usize;
-}
-
-impl<I: Indices<N>, J: Indices<N>, const N: usize> Mul for Tensor<I, N>
-where
-    I: Concat<J>,
-    <I as Concat<J>>::Output: Indices<N>,
-    [u8; I::NUM_ELEMS]: Sized,
-    [u8; J::NUM_ELEMS]: Sized,
-    [u8; <I as Concat<J>>::Output::NUM_ELEMS]: Sized,
-{
-}
-
-pub trait Concat<J> {}
-
-pub struct Tensor<I: Indices<N>, const N: usize> {}
-
-impl<I: Indices<N>, J: Indices<N>, const N: usize> Mul for Tensor<I, N>
-where
-    I: Concat<J>,
-    <I as Concat<J>>::Output: Indices<N>,
-    [u8; I::NUM_ELEMS]: Sized,
-    [u8; J::NUM_ELEMS]: Sized,
-    [u8; <I as Concat<J>>::Output::NUM_ELEMS]: Sized,
-{
-}
diff --git a/tests/crashes/126725.rs b/tests/crashes/126725.rs
deleted file mode 100644
index d7a7d21..0000000
--- a/tests/crashes/126725.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-//@ known-bug: rust-lang/rust#126725
-trait Foo {
-    fn foo<'a>(&'a self) -> <&'a impl Sized as Bar>::Output;
-}
-
-trait Bar {
-    type Output;
-}
-
-struct X(i32);
-
-impl<'a> Bar for &'a X {
-    type Output = &'a i32;
-}
-
-impl Foo for X {
-    fn foo<'a>(&'a self) -> <&'a Self as Bar>::Output {
-        &self.0
-    }
-}
diff --git a/tests/debuginfo/thread.rs b/tests/debuginfo/thread.rs
index 0415f58..dc8cb08 100644
--- a/tests/debuginfo/thread.rs
+++ b/tests/debuginfo/thread.rs
@@ -12,15 +12,15 @@
 // cdb-check:join_handle,d    [Type: std::thread::JoinHandle<tuple$<> >]
 // cdb-check:    [...] __0              [Type: std::thread::JoinInner<tuple$<> >]
 //
-// cdb-command:dx t,d
+// cdb-command:dx -r3 t,d
 // cdb-check:t,d              : [...] [Type: std::thread::Thread *]
-// cdb-check:[...] inner [...][Type: core::pin::Pin<alloc::sync::Arc<std::thread::Inner,alloc::alloc::Global> >]
+// cdb-check:    [...] __0              : Other [Type: enum2$<std::thread::Inner>]
+// cdb-check:         [...] __0              [Type: core::pin::Pin<alloc::sync::Arc<std::thread::OtherInner,[...]> >]
 
 use std::thread;
 
 #[allow(unused_variables)]
-fn main()
-{
+fn main() {
     let join_handle = thread::spawn(|| {
         println!("Initialize a thread");
     });
diff --git a/tests/run-make/cross-lang-lto-clang/rmake.rs b/tests/run-make/cross-lang-lto-clang/rmake.rs
index 1b15a54..3fed6ea 100644
--- a/tests/run-make/cross-lang-lto-clang/rmake.rs
+++ b/tests/run-make/cross-lang-lto-clang/rmake.rs
@@ -9,6 +9,24 @@
 
 use run_make_support::{clang, env_var, llvm_ar, llvm_objdump, rustc, static_lib_name};
 
+#[cfg(any(target_arch = "aarch64", target_arch = "arm"))]
+static RUST_ALWAYS_INLINED_PATTERN: &'static str = "bl.*<rust_always_inlined>";
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+static RUST_ALWAYS_INLINED_PATTERN: &'static str = "call.*rust_always_inlined";
+#[cfg(any(target_arch = "aarch64", target_arch = "arm"))]
+static C_ALWAYS_INLINED_PATTERN: &'static str = "bl.*<c_always_inlined>";
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+static C_ALWAYS_INLINED_PATTERN: &'static str = "call.*c_always_inlined";
+
+#[cfg(any(target_arch = "aarch64", target_arch = "arm"))]
+static RUST_NEVER_INLINED_PATTERN: &'static str = "bl.*<rust_never_inlined>";
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+static RUST_NEVER_INLINED_PATTERN: &'static str = "call.*rust_never_inlined";
+#[cfg(any(target_arch = "aarch64", target_arch = "arm"))]
+static C_NEVER_INLINED_PATTERN: &'static str = "bl.*<c_never_inlined>";
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+static C_NEVER_INLINED_PATTERN: &'static str = "call.*c_never_inlined";
+
 fn main() {
     rustc()
         .linker_plugin_lto("on")
@@ -31,14 +49,14 @@
         .disassemble()
         .input("cmain")
         .run()
-        .assert_stdout_not_contains_regex("call.*rust_always_inlined");
+        .assert_stdout_not_contains_regex(RUST_ALWAYS_INLINED_PATTERN);
     // As a sanity check, make sure we do find a call instruction to a
     // non-inlined function
     llvm_objdump()
         .disassemble()
         .input("cmain")
         .run()
-        .assert_stdout_contains_regex("call.*rust_never_inlined");
+        .assert_stdout_contains_regex(RUST_NEVER_INLINED_PATTERN);
     clang().input("clib.c").lto("thin").arg("-c").out_exe("clib.o").arg("-O2").run();
     llvm_ar().obj_to_ar().output_input(static_lib_name("xyz"), "clib.o").run();
     rustc()
@@ -53,10 +71,10 @@
         .disassemble()
         .input("rsmain")
         .run()
-        .assert_stdout_not_contains_regex("call.*c_always_inlined");
+        .assert_stdout_not_contains_regex(C_ALWAYS_INLINED_PATTERN);
     llvm_objdump()
         .disassemble()
         .input("rsmain")
         .run()
-        .assert_stdout_contains_regex("call.*c_never_inlined");
+        .assert_stdout_contains_regex(C_NEVER_INLINED_PATTERN);
 }
diff --git a/tests/run-make/cross-lang-lto-riscv-abi/rmake.rs b/tests/run-make/cross-lang-lto-riscv-abi/rmake.rs
index 9257335..e595dbe 100644
--- a/tests/run-make/cross-lang-lto-riscv-abi/rmake.rs
+++ b/tests/run-make/cross-lang-lto-riscv-abi/rmake.rs
@@ -1,21 +1,20 @@
-//! Make sure that cross-language LTO works on riscv targets,
-//! which requires extra `target-abi` metadata to be emitted.
+//! Make sure that cross-language LTO works on riscv targets, which requires extra `target-abi`
+//! metadata to be emitted.
 //@ needs-force-clang-based-tests
-//@ needs-llvm-components riscv
+//@ needs-llvm-components: riscv
 
-//@ needs-force-clang-based-tests
-// FIXME(#126180): This test can only run on `x86_64-gnu-debug`, because that CI job sets
-// RUSTBUILD_FORCE_CLANG_BASED_TESTS and only runs tests which contain "clang" in their
-// name.
-// However, this test does not run at all as its name does not contain "clang".
+// ignore-tidy-linelength
 
-use std::path::PathBuf;
-use std::process::{Command, Output};
-use std::{env, str};
+use object::elf;
+use object::read::elf as readelf;
+use run_make_support::{bin_name, clang, object, rfs, rustc};
 
-use run_make_support::{bin_name, clang, llvm_readobj, rustc};
-
-fn check_target(target: &str, clang_target: &str, carch: &str, is_double_float: bool) {
+fn check_target<H: readelf::FileHeader<Endian = object::Endianness>>(
+    target: &str,
+    clang_target: &str,
+    carch: &str,
+    is_double_float: bool,
+) {
     eprintln!("Checking target {target}");
     // Rust part
     rustc()
@@ -39,16 +38,55 @@
 
     // Check that the built binary has correct float abi
     let executable = bin_name("riscv-xlto");
-    let output = llvm_readobj().input(&executable).file_header().run();
-    let stdout = String::from_utf8_lossy(&output.stdout);
-    eprintln!("obj:\n{}", stdout);
-
-    assert!(!(is_double_float ^ stdout.contains("EF_RISCV_FLOAT_ABI_DOUBLE")));
+    let data = rfs::read(&executable);
+    let header = <H>::parse(&*data).unwrap();
+    let endian = match header.e_ident().data {
+        elf::ELFDATA2LSB => object::Endianness::Little,
+        elf::ELFDATA2MSB => object::Endianness::Big,
+        x => unreachable!("invalid e_ident data: {:#010b}", x),
+    };
+    // Check `(e_flags & EF_RISCV_FLOAT_ABI) == EF_RISCV_FLOAT_ABI_DOUBLE`.
+    //
+    // See
+    // <https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-elf.adoc#elf-object-files>.
+    if is_double_float {
+        assert_eq!(
+            header.e_flags(endian) & elf::EF_RISCV_FLOAT_ABI,
+            elf::EF_RISCV_FLOAT_ABI_DOUBLE,
+            "expected {target} to use double ABI, but it did not"
+        );
+    } else {
+        assert_ne!(
+            header.e_flags(endian) & elf::EF_RISCV_FLOAT_ABI,
+            elf::EF_RISCV_FLOAT_ABI_DOUBLE,
+            "did not expected {target} to use double ABI"
+        );
+    }
 }
 
 fn main() {
-    check_target("riscv64gc-unknown-linux-gnu", "riscv64-linux-gnu", "rv64gc", true);
-    check_target("riscv64imac-unknown-none-elf", "riscv64-unknown-elf", "rv64imac", false);
-    check_target("riscv32imac-unknown-none-elf", "riscv32-unknown-elf", "rv32imac", false);
-    check_target("riscv32gc-unknown-linux-gnu", "riscv32-linux-gnu", "rv32gc", true);
+    check_target::<elf::FileHeader64<object::Endianness>>(
+        "riscv64gc-unknown-linux-gnu",
+        "riscv64-linux-gnu",
+        "rv64gc",
+        true,
+    );
+    check_target::<elf::FileHeader64<object::Endianness>>(
+        "riscv64imac-unknown-none-elf",
+        "riscv64-unknown-elf",
+        "rv64imac",
+        false,
+    );
+    check_target::<elf::FileHeader32<object::Endianness>>(
+        "riscv32imac-unknown-none-elf",
+        "riscv32-unknown-elf",
+        "rv32imac",
+        false,
+    );
+    check_target::<elf::FileHeader32<object::Endianness>>(
+        "riscv32gc-unknown-linux-gnu",
+        "riscv32-linux-gnu",
+        "rv32gc",
+        true,
+    );
 }
diff --git a/tests/run-make/import-macro-verbatim/include/include.txt b/tests/run-make/import-macro-verbatim/include/include.txt
new file mode 100644
index 0000000..63d71b1
--- /dev/null
+++ b/tests/run-make/import-macro-verbatim/include/include.txt
@@ -0,0 +1 @@
+static TEST: &str = "Hello World!";
diff --git a/tests/run-make/import-macro-verbatim/rmake.rs b/tests/run-make/import-macro-verbatim/rmake.rs
new file mode 100644
index 0000000..d2bf626
--- /dev/null
+++ b/tests/run-make/import-macro-verbatim/rmake.rs
@@ -0,0 +1,8 @@
+//@ only-windows other platforms do not have Windows verbatim paths
+use run_make_support::rustc;
+fn main() {
+    // Canonicalizing the path ensures that it's verbatim (i.e. starts with `\\?\`)
+    let mut path = std::fs::canonicalize(file!()).unwrap();
+    path.pop();
+    rustc().input("verbatim.rs").env("VERBATIM_DIR", path).run();
+}
diff --git a/tests/run-make/import-macro-verbatim/verbatim.rs b/tests/run-make/import-macro-verbatim/verbatim.rs
new file mode 100644
index 0000000..56a8367
--- /dev/null
+++ b/tests/run-make/import-macro-verbatim/verbatim.rs
@@ -0,0 +1,12 @@
+//! Include a file by concating the verbatim path using `/` instead of `\`
+
+include!(concat!(env!("VERBATIM_DIR"), "/include/include.txt"));
+fn main() {
+    assert_eq!(TEST, "Hello World!");
+
+    let s = include_str!(concat!(env!("VERBATIM_DIR"), "/include/include.txt"));
+    assert_eq!(s, "static TEST: &str = \"Hello World!\";\n");
+
+    let b = include_bytes!(concat!(env!("VERBATIM_DIR"), "/include/include.txt"));
+    assert_eq!(b, b"static TEST: &str = \"Hello World!\";\n");
+}
diff --git a/tests/run-make/issue-84395-lto-embed-bitcode/Makefile b/tests/run-make/issue-84395-lto-embed-bitcode/Makefile
deleted file mode 100644
index aabe907..0000000
--- a/tests/run-make/issue-84395-lto-embed-bitcode/Makefile
+++ /dev/null
@@ -1,14 +0,0 @@
-# needs-force-clang-based-tests
-
-# FIXME(#126180): This test doesn't actually run anywhere, because the only
-# CI job that sets RUSTBUILD_FORCE_CLANG_BASED_TESTS runs very few tests.
-
-# This test makes sure the embed bitcode in elf created with
-# lto-embed-bitcode=optimized is valid llvm BC module.
-
-include ../tools.mk
-
-all:
-	$(RUSTC) test.rs --target $(TARGET) -Clink-arg=-fuse-ld=lld -Clinker-plugin-lto -Clinker=$(CLANG) -Clink-arg=-Wl,--plugin-opt=-lto-embed-bitcode=optimized -Zemit-thin-lto=no
-	$(LLVM_BIN_DIR)/objcopy --dump-section .llvmbc=$(TMPDIR)/test.bc $(TMPDIR)/test
-	$(LLVM_BIN_DIR)/llvm-dis $(TMPDIR)/test.bc
diff --git a/tests/run-make/issue-84395-lto-embed-bitcode/rmake.rs b/tests/run-make/issue-84395-lto-embed-bitcode/rmake.rs
new file mode 100644
index 0000000..450d8a9
--- /dev/null
+++ b/tests/run-make/issue-84395-lto-embed-bitcode/rmake.rs
@@ -0,0 +1,27 @@
+//! Smoke test to make sure the embed bitcode in elf created with
+//! `--plugin-opt=-lto-embed-bitcode=optimized` is valid llvm BC module.
+//!
+//! See <https://github.com/rust-lang/rust/issues/84395> where passing
+//! `-lto-embed-bitcode=optimized` to lld when linking rust code via `linker-plugin-lto` doesn't
+//! produce the expected result.
+//!
+//! See PR <https://github.com/rust-lang/rust/pull/98162> which initially introduced this test.
+
+//@ needs-force-clang-based-tests
+
+use run_make_support::{env_var, llvm_dis, llvm_objcopy, rustc};
+
+fn main() {
+    rustc()
+        .input("test.rs")
+        .arg("-Clink-arg=-fuse-ld=lld")
+        .arg("-Clinker-plugin-lto")
+        .arg(format!("-Clinker={}", env_var("CLANG")))
+        .arg("-Clink-arg=-Wl,--plugin-opt=-lto-embed-bitcode=optimized")
+        .arg("-Zemit-thin-lto=no")
+        .run();
+
+    llvm_objcopy().dump_section(".llvmbc", "test.bc").arg("test").run();
+
+    llvm_dis().arg("test.bc").run();
+}
diff --git a/tests/run-make/linkage-attr-framework/main.rs b/tests/run-make/linkage-attr-framework/main.rs
new file mode 100644
index 0000000..8efabc8
--- /dev/null
+++ b/tests/run-make/linkage-attr-framework/main.rs
@@ -0,0 +1,17 @@
+#![cfg_attr(any(weak, both), feature(link_arg_attribute))]
+
+#[cfg_attr(any(link, both), link(name = "CoreFoundation", kind = "framework"))]
+#[cfg_attr(
+    any(weak, both),
+    link(name = "-weak_framework", kind = "link-arg", modifiers = "+verbatim"),
+    link(name = "CoreFoundation", kind = "link-arg", modifiers = "+verbatim")
+)]
+extern "C" {
+    fn CFRunLoopGetTypeID() -> core::ffi::c_ulong;
+}
+
+fn main() {
+    unsafe {
+        CFRunLoopGetTypeID();
+    }
+}
diff --git a/tests/run-make/linkage-attr-framework/rmake.rs b/tests/run-make/linkage-attr-framework/rmake.rs
new file mode 100644
index 0000000..4450350
--- /dev/null
+++ b/tests/run-make/linkage-attr-framework/rmake.rs
@@ -0,0 +1,26 @@
+//! Check that linking frameworks on Apple platforms works.
+
+//@ only-apple
+
+use run_make_support::{Rustc, run, rustc};
+
+fn compile(cfg: &str) -> Rustc {
+    let mut rustc = rustc();
+    rustc.cfg(cfg).input("main.rs");
+    rustc
+}
+
+fn main() {
+    for cfg in ["link", "weak", "both"] {
+        compile(cfg).run();
+        run("main");
+    }
+
+    let errs = compile("omit").run_fail();
+    // The linker's exact error output changes between Xcode versions, depends on
+    // linker invocation details, and the linker sometimes outputs more warnings.
+    errs.assert_stderr_contains_regex(r"error: linking with `.*` failed");
+    errs.assert_stderr_contains_regex(r"(Undefined symbols|ld: symbol[^\s]* not found)");
+    errs.assert_stderr_contains_regex(r".?_CFRunLoopGetTypeID.?, referenced from:");
+    errs.assert_stderr_contains("clang: error: linker command failed with exit code 1");
+}
diff --git a/tests/run-make/pointer-auth-link-with-c-lto-clang/rmake.rs b/tests/run-make/pointer-auth-link-with-c-lto-clang/rmake.rs
new file mode 100644
index 0000000..cf6e3d8
--- /dev/null
+++ b/tests/run-make/pointer-auth-link-with-c-lto-clang/rmake.rs
@@ -0,0 +1,36 @@
+// `-Z branch protection` is an unstable compiler feature which adds pointer-authentication
+// code (PAC), a useful hashing measure for verifying that pointers have not been modified.
+// This test checks that compilation and execution is successful when this feature is activated,
+// with some of its possible extra arguments (bti, pac-ret, leaf) when doing LTO.
+// See https://github.com/rust-lang/rust/pull/88354
+
+//@ needs-force-clang-based-tests
+//@ only-aarch64
+// Reason: branch protection is not supported on other architectures
+//@ ignore-cross-compile
+// Reason: the compiled binary is executed
+
+use run_make_support::{clang, env_var, llvm_ar, run, rustc, static_lib_name};
+
+fn main() {
+    clang()
+        .arg("-v")
+        .lto("thin")
+        .arg("-mbranch-protection=bti+pac-ret+leaf")
+        .arg("-O2")
+        .arg("-c")
+        .out_exe("test.o")
+        .input("test.c")
+        .run();
+    llvm_ar().obj_to_ar().output_input(static_lib_name("test"), "test.o").run();
+    rustc()
+        .linker_plugin_lto("on")
+        .opt_level("2")
+        .linker(&env_var("CLANG"))
+        .link_arg("-fuse-ld=lld")
+        .arg("-Zbranch-protection=bti,pac-ret,leaf")
+        .input("test.rs")
+        .output("test.bin")
+        .run();
+    run("test.bin");
+}
diff --git a/tests/run-make/pointer-auth-link-with-c-lto-clang/test.c b/tests/run-make/pointer-auth-link-with-c-lto-clang/test.c
new file mode 100644
index 0000000..9fe07f8
--- /dev/null
+++ b/tests/run-make/pointer-auth-link-with-c-lto-clang/test.c
@@ -0,0 +1 @@
+int foo() { return 0; }
diff --git a/tests/run-make/pointer-auth-link-with-c-lto-clang/test.rs b/tests/run-make/pointer-auth-link-with-c-lto-clang/test.rs
new file mode 100644
index 0000000..1a3be80
--- /dev/null
+++ b/tests/run-make/pointer-auth-link-with-c-lto-clang/test.rs
@@ -0,0 +1,10 @@
+#[link(name = "test")]
+extern "C" {
+    fn foo() -> i32;
+}
+
+fn main() {
+    unsafe {
+        foo();
+    }
+}
diff --git a/tests/run-make/rust-lld-link-script-provide/main.rs b/tests/run-make/rust-lld-link-script-provide/main.rs
new file mode 100644
index 0000000..5c19e7a
--- /dev/null
+++ b/tests/run-make/rust-lld-link-script-provide/main.rs
@@ -0,0 +1,7 @@
+#[no_mangle]
+fn foo() {}
+
+#[no_mangle]
+fn bar() {}
+
+fn main() {}
diff --git a/tests/run-make/rust-lld-link-script-provide/rmake.rs b/tests/run-make/rust-lld-link-script-provide/rmake.rs
new file mode 100644
index 0000000..e78a411
--- /dev/null
+++ b/tests/run-make/rust-lld-link-script-provide/rmake.rs
@@ -0,0 +1,18 @@
+// This test ensures that the “symbol not found” error does not occur
+// when the symbols in the `PROVIDE` of the link script can be eliminated.
+// This is a regression test for #131164.
+
+//@ needs-rust-lld
+//@ only-x86_64-unknown-linux-gnu
+
+use run_make_support::rustc;
+
+fn main() {
+    rustc()
+        .input("main.rs")
+        .arg("-Zlinker-features=+lld")
+        .arg("-Clink-self-contained=+linker")
+        .arg("-Zunstable-options")
+        .link_arg("-Tscript.t")
+        .run();
+}
diff --git a/tests/run-make/rust-lld-link-script-provide/script.t b/tests/run-make/rust-lld-link-script-provide/script.t
new file mode 100644
index 0000000..4c4c6dd
--- /dev/null
+++ b/tests/run-make/rust-lld-link-script-provide/script.t
@@ -0,0 +1 @@
+PROVIDE(foo = bar);
diff --git a/tests/rustdoc-gui/check-stab-in-docblock.goml b/tests/rustdoc-gui/check-stab-in-docblock.goml
index f25c886..916bea6 100644
--- a/tests/rustdoc-gui/check-stab-in-docblock.goml
+++ b/tests/rustdoc-gui/check-stab-in-docblock.goml
@@ -1,5 +1,5 @@
 // This test checks that using `.stab` attributes in `.docblock` elements doesn't
-// create scrollable paragraphs.
+// create scrollable paragraphs and is correctly displayed (not making weird blocks).
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
 // Needs the text to be display to check for scrollable content.
 show-text: true
@@ -31,3 +31,15 @@
     ".top-doc .docblock p:nth-of-type(3)",
     {"scrollHeight": |clientHeight|, "scrollWidth": |clientWidth|},
 )
+
+// Ensure that `<code>` elements in code don't make big blocks.
+compare-elements-size-near: (
+    "#reexport\.TheStdReexport > code",
+    ".docblock p span[data-span='1']",
+    {"height": 1},
+)
+compare-elements-size-near: (
+    "#reexport\.TheStdReexport > code",
+    ".docblock p span[data-span='2']",
+    {"height": 1},
+)
diff --git a/tests/rustdoc-gui/docblock-big-code-mobile.goml b/tests/rustdoc-gui/docblock-big-code-mobile.goml
index 6fc6834..71e08e2 100644
--- a/tests/rustdoc-gui/docblock-big-code-mobile.goml
+++ b/tests/rustdoc-gui/docblock-big-code-mobile.goml
@@ -1,13 +1,15 @@
 // If we have a long `<code>`, we need to ensure that it'll be fully displayed on mobile, meaning
 // that it'll be on two lines.
+
 emulate: "iPhone 8" // it has the following size: (375, 667)
 go-to: "file://" + |DOC_PATH| + "/test_docs/long_code_block/index.html"
-// We now check that the block is on two lines:
 show-text: true // We need to enable text draw to be able to have the "real" size
+
+// We now check that the block is on two lines:
 // Little explanations for this test: if the text wasn't displayed on two lines, it would take
-// around 20px (which is the font size).
-assert-property: (".docblock p > code", {"offsetHeight": "44"})
+// around 24px (which is the font size).
+assert-size: (".docblock p > code", {"height": 48})
 
 // Same check, but where the long code block is also a link
 go-to: "file://" + |DOC_PATH| + "/test_docs/long_code_block_link/index.html"
-assert-property: (".docblock p > a > code", {"offsetHeight": "44"})
+assert-size: (".docblock p > a > code", {"height": 48})
diff --git a/tests/rustdoc-gui/fields.goml b/tests/rustdoc-gui/fields.goml
index b8139a2..5d13d7b 100644
--- a/tests/rustdoc-gui/fields.goml
+++ b/tests/rustdoc-gui/fields.goml
@@ -1,13 +1,36 @@
-// This test checks that fields are displayed as expected (one by line).
-go-to: "file://" + |DOC_PATH| + "/test_docs/fields/struct.Struct.html"
-store-position: ("#structfield\.a", {"y": a_y})
-store-position: ("#structfield\.b", {"y": b_y})
-assert: |a_y| < |b_y|
+// This test checks that fields are displayed as expected (one by line) and they are surrounded
+// by margins.
 
-go-to: "file://" + |DOC_PATH| + "/test_docs/fields/union.Union.html"
-store-position: ("#structfield\.a", {"y": a_y})
-store-position: ("#structfield\.b", {"y": b_y})
-assert: |a_y| < |b_y|
+define-function: (
+    "check-fields",
+    [path, selector_1, selector_2],
+    block {
+        go-to: "file://" + |DOC_PATH| + "/test_docs/fields/" + |path|
+        store-position: (|selector_1|, {"y": a_y})
+        store-position: (|selector_2|, {"y": b_y})
+        assert: |a_y| < |b_y|
+
+        // Check the margins.
+        assert-css: (".structfield.section-header", {
+            "margin-top": "9.6px",
+            "margin-bottom": "9.6px",
+            "margin-left": "0px",
+            "margin-right": "0px",
+        }, ALL)
+    }
+)
+
+call-function: ("check-fields", {
+    "path": "struct.Struct.html",
+    "selector_1": "#structfield\.a",
+    "selector_2": "#structfield\.b",
+})
+
+call-function: ("check-fields", {
+    "path": "union.Union.html",
+    "selector_1": "#structfield\.a",
+    "selector_2": "#structfield\.b",
+})
 
 go-to: "file://" + |DOC_PATH| + "/test_docs/fields/enum.Enum.html"
 store-position: ("#variant\.A\.field\.a", {"y": a_y})
@@ -16,3 +39,11 @@
 store-position: ("#variant\.B\.field\.a", {"y": a_y})
 store-position: ("#variant\.B\.field\.b", {"y": b_y})
 assert: |a_y| < |b_y|
+
+// Check the margins.
+assert-css: (".sub-variant-field .section-header", {
+    "margin-top": "0px",
+    "margin-bottom": "0px",
+    "margin-left": "0px",
+    "margin-right": "0px",
+}, ALL)
diff --git a/tests/rustdoc-gui/item-info.goml b/tests/rustdoc-gui/item-info.goml
index c8aa7b3..1636e14 100644
--- a/tests/rustdoc-gui/item-info.goml
+++ b/tests/rustdoc-gui/item-info.goml
@@ -20,7 +20,7 @@
     {"x": second_line_x, "y": second_line_y},
 )
 assert: |first_line_x| != |second_line_x| && |first_line_x| == 516 && |second_line_x| == 272
-assert: |first_line_y| != |second_line_y| && |first_line_y| == 714 && |second_line_y| == 737
+assert: |first_line_y| != |second_line_y| && |first_line_y| == 718 && |second_line_y| == 741
 
 // Now we ensure that they're not rendered on the same line.
 set-window-size: (1100, 800)
diff --git a/tests/rustdoc-gui/scrape-examples-layout.goml b/tests/rustdoc-gui/scrape-examples-layout.goml
index 96c78bb..5187ac4 100644
--- a/tests/rustdoc-gui/scrape-examples-layout.goml
+++ b/tests/rustdoc-gui/scrape-examples-layout.goml
@@ -80,8 +80,8 @@
 store-value: (offset_y, 4)
 
 // First with desktop
-assert-position: (".scraped-example", {"y": 252})
-assert-position: (".scraped-example .prev", {"y": 252 + |offset_y|})
+assert-position: (".scraped-example", {"y": 256})
+assert-position: (".scraped-example .prev", {"y": 256 + |offset_y|})
 
 // Gradient background should be at the top of the code block.
 assert-css: (".scraped-example .example-wrap::before", {"top": "0px"})
@@ -90,8 +90,8 @@
 // Then with mobile
 set-window-size: (600, 600)
 store-size: (".scraped-example .scraped-example-title", {"height": title_height})
-assert-position: (".scraped-example", {"y": 287})
-assert-position: (".scraped-example .prev", {"y": 287 + |offset_y| + |title_height|})
+assert-position: (".scraped-example", {"y": 291})
+assert-position: (".scraped-example .prev", {"y": 291 + |offset_y| + |title_height|})
 
 define-function: (
     "check_title_and_code_position",
diff --git a/tests/rustdoc-gui/sidebar-source-code-display.goml b/tests/rustdoc-gui/sidebar-source-code-display.goml
index 742453c..1e77bcc 100644
--- a/tests/rustdoc-gui/sidebar-source-code-display.goml
+++ b/tests/rustdoc-gui/sidebar-source-code-display.goml
@@ -141,7 +141,7 @@
 wait-for-css: (".src .sidebar > *", {"visibility": "hidden"})
 // We scroll to line 117 to change the scroll position.
 scroll-to: '//*[@id="117"]'
-store-value: (y_offset, "2570")
+store-value: (y_offset, "2578")
 assert-window-property: {"pageYOffset": |y_offset|}
 // Expanding the sidebar...
 click: "#sidebar-button"
diff --git a/tests/rustdoc-gui/source-anchor-scroll.goml b/tests/rustdoc-gui/source-anchor-scroll.goml
index f879464..4ad65bb 100644
--- a/tests/rustdoc-gui/source-anchor-scroll.goml
+++ b/tests/rustdoc-gui/source-anchor-scroll.goml
@@ -8,13 +8,13 @@
 assert-property: ("html", {"scrollTop": "0"})
 
 click: '//a[text() = "barbar" and @href="#5-7"]'
-assert-property: ("html", {"scrollTop": "200"})
+assert-property: ("html", {"scrollTop": "208"})
 click: '//a[text() = "bar" and @href="#28-36"]'
-assert-property: ("html", {"scrollTop": "231"})
+assert-property: ("html", {"scrollTop": "239"})
 click: '//a[normalize-space() = "sub_fn" and @href="#2-4"]'
-assert-property: ("html", {"scrollTop": "128"})
+assert-property: ("html", {"scrollTop": "136"})
 
 // We now check that clicking on lines doesn't change the scroll
 // Extra information: the "sub_fn" function header is on line 1.
 click: '//*[@id="6"]'
-assert-property: ("html", {"scrollTop": "128"})
+assert-property: ("html", {"scrollTop": "136"})
diff --git a/tests/rustdoc-gui/source-code-page.goml b/tests/rustdoc-gui/source-code-page.goml
index 095354c..afb1946 100644
--- a/tests/rustdoc-gui/source-code-page.goml
+++ b/tests/rustdoc-gui/source-code-page.goml
@@ -89,7 +89,7 @@
 // do anything (and certainly not add a `#NaN` to the URL!).
 go-to: "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html"
 // We use this assert-position to know where we will click.
-assert-position: ("//*[@id='1']", {"x": 88, "y": 163})
+assert-position: ("//*[@id='1']", {"x": 88, "y": 171})
 // We click on the left of the "1" anchor but still in the "src-line-number" `<pre>`.
 click: (163, 77)
 assert-document-property: ({"URL": "/lib.rs.html"}, ENDS_WITH)
@@ -165,7 +165,7 @@
 // offsetTop[nav.sub form] = offsetTop[#main-content] - offsetHeight[nav.sub form] - offsetTop[nav.sub form]
 assert-position: ("nav.sub form", {"y": 15})
 assert-property: ("nav.sub form", {"offsetHeight": 34})
-assert-position: ("h1", {"y": 64})
+assert-position: ("h1", {"y": 68})
 // 15 = 64 - 34 - 15
 
 // Now do the same check on moderately-sized, tablet mobile.
@@ -173,7 +173,7 @@
 assert-css: ("nav.sub", {"flex-direction": "row"})
 assert-position: ("nav.sub form", {"y": 8})
 assert-property: ("nav.sub form", {"offsetHeight": 34})
-assert-position: ("h1", {"y": 50})
+assert-position: ("h1", {"y": 54})
 // 8 = 50 - 34 - 8
 
 // Check the sidebar directory entries have a marker and spacing (tablet).
diff --git a/tests/rustdoc-gui/struct-fields.goml b/tests/rustdoc-gui/struct-fields.goml
index 3c87a4c..302a1a0 100644
--- a/tests/rustdoc-gui/struct-fields.goml
+++ b/tests/rustdoc-gui/struct-fields.goml
@@ -1,4 +1,5 @@
-// This test ensures that each field is on its own line (In other words, they have display: block).
+// This test ensures that each field is on its own line (In other words, they have
+// `display: block`).
 go-to: "file://" + |DOC_PATH| + "/test_docs/struct.StructWithPublicUndocumentedFields.html"
 
 store-property: ("//*[@id='structfield.first']", {"offsetTop": first_top})
diff --git a/tests/rustdoc-js/extern-func.js b/tests/rustdoc-js/extern-func.js
new file mode 100644
index 0000000..a3fe2d8
--- /dev/null
+++ b/tests/rustdoc-js/extern-func.js
@@ -0,0 +1,8 @@
+const EXPECTED = [
+    {
+        'query': 'c_float -> c_float',
+        'others': [
+            { 'path': 'extern_func', 'name': 'sqrt' }
+        ],
+    },
+];
diff --git a/tests/rustdoc-js/extern-func.rs b/tests/rustdoc-js/extern-func.rs
new file mode 100644
index 0000000..ab1e3e7
--- /dev/null
+++ b/tests/rustdoc-js/extern-func.rs
@@ -0,0 +1,5 @@
+use std::ffi::c_float;
+
+extern "C" {
+    pub fn sqrt(x: c_float) -> c_float;
+}
diff --git a/tests/rustdoc-json/impls/auto.rs b/tests/rustdoc-json/impls/auto.rs
index e14c935..f37dae4 100644
--- a/tests/rustdoc-json/impls/auto.rs
+++ b/tests/rustdoc-json/impls/auto.rs
@@ -4,8 +4,8 @@
 #[lang = "sized"]
 trait Sized {}
 
-#[lang = "receiver"]
-pub trait Receiver {}
+#[lang = "legacy_receiver"]
+pub trait LegacyReceiver {}
 
 pub auto trait Bar {}
 
diff --git a/tests/rustdoc-ui/deprecated-attrs.rs b/tests/rustdoc-ui/deprecated-attrs.rs
index e4802ee..3b59e05 100644
--- a/tests/rustdoc-ui/deprecated-attrs.rs
+++ b/tests/rustdoc-ui/deprecated-attrs.rs
@@ -1,16 +1,21 @@
-//@ check-pass
 //@ compile-flags: --passes unknown-pass
 //@ error-pattern: the `passes` flag no longer functions
 
 #![doc(no_default_passes)]
-//~^ WARNING attribute is deprecated
+//~^ ERROR unknown `doc` attribute `no_default_passes`
+//~| NOTE no longer functions
 //~| NOTE see issue #44136
-//~| HELP no longer functions; you may want to use `#![doc(document_private_items)]`
+//~| HELP you may want to use `doc(document_private_items)`
+//~| NOTE `doc(no_default_passes)` is now a no-op
+//~| NOTE `#[deny(invalid_doc_attributes)]` on by default
 #![doc(passes = "collapse-docs unindent-comments")]
-//~^ WARNING attribute is deprecated
+//~^ ERROR unknown `doc` attribute `passes`
+//~| NOTE no longer functions
 //~| NOTE see issue #44136
-//~| HELP no longer functions; you may want to use `#![doc(document_private_items)]`
+//~| HELP you may want to use `doc(document_private_items)`
+//~| NOTE `doc(passes)` is now a no-op
 #![doc(plugins = "xxx")]
-//~^ WARNING attribute is deprecated
+//~^ ERROR unknown `doc` attribute `plugins`
 //~| NOTE see issue #44136
-//~| WARNING no longer functions; see CVE
+//~| NOTE no longer functions
+//~| NOTE `doc(plugins)` is now a no-op
diff --git a/tests/rustdoc-ui/deprecated-attrs.stderr b/tests/rustdoc-ui/deprecated-attrs.stderr
index 45b20ce..a30523e 100644
--- a/tests/rustdoc-ui/deprecated-attrs.stderr
+++ b/tests/rustdoc-ui/deprecated-attrs.stderr
@@ -3,32 +3,35 @@
    = note: see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information
    = help: you may want to use --document-private-items
 
-warning: the `#![doc(no_default_passes)]` attribute is deprecated
-  --> $DIR/deprecated-attrs.rs:5:8
+error: unknown `doc` attribute `no_default_passes`
+  --> $DIR/deprecated-attrs.rs:4:8
    |
 LL | #![doc(no_default_passes)]
-   |        ^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^^^^^^^^ no longer functions
    |
-   = note: see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information
-   = help: `#![doc(no_default_passes)]` no longer functions; you may want to use `#![doc(document_private_items)]`
+   = note: `doc` attribute `no_default_passes` no longer functions; see issue #44136 <https://github.com/rust-lang/rust/issues/44136>
+   = help: you may want to use `doc(document_private_items)`
+   = note: `doc(no_default_passes)` is now a no-op
+   = note: `#[deny(invalid_doc_attributes)]` on by default
 
-warning: the `#![doc(passes = "...")]` attribute is deprecated
-  --> $DIR/deprecated-attrs.rs:9:8
+error: unknown `doc` attribute `passes`
+  --> $DIR/deprecated-attrs.rs:11:8
    |
 LL | #![doc(passes = "collapse-docs unindent-comments")]
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no longer functions
    |
-   = note: see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information
-   = help: `#![doc(passes = "...")]` no longer functions; you may want to use `#![doc(document_private_items)]`
+   = note: `doc` attribute `passes` no longer functions; see issue #44136 <https://github.com/rust-lang/rust/issues/44136>
+   = help: you may want to use `doc(document_private_items)`
+   = note: `doc(passes)` is now a no-op
 
-warning: the `#![doc(plugins = "...")]` attribute is deprecated
-  --> $DIR/deprecated-attrs.rs:13:8
+error: unknown `doc` attribute `plugins`
+  --> $DIR/deprecated-attrs.rs:17:8
    |
 LL | #![doc(plugins = "xxx")]
-   |        ^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^^^^^^ no longer functions
    |
-   = note: see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information
-   = warning: `#![doc(plugins = "...")]` no longer functions; see CVE-2018-1000622 <https://nvd.nist.gov/vuln/detail/CVE-2018-1000622>
+   = note: `doc` attribute `plugins` no longer functions; see issue #44136 <https://github.com/rust-lang/rust/issues/44136> and CVE-2018-1000622 <https://nvd.nist.gov/vuln/detail/CVE-2018-1000622>
+   = note: `doc(plugins)` is now a no-op
 
-warning: 3 warnings emitted
+error: aborting due to 3 previous errors
 
diff --git a/tests/rustdoc-ui/doctest/nested-main.rs b/tests/rustdoc-ui/doctest/nested-main.rs
new file mode 100644
index 0000000..e939ba8
--- /dev/null
+++ b/tests/rustdoc-ui/doctest/nested-main.rs
@@ -0,0 +1,24 @@
+//@ check-pass
+//@ compile-flags:--test --test-args=--test-threads=1
+//@ normalize-stdout-test: "tests/rustdoc-ui/doctest" -> "$$DIR"
+//@ normalize-stdout-test: "finished in \d+\.\d+s" -> "finished in $$TIME"
+
+// Regression test for <https://github.com/rust-lang/rust/issues/131893>.
+// It ensures that if a function called `main` is nested, it will not consider
+// it as the `main` function.
+
+/// ```
+/// fn dox() {
+///     fn main() {}
+/// }
+/// ```
+pub fn foo() {}
+
+// This one ensures that having a nested `main` doesn't prevent the
+// actual `main` function to be detected.
+/// ```
+/// fn main() {
+///     fn main() {}
+/// }
+/// ```
+pub fn foo2() {}
diff --git a/tests/rustdoc-ui/doctest/nested-main.stdout b/tests/rustdoc-ui/doctest/nested-main.stdout
new file mode 100644
index 0000000..af9a8f5
--- /dev/null
+++ b/tests/rustdoc-ui/doctest/nested-main.stdout
@@ -0,0 +1,7 @@
+
+running 2 tests
+test $DIR/nested-main.rs - foo (line 10) ... ok
+test $DIR/nested-main.rs - foo2 (line 19) ... ok
+
+test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
+
diff --git a/tests/rustdoc-ui/rustc-check-passes.stderr b/tests/rustdoc-ui/rustc-check-passes.stderr
index 58d61c0..5b20d11 100644
--- a/tests/rustdoc-ui/rustc-check-passes.stderr
+++ b/tests/rustdoc-ui/rustc-check-passes.stderr
@@ -1,4 +1,4 @@
-error[E0636]: the feature `rustdoc_internals` has already been declared
+error[E0636]: the feature `rustdoc_internals` has already been enabled
   --> $DIR/rustc-check-passes.rs:2:12
    |
 LL | #![feature(rustdoc_internals)]
diff --git a/tests/rustdoc/anchors.no_const_anchor.html b/tests/rustdoc/anchors.no_const_anchor.html
index 06673d8..07a7507 100644
--- a/tests/rustdoc/anchors.no_const_anchor.html
+++ b/tests/rustdoc/anchors.no_const_anchor.html
@@ -1 +1 @@
-<section id="associatedconstant.YOLO" class="method"><a class="src rightside" href="../src/foo/anchors.rs.html#16">source</a><h4 class="code-header">const <a href="#associatedconstant.YOLO" class="constant">YOLO</a>: <a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a></h4></section>
\ No newline at end of file
+<section id="associatedconstant.YOLO" class="method"><a class="src rightside" href="../src/foo/anchors.rs.html#16">Source</a><h4 class="code-header">const <a href="#associatedconstant.YOLO" class="constant">YOLO</a>: <a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a></h4></section>
\ No newline at end of file
diff --git a/tests/rustdoc/anchors.no_const_anchor2.html b/tests/rustdoc/anchors.no_const_anchor2.html
index 73c3d0a..091dac3 100644
--- a/tests/rustdoc/anchors.no_const_anchor2.html
+++ b/tests/rustdoc/anchors.no_const_anchor2.html
@@ -1 +1 @@
-<section id="associatedconstant.X" class="associatedconstant"><a class="src rightside" href="../src/foo/anchors.rs.html#42">source</a><h4 class="code-header">pub const <a href="#associatedconstant.X" class="constant">X</a>: <a class="primitive" href="{{channel}}/std/primitive.i32.html">i32</a> = 0i32</h4></section>
\ No newline at end of file
+<section id="associatedconstant.X" class="associatedconstant"><a class="src rightside" href="../src/foo/anchors.rs.html#42">Source</a><h4 class="code-header">pub const <a href="#associatedconstant.X" class="constant">X</a>: <a class="primitive" href="{{channel}}/std/primitive.i32.html">i32</a> = 0i32</h4></section>
\ No newline at end of file
diff --git a/tests/rustdoc/anchors.no_method_anchor.html b/tests/rustdoc/anchors.no_method_anchor.html
index e8b61ca..89f9898 100644
--- a/tests/rustdoc/anchors.no_method_anchor.html
+++ b/tests/rustdoc/anchors.no_method_anchor.html
@@ -1 +1 @@
-<section id="method.new" class="method"><a class="src rightside" href="../src/foo/anchors.rs.html#48">source</a><h4 class="code-header">pub fn <a href="#method.new" class="fn">new</a>() -&gt; Self</h4></section>
\ No newline at end of file
+<section id="method.new" class="method"><a class="src rightside" href="../src/foo/anchors.rs.html#48">Source</a><h4 class="code-header">pub fn <a href="#method.new" class="fn">new</a>() -&gt; Self</h4></section>
\ No newline at end of file
diff --git a/tests/rustdoc/anchors.no_trait_method_anchor.html b/tests/rustdoc/anchors.no_trait_method_anchor.html
index abdb17c..51656a3 100644
--- a/tests/rustdoc/anchors.no_trait_method_anchor.html
+++ b/tests/rustdoc/anchors.no_trait_method_anchor.html
@@ -1 +1 @@
-<section id="method.bar" class="method"><a class="src rightside" href="../src/foo/anchors.rs.html#23">source</a><h4 class="code-header">fn <a href="#method.bar" class="fn">bar</a>()</h4></section>
\ No newline at end of file
+<section id="method.bar" class="method"><a class="src rightside" href="../src/foo/anchors.rs.html#23">Source</a><h4 class="code-header">fn <a href="#method.bar" class="fn">bar</a>()</h4></section>
\ No newline at end of file
diff --git a/tests/rustdoc/anchors.no_tymethod_anchor.html b/tests/rustdoc/anchors.no_tymethod_anchor.html
index 23f4277..49ee624 100644
--- a/tests/rustdoc/anchors.no_tymethod_anchor.html
+++ b/tests/rustdoc/anchors.no_tymethod_anchor.html
@@ -1 +1 @@
-<section id="tymethod.foo" class="method"><a class="src rightside" href="../src/foo/anchors.rs.html#20">source</a><h4 class="code-header">fn <a href="#tymethod.foo" class="fn">foo</a>()</h4></section>
\ No newline at end of file
+<section id="tymethod.foo" class="method"><a class="src rightside" href="../src/foo/anchors.rs.html#20">Source</a><h4 class="code-header">fn <a href="#tymethod.foo" class="fn">foo</a>()</h4></section>
\ No newline at end of file
diff --git a/tests/rustdoc/anchors.no_type_anchor.html b/tests/rustdoc/anchors.no_type_anchor.html
index 62b9295..c5ac3c9 100644
--- a/tests/rustdoc/anchors.no_type_anchor.html
+++ b/tests/rustdoc/anchors.no_type_anchor.html
@@ -1 +1 @@
-<section id="associatedtype.T" class="method"><a class="src rightside" href="../src/foo/anchors.rs.html#13">source</a><h4 class="code-header">type <a href="#associatedtype.T" class="associatedtype">T</a></h4></section>
\ No newline at end of file
+<section id="associatedtype.T" class="method"><a class="src rightside" href="../src/foo/anchors.rs.html#13">Source</a><h4 class="code-header">type <a href="#associatedtype.T" class="associatedtype">T</a></h4></section>
\ No newline at end of file
diff --git a/tests/rustdoc/anchors.no_type_anchor2.html b/tests/rustdoc/anchors.no_type_anchor2.html
index 9127104..14dd31d 100644
--- a/tests/rustdoc/anchors.no_type_anchor2.html
+++ b/tests/rustdoc/anchors.no_type_anchor2.html
@@ -1 +1 @@
-<section id="associatedtype.Y" class="associatedtype"><a class="src rightside" href="../src/foo/anchors.rs.html#45">source</a><h4 class="code-header">pub type <a href="#associatedtype.Y" class="associatedtype">Y</a> = <a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a></h4></section>
\ No newline at end of file
+<section id="associatedtype.Y" class="associatedtype"><a class="src rightside" href="../src/foo/anchors.rs.html#45">Source</a><h4 class="code-header">pub type <a href="#associatedtype.Y" class="associatedtype">Y</a> = <a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a></h4></section>
\ No newline at end of file
diff --git a/tests/rustdoc/assoc-type-source-link.rs b/tests/rustdoc/assoc-type-source-link.rs
index 34b156b..a955a67 100644
--- a/tests/rustdoc/assoc-type-source-link.rs
+++ b/tests/rustdoc/assoc-type-source-link.rs
@@ -8,7 +8,7 @@
 pub struct Bar;
 
 impl Bar {
-    //@ has - '//*[@id="implementations-list"]//*[@id="associatedtype.Y"]/a' 'source'
+    //@ has - '//*[@id="implementations-list"]//*[@id="associatedtype.Y"]/a' 'Source'
     //@ has - '//*[@id="implementations-list"]//*[@id="associatedtype.Y"]/a/@href' \
     // '../src/foo/assoc-type-source-link.rs.html#14'
     pub type Y = u8;
@@ -19,7 +19,7 @@
 }
 
 impl Foo for Bar {
-    //@ has - '//*[@id="trait-implementations-list"]//*[@id="associatedtype.Z"]/a' 'source'
+    //@ has - '//*[@id="trait-implementations-list"]//*[@id="associatedtype.Z"]/a' 'Source'
     //@ has - '//*[@id="trait-implementations-list"]//*[@id="associatedtype.Z"]/a/@href' \
     // '../src/foo/assoc-type-source-link.rs.html#25'
     type Z = u8;
diff --git a/tests/rustdoc/const-display.rs b/tests/rustdoc/const-display.rs
index a71825d..bc4270c 100644
--- a/tests/rustdoc/const-display.rs
+++ b/tests/rustdoc/const-display.rs
@@ -89,10 +89,4 @@
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_stable(feature = "const2", since = "1.2.0")]
     pub const fn stable_impl() -> u32 { 42 }
-
-    // Show const-stability even for unstable functions.
-    //@ matches 'foo/struct.Bar.html' '//span[@class="since"]' '^const: 1.3.0$'
-    #[unstable(feature = "foo2", issue = "none")]
-    #[rustc_const_stable(feature = "const3", since = "1.3.0")]
-    pub const fn const_stable_unstable() -> u32 { 42 }
 }
diff --git a/tests/rustdoc/demo-allocator-54478.rs b/tests/rustdoc/demo-allocator-54478.rs
index dd98e80..80acfc0 100644
--- a/tests/rustdoc/demo-allocator-54478.rs
+++ b/tests/rustdoc/demo-allocator-54478.rs
@@ -40,6 +40,7 @@
 //! }
 //!
 //! fn main() {
+//!     drop(String::from("An allocation"));
 //!     assert!(unsafe { HIT });
 //! }
 //! ```
diff --git a/tests/rustdoc/ensure-src-link.rs b/tests/rustdoc/ensure-src-link.rs
index 4156fdc..f70902b 100644
--- a/tests/rustdoc/ensure-src-link.rs
+++ b/tests/rustdoc/ensure-src-link.rs
@@ -2,5 +2,5 @@
 
 // This test ensures that the [src] link is present on traits items.
 
-//@ has foo/trait.Iterator.html '//*[@id="method.zip"]//a[@class="src"]' "source"
+//@ has foo/trait.Iterator.html '//*[@id="method.zip"]//a[@class="src"]' "Source"
 pub use std::iter::Iterator;
diff --git a/tests/rustdoc/external-macro-src.rs b/tests/rustdoc/external-macro-src.rs
index f723af5..998687d 100644
--- a/tests/rustdoc/external-macro-src.rs
+++ b/tests/rustdoc/external-macro-src.rs
@@ -5,8 +5,8 @@
 #[macro_use]
 extern crate external_macro_src;
 
-//@ has foo/index.html '//a[@href="../src/foo/external-macro-src.rs.html#3-12"]' 'source'
+//@ has foo/index.html '//a[@href="../src/foo/external-macro-src.rs.html#3-12"]' 'Source'
 
 //@ has foo/struct.Foo.html
-//@ has - '//a[@href="../src/foo/external-macro-src.rs.html#12"]' 'source'
+//@ has - '//a[@href="../src/foo/external-macro-src.rs.html#12"]' 'Source'
 make_foo!();
diff --git a/tests/rustdoc/primitive-tuple-variadic.rs b/tests/rustdoc/primitive-tuple-variadic.rs
index b15e996..d142729 100644
--- a/tests/rustdoc/primitive-tuple-variadic.rs
+++ b/tests/rustdoc/primitive-tuple-variadic.rs
@@ -33,3 +33,22 @@
 //@ has - '//section[@id="impl-Baz%3CT%3E-for-(T,)"]/h3' 'impl<T> Baz<T> for (T₁, T₂, …, Tₙ)'
 #[doc(fake_variadic)]
 impl<T> Baz<T> for (T,) {}
+
+pub trait Qux {}
+
+pub struct NewType<T>(T);
+
+//@ has foo/trait.Qux.html
+//@ has - '//section[@id="impl-Qux-for-NewType%3C(T,)%3E"]/h3' 'impl<T> Qux for NewType<(T₁, T₂, …, Tₙ)>'
+#[doc(fake_variadic)]
+impl<T> Qux for NewType<(T,)> {}
+
+//@ has foo/trait.Qux.html
+//@ has - '//section[@id="impl-Qux-for-NewType%3CNewType%3C(T,)%3E%3E"]/h3' 'impl<T> Qux for NewType<NewType<(T₁, T₂, …, Tₙ)>>'
+#[doc(fake_variadic)]
+impl<T> Qux for NewType<NewType<(T,)>> {}
+
+//@ has foo/trait.Qux.html
+//@ has - '//section[@id="impl-Qux-for-NewType%3Cfn(T)+-%3E+Out%3E"]/h3' 'impl<T, Out> Qux for NewType<fn(T₁, T₂, …, Tₙ) -> Out>'
+#[doc(fake_variadic)]
+impl<T, Out> Qux for NewType<fn(T) -> Out> {}
diff --git a/tests/rustdoc/source-version-separator.rs b/tests/rustdoc/source-version-separator.rs
index 9709bbe..78b9d36 100644
--- a/tests/rustdoc/source-version-separator.rs
+++ b/tests/rustdoc/source-version-separator.rs
@@ -3,23 +3,23 @@
 #![feature(staged_api)]
 
 //@ has foo/trait.Bar.html
-//@ has - '//div[@class="main-heading"]/*[@class="sub-heading"]' '1.0.0 · source'
+//@ has - '//div[@class="main-heading"]/*[@class="sub-heading"]' '1.0.0 · Source'
 #[stable(feature = "bar", since = "1.0")]
 pub trait Bar {
-    //@ has - '//*[@id="tymethod.foo"]/*[@class="rightside"]' '3.0.0 · source'
+    //@ has - '//*[@id="tymethod.foo"]/*[@class="rightside"]' '3.0.0 · Source'
     #[stable(feature = "foobar", since = "3.0")]
     fn foo();
 }
 
-//@ has - '//div[@id="implementors-list"]//*[@class="rightside"]' '4.0.0 · source'
+//@ has - '//div[@id="implementors-list"]//*[@class="rightside"]' '4.0.0 · Source'
 
 //@ has foo/struct.Foo.html
-//@ has - '//div[@class="main-heading"]/*[@class="sub-heading"]' '1.0.0 · source'
+//@ has - '//div[@class="main-heading"]/*[@class="sub-heading"]' '1.0.0 · Source'
 #[stable(feature = "baz", since = "1.0")]
 pub struct Foo;
 
 impl Foo {
-    //@ has - '//*[@id="method.foofoo"]/*[@class="rightside"]' '3.0.0 · source'
+    //@ has - '//*[@id="method.foofoo"]/*[@class="rightside"]' '3.0.0 · Source'
     #[stable(feature = "foobar", since = "3.0")]
     pub fn foofoo() {}
 }
diff --git a/tests/rustdoc/src-link-external-macro-26606.rs b/tests/rustdoc/src-link-external-macro-26606.rs
index b5662be..0ce829f 100644
--- a/tests/rustdoc/src-link-external-macro-26606.rs
+++ b/tests/rustdoc/src-link-external-macro-26606.rs
@@ -10,5 +10,5 @@
 extern crate issue_26606_macro;
 
 //@ has issue_26606/constant.FOO.html
-//@ has - '//a[@href="../src/issue_26606/src-link-external-macro-26606.rs.html#14"]' 'source'
+//@ has - '//a[@href="../src/issue_26606/src-link-external-macro-26606.rs.html#14"]' 'Source'
 make_item!(FOO);
diff --git a/tests/rustdoc/src-links-auto-impls.rs b/tests/rustdoc/src-links-auto-impls.rs
index dd07f85..5a777f5 100644
--- a/tests/rustdoc/src-links-auto-impls.rs
+++ b/tests/rustdoc/src-links-auto-impls.rs
@@ -2,11 +2,11 @@
 
 //@ has foo/struct.Unsized.html
 //@ has - '//*[@id="impl-Sized-for-Unsized"]/h3[@class="code-header"]' 'impl !Sized for Unsized'
-//@ !has - '//*[@id="impl-Sized-for-Unsized"]//a[@class="src"]' 'source'
+//@ !has - '//*[@id="impl-Sized-for-Unsized"]//a[@class="src"]' 'Source'
 //@ has - '//*[@id="impl-Sync-for-Unsized"]/h3[@class="code-header"]' 'impl Sync for Unsized'
-//@ !has - '//*[@id="impl-Sync-for-Unsized"]//a[@class="src"]' 'source'
+//@ !has - '//*[@id="impl-Sync-for-Unsized"]//a[@class="src"]' 'Source'
 //@ has - '//*[@id="impl-Any-for-T"]/h3[@class="code-header"]' 'impl<T> Any for T'
-//@ has - '//*[@id="impl-Any-for-T"]//a[@class="src rightside"]' 'source'
+//@ has - '//*[@id="impl-Any-for-T"]//a[@class="src rightside"]' 'Source'
 pub struct Unsized {
     data: [u8],
 }
diff --git a/tests/rustdoc/thread-local-src.rs b/tests/rustdoc/thread-local-src.rs
index b23a9a4..16509e8 100644
--- a/tests/rustdoc/thread-local-src.rs
+++ b/tests/rustdoc/thread-local-src.rs
@@ -1,6 +1,6 @@
 #![crate_name = "foo"]
 
-//@ has foo/index.html '//a[@href="../src/foo/thread-local-src.rs.html#1-6"]' 'source'
+//@ has foo/index.html '//a[@href="../src/foo/thread-local-src.rs.html#1-6"]' 'Source'
 
-//@ has foo/constant.FOO.html '//a[@href="../src/foo/thread-local-src.rs.html#6"]' 'source'
+//@ has foo/constant.FOO.html '//a[@href="../src/foo/thread-local-src.rs.html#6"]' 'Source'
 thread_local!(pub static FOO: bool = false);
diff --git a/tests/rustdoc/trait-src-link.rs b/tests/rustdoc/trait-src-link.rs
index 7c3afb7..7bf883d 100644
--- a/tests/rustdoc/trait-src-link.rs
+++ b/tests/rustdoc/trait-src-link.rs
@@ -1,26 +1,26 @@
 #![crate_name = "quix"]
 pub trait Foo {
-    //@ has quix/trait.Foo.html '//a[@href="../src/quix/trait-src-link.rs.html#4"]' 'source'
+    //@ has quix/trait.Foo.html '//a[@href="../src/quix/trait-src-link.rs.html#4"]' 'Source'
     fn required();
 
-    //@ has quix/trait.Foo.html '//a[@href="../src/quix/trait-src-link.rs.html#7"]' 'source'
+    //@ has quix/trait.Foo.html '//a[@href="../src/quix/trait-src-link.rs.html#7"]' 'Source'
     fn provided() {}
 }
 
 pub struct Bar;
 
 impl Foo for Bar {
-    //@ has quix/struct.Bar.html '//a[@href="../src/quix/trait-src-link.rs.html#14"]' 'source'
+    //@ has quix/struct.Bar.html '//a[@href="../src/quix/trait-src-link.rs.html#14"]' 'Source'
     fn required() {}
-    //@ has quix/struct.Bar.html '//a[@href="../src/quix/trait-src-link.rs.html#7"]' 'source'
+    //@ has quix/struct.Bar.html '//a[@href="../src/quix/trait-src-link.rs.html#7"]' 'Source'
 }
 
 pub struct Baz;
 
 impl Foo for Baz {
-    //@ has quix/struct.Baz.html '//a[@href="../src/quix/trait-src-link.rs.html#22"]' 'source'
+    //@ has quix/struct.Baz.html '//a[@href="../src/quix/trait-src-link.rs.html#22"]' 'Source'
     fn required() {}
 
-    //@ has quix/struct.Baz.html '//a[@href="../src/quix/trait-src-link.rs.html#25"]' 'source'
+    //@ has quix/struct.Baz.html '//a[@href="../src/quix/trait-src-link.rs.html#25"]' 'Source'
     fn provided() {}
 }
diff --git a/tests/ui-fulldeps/internal-lints/lint_pass_impl_without_macro.rs b/tests/ui-fulldeps/internal-lints/lint_pass_impl_without_macro.rs
index c3df917..6eb698c 100644
--- a/tests/ui-fulldeps/internal-lints/lint_pass_impl_without_macro.rs
+++ b/tests/ui-fulldeps/internal-lints/lint_pass_impl_without_macro.rs
@@ -6,7 +6,7 @@
 extern crate rustc_middle;
 extern crate rustc_session;
 
-use rustc_session::lint::{LintPass, LintVec};
+use rustc_session::lint::{LintPass, LintVec, Lint};
 use rustc_session::{declare_lint, declare_lint_pass, impl_lint_pass};
 
 declare_lint! {
@@ -21,6 +21,10 @@
     fn name(&self) -> &'static str {
         "Foo"
     }
+
+    fn get_lints(&self) -> Vec<&'static Lint> {
+        vec![TEST_LINT]
+    }
 }
 
 macro_rules! custom_lint_pass_macro {
@@ -31,6 +35,10 @@
             fn name(&self) -> &'static str {
                 "Custom"
             }
+
+            fn get_lints(&self) -> Vec<&'static Lint> {
+                vec![TEST_LINT]
+            }
         }
     };
 }
diff --git a/tests/ui-fulldeps/internal-lints/lint_pass_impl_without_macro.stderr b/tests/ui-fulldeps/internal-lints/lint_pass_impl_without_macro.stderr
index ad6e933..824eb35 100644
--- a/tests/ui-fulldeps/internal-lints/lint_pass_impl_without_macro.stderr
+++ b/tests/ui-fulldeps/internal-lints/lint_pass_impl_without_macro.stderr
@@ -12,7 +12,7 @@
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: implementing `LintPass` by hand
-  --> $DIR/lint_pass_impl_without_macro.rs:30:14
+  --> $DIR/lint_pass_impl_without_macro.rs:34:14
    |
 LL |         impl LintPass for Custom {
    |              ^^^^^^^^
diff --git a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr
index ff7af38..03fca17 100644
--- a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr
+++ b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr
@@ -1,10 +1,10 @@
-error: unsupported type attribute for diagnostic derive enum
+error: derive(Diagnostic): unsupported type attribute for diagnostic derive enum
   --> $DIR/diagnostic-derive.rs:47:1
    |
 LL | #[diag(no_crate_example, code = E0123)]
    | ^
 
-error: diagnostic slug not specified
+error: derive(Diagnostic): diagnostic slug not specified
   --> $DIR/diagnostic-derive.rs:50:5
    |
 LL |     Foo,
@@ -12,7 +12,7 @@
    |
    = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
 
-error: diagnostic slug not specified
+error: derive(Diagnostic): diagnostic slug not specified
   --> $DIR/diagnostic-derive.rs:52:5
    |
 LL |     Bar,
@@ -20,13 +20,13 @@
    |
    = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
 
-error: `#[nonsense(...)]` is not a valid attribute
+error: derive(Diagnostic): `#[nonsense(...)]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:63:1
    |
 LL | #[nonsense(no_crate_example, code = E0123)]
    | ^
 
-error: diagnostic slug not specified
+error: derive(Diagnostic): diagnostic slug not specified
   --> $DIR/diagnostic-derive.rs:63:1
    |
 LL | #[nonsense(no_crate_example, code = E0123)]
@@ -34,7 +34,7 @@
    |
    = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
 
-error: diagnostic slug not specified
+error: derive(Diagnostic): diagnostic slug not specified
   --> $DIR/diagnostic-derive.rs:70:1
    |
 LL | #[diag(code = E0123)]
@@ -42,13 +42,13 @@
    |
    = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
 
-error: diagnostic slug must be the first argument
+error: derive(Diagnostic): diagnostic slug must be the first argument
   --> $DIR/diagnostic-derive.rs:80:16
    |
 LL | #[diag(nonsense("foo"), code = E0123, slug = "foo")]
    |                ^
 
-error: diagnostic slug not specified
+error: derive(Diagnostic): diagnostic slug not specified
   --> $DIR/diagnostic-derive.rs:80:1
    |
 LL | #[diag(nonsense("foo"), code = E0123, slug = "foo")]
@@ -56,7 +56,7 @@
    |
    = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
 
-error: unknown argument
+error: derive(Diagnostic): unknown argument
   --> $DIR/diagnostic-derive.rs:86:8
    |
 LL | #[diag(nonsense = "...", code = E0123, slug = "foo")]
@@ -64,7 +64,7 @@
    |
    = note: only the `code` parameter is valid after the slug
 
-error: diagnostic slug not specified
+error: derive(Diagnostic): diagnostic slug not specified
   --> $DIR/diagnostic-derive.rs:86:1
    |
 LL | #[diag(nonsense = "...", code = E0123, slug = "foo")]
@@ -72,7 +72,7 @@
    |
    = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
 
-error: unknown argument
+error: derive(Diagnostic): unknown argument
   --> $DIR/diagnostic-derive.rs:92:8
    |
 LL | #[diag(nonsense = 4, code = E0123, slug = "foo")]
@@ -80,7 +80,7 @@
    |
    = note: only the `code` parameter is valid after the slug
 
-error: diagnostic slug not specified
+error: derive(Diagnostic): diagnostic slug not specified
   --> $DIR/diagnostic-derive.rs:92:1
    |
 LL | #[diag(nonsense = 4, code = E0123, slug = "foo")]
@@ -88,7 +88,7 @@
    |
    = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
 
-error: unknown argument
+error: derive(Diagnostic): unknown argument
   --> $DIR/diagnostic-derive.rs:98:40
    |
 LL | #[diag(no_crate_example, code = E0123, slug = "foo")]
@@ -96,13 +96,13 @@
    |
    = note: only the `code` parameter is valid after the slug
 
-error: `#[suggestion = ...]` is not a valid attribute
+error: derive(Diagnostic): `#[suggestion = ...]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:105:5
    |
 LL |     #[suggestion = "bar"]
    |     ^
 
-error: specified multiple times
+error: derive(Diagnostic): attribute specified multiple times
   --> $DIR/diagnostic-derive.rs:112:8
    |
 LL | #[diag(no_crate_example, code = E0456)]
@@ -114,7 +114,7 @@
 LL | #[diag(no_crate_example, code = E0123)]
    |        ^^^^^^^^^^^^^^^^
 
-error: specified multiple times
+error: derive(Diagnostic): attribute specified multiple times
   --> $DIR/diagnostic-derive.rs:112:26
    |
 LL | #[diag(no_crate_example, code = E0456)]
@@ -126,7 +126,7 @@
 LL | #[diag(no_crate_example, code = E0123)]
    |                          ^^^^
 
-error: specified multiple times
+error: derive(Diagnostic): attribute specified multiple times
   --> $DIR/diagnostic-derive.rs:118:40
    |
 LL | #[diag(no_crate_example, code = E0123, code = E0456)]
@@ -138,13 +138,13 @@
 LL | #[diag(no_crate_example, code = E0123, code = E0456)]
    |                          ^^^^
 
-error: diagnostic slug must be the first argument
+error: derive(Diagnostic): diagnostic slug must be the first argument
   --> $DIR/diagnostic-derive.rs:123:43
    |
 LL | #[diag(no_crate_example, no_crate::example, code = E0123)]
    |                                           ^
 
-error: diagnostic slug not specified
+error: derive(Diagnostic): diagnostic slug not specified
   --> $DIR/diagnostic-derive.rs:128:1
    |
 LL | struct KindNotProvided {}
@@ -152,7 +152,7 @@
    |
    = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
 
-error: diagnostic slug not specified
+error: derive(Diagnostic): diagnostic slug not specified
   --> $DIR/diagnostic-derive.rs:131:1
    |
 LL | #[diag(code = E0123)]
@@ -160,25 +160,25 @@
    |
    = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
 
-error: the `#[primary_span]` attribute can only be applied to fields of type `Span` or `MultiSpan`
+error: derive(Diagnostic): the `#[primary_span]` attribute can only be applied to fields of type `Span` or `MultiSpan`
   --> $DIR/diagnostic-derive.rs:142:5
    |
 LL |     #[primary_span]
    |     ^
 
-error: `#[nonsense]` is not a valid attribute
+error: derive(Diagnostic): `#[nonsense]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:150:5
    |
 LL |     #[nonsense]
    |     ^
 
-error: the `#[label(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan`
+error: derive(Diagnostic): the `#[label(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan`
   --> $DIR/diagnostic-derive.rs:167:5
    |
 LL |     #[label(no_crate_label)]
    |     ^
 
-error: `name` doesn't refer to a field on this type
+error: derive(Diagnostic): `name` doesn't refer to a field on this type
   --> $DIR/diagnostic-derive.rs:175:46
    |
 LL |     #[suggestion(no_crate_suggestion, code = "{name}")]
@@ -202,19 +202,19 @@
    = note: if you intended to print `}`, you can escape it using `}}`
    = note: this error originates in the derive macro `Diagnostic` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: the `#[label(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan`
+error: derive(Diagnostic): the `#[label(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan`
   --> $DIR/diagnostic-derive.rs:210:5
    |
 LL |     #[label(no_crate_label)]
    |     ^
 
-error: suggestion without `code = "..."`
+error: derive(Diagnostic): suggestion without `code = "..."`
   --> $DIR/diagnostic-derive.rs:229:5
    |
 LL |     #[suggestion(no_crate_suggestion)]
    |     ^
 
-error: invalid nested attribute
+error: derive(Diagnostic): invalid nested attribute
   --> $DIR/diagnostic-derive.rs:237:18
    |
 LL |     #[suggestion(nonsense = "bar")]
@@ -222,13 +222,13 @@
    |
    = help: only `no_span`, `style`, `code` and `applicability` are valid nested attributes
 
-error: suggestion without `code = "..."`
+error: derive(Diagnostic): suggestion without `code = "..."`
   --> $DIR/diagnostic-derive.rs:237:5
    |
 LL |     #[suggestion(nonsense = "bar")]
    |     ^
 
-error: invalid nested attribute
+error: derive(Diagnostic): invalid nested attribute
   --> $DIR/diagnostic-derive.rs:246:18
    |
 LL |     #[suggestion(msg = "bar")]
@@ -236,13 +236,13 @@
    |
    = help: only `no_span`, `style`, `code` and `applicability` are valid nested attributes
 
-error: suggestion without `code = "..."`
+error: derive(Diagnostic): suggestion without `code = "..."`
   --> $DIR/diagnostic-derive.rs:246:5
    |
 LL |     #[suggestion(msg = "bar")]
    |     ^
 
-error: wrong field type for suggestion
+error: derive(Diagnostic): wrong field type for suggestion
   --> $DIR/diagnostic-derive.rs:269:5
    |
 LL |     #[suggestion(no_crate_suggestion, code = "This is suggested code")]
@@ -250,7 +250,7 @@
    |
    = help: `#[suggestion(...)]` should be applied to fields of type `Span` or `(Span, Applicability)`
 
-error: specified multiple times
+error: derive(Diagnostic): attribute specified multiple times
   --> $DIR/diagnostic-derive.rs:285:24
    |
 LL |     suggestion: (Span, Span, Applicability),
@@ -262,7 +262,7 @@
 LL |     suggestion: (Span, Span, Applicability),
    |                  ^^^^
 
-error: specified multiple times
+error: derive(Diagnostic): attribute specified multiple times
   --> $DIR/diagnostic-derive.rs:293:33
    |
 LL |     suggestion: (Applicability, Applicability, Span),
@@ -274,13 +274,13 @@
 LL |     suggestion: (Applicability, Applicability, Span),
    |                  ^^^^^^^^^^^^^
 
-error: `#[label = ...]` is not a valid attribute
+error: derive(Diagnostic): `#[label = ...]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:300:5
    |
 LL |     #[label = "bar"]
    |     ^
 
-error: specified multiple times
+error: derive(Diagnostic): attribute specified multiple times
   --> $DIR/diagnostic-derive.rs:451:5
    |
 LL |     #[suggestion(no_crate_suggestion, code = "...", applicability = "maybe-incorrect")]
@@ -292,37 +292,37 @@
 LL |     suggestion: (Span, Applicability),
    |                        ^^^^^^^^^^^^^
 
-error: invalid applicability
+error: derive(Diagnostic): invalid applicability
   --> $DIR/diagnostic-derive.rs:459:69
    |
 LL |     #[suggestion(no_crate_suggestion, code = "...", applicability = "batman")]
    |                                                                     ^^^^^^^^
 
-error: the `#[help(...)]` attribute can only be applied to fields of type `Span`, `MultiSpan`, `bool` or `()`
+error: derive(Diagnostic): the `#[help(...)]` attribute can only be applied to fields of type `Span`, `MultiSpan`, `bool` or `()`
   --> $DIR/diagnostic-derive.rs:526:5
    |
 LL |     #[help(no_crate_help)]
    |     ^
 
-error: a diagnostic slug must be the first argument to the attribute
+error: derive(Diagnostic): a diagnostic slug must be the first argument to the attribute
   --> $DIR/diagnostic-derive.rs:535:32
    |
 LL |     #[label(no_crate_label, foo)]
    |                                ^
 
-error: only `no_span` is a valid nested attribute
+error: derive(Diagnostic): only `no_span` is a valid nested attribute
   --> $DIR/diagnostic-derive.rs:543:29
    |
 LL |     #[label(no_crate_label, foo = "...")]
    |                             ^^^
 
-error: only `no_span` is a valid nested attribute
+error: derive(Diagnostic): only `no_span` is a valid nested attribute
   --> $DIR/diagnostic-derive.rs:551:29
    |
 LL |     #[label(no_crate_label, foo("..."))]
    |                             ^^^
 
-error: `#[primary_span]` is not a valid attribute
+error: derive(Diagnostic): `#[primary_span]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:563:5
    |
 LL |     #[primary_span]
@@ -330,13 +330,13 @@
    |
    = help: the `primary_span` field attribute is not valid for lint diagnostics
 
-error: `#[error(...)]` is not a valid attribute
+error: derive(Diagnostic): `#[error(...)]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:583:1
    |
 LL | #[error(no_crate_example, code = E0123)]
    | ^
 
-error: diagnostic slug not specified
+error: derive(Diagnostic): diagnostic slug not specified
   --> $DIR/diagnostic-derive.rs:583:1
    |
 LL | #[error(no_crate_example, code = E0123)]
@@ -344,13 +344,13 @@
    |
    = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
 
-error: `#[warn_(...)]` is not a valid attribute
+error: derive(Diagnostic): `#[warn_(...)]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:590:1
    |
 LL | #[warn_(no_crate_example, code = E0123)]
    | ^
 
-error: diagnostic slug not specified
+error: derive(Diagnostic): diagnostic slug not specified
   --> $DIR/diagnostic-derive.rs:590:1
    |
 LL | #[warn_(no_crate_example, code = E0123)]
@@ -358,13 +358,13 @@
    |
    = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
 
-error: `#[lint(...)]` is not a valid attribute
+error: derive(Diagnostic): `#[lint(...)]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:597:1
    |
 LL | #[lint(no_crate_example, code = E0123)]
    | ^
 
-error: diagnostic slug not specified
+error: derive(Diagnostic): diagnostic slug not specified
   --> $DIR/diagnostic-derive.rs:597:1
    |
 LL | #[lint(no_crate_example, code = E0123)]
@@ -372,13 +372,13 @@
    |
    = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
 
-error: `#[lint(...)]` is not a valid attribute
+error: derive(Diagnostic): `#[lint(...)]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:604:1
    |
 LL | #[lint(no_crate_example, code = E0123)]
    | ^
 
-error: diagnostic slug not specified
+error: derive(Diagnostic): diagnostic slug not specified
   --> $DIR/diagnostic-derive.rs:604:1
    |
 LL | #[lint(no_crate_example, code = E0123)]
@@ -386,7 +386,7 @@
    |
    = help: specify the slug as the first argument to the attribute, such as `#[diag(compiletest_example)]`
 
-error: specified multiple times
+error: derive(Diagnostic): attribute specified multiple times
   --> $DIR/diagnostic-derive.rs:613:53
    |
 LL |     #[suggestion(no_crate_suggestion, code = "...", code = ",,,")]
@@ -398,7 +398,7 @@
 LL |     #[suggestion(no_crate_suggestion, code = "...", code = ",,,")]
    |                                       ^^^^
 
-error: wrong types for suggestion
+error: derive(Diagnostic): wrong types for suggestion
   --> $DIR/diagnostic-derive.rs:622:24
    |
 LL |     suggestion: (Span, usize),
@@ -406,7 +406,7 @@
    |
    = help: `#[suggestion(...)]` on a tuple field must be applied to fields of type `(Span, Applicability)`
 
-error: wrong types for suggestion
+error: derive(Diagnostic): wrong types for suggestion
   --> $DIR/diagnostic-derive.rs:630:17
    |
 LL |     suggestion: (Span,),
@@ -414,13 +414,13 @@
    |
    = help: `#[suggestion(...)]` on a tuple field must be applied to fields of type `(Span, Applicability)`
 
-error: suggestion without `code = "..."`
+error: derive(Diagnostic): suggestion without `code = "..."`
   --> $DIR/diagnostic-derive.rs:637:5
    |
 LL |     #[suggestion(no_crate_suggestion)]
    |     ^
 
-error: `#[multipart_suggestion(...)]` is not a valid attribute
+error: derive(Diagnostic): `#[multipart_suggestion(...)]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:644:1
    |
 LL | #[multipart_suggestion(no_crate_suggestion)]
@@ -428,7 +428,7 @@
    |
    = help: consider creating a `Subdiagnostic` instead
 
-error: `#[multipart_suggestion(...)]` is not a valid attribute
+error: derive(Diagnostic): `#[multipart_suggestion(...)]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:647:1
    |
 LL | #[multipart_suggestion()]
@@ -436,7 +436,7 @@
    |
    = help: consider creating a `Subdiagnostic` instead
 
-error: `#[multipart_suggestion(...)]` is not a valid attribute
+error: derive(Diagnostic): `#[multipart_suggestion(...)]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:651:5
    |
 LL |     #[multipart_suggestion(no_crate_suggestion)]
@@ -444,7 +444,7 @@
    |
    = help: consider creating a `Subdiagnostic` instead
 
-error: `#[suggestion(...)]` is not a valid attribute
+error: derive(Diagnostic): `#[suggestion(...)]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:659:1
    |
 LL | #[suggestion(no_crate_suggestion, code = "...")]
@@ -452,7 +452,7 @@
    |
    = help: `#[label]` and `#[suggestion]` can only be applied to fields
 
-error: `#[label]` is not a valid attribute
+error: derive(Diagnostic): `#[label]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:668:1
    |
 LL | #[label]
@@ -460,61 +460,61 @@
    |
    = help: `#[label]` and `#[suggestion]` can only be applied to fields
 
-error: `#[subdiagnostic(...)]` is not a valid attribute
+error: derive(Diagnostic): `#[subdiagnostic(...)]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:702:5
    |
 LL |     #[subdiagnostic(bad)]
    |     ^
 
-error: `#[subdiagnostic = ...]` is not a valid attribute
+error: derive(Diagnostic): `#[subdiagnostic = ...]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:710:5
    |
 LL |     #[subdiagnostic = "bad"]
    |     ^
 
-error: `#[subdiagnostic(...)]` is not a valid attribute
+error: derive(Diagnostic): `#[subdiagnostic(...)]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:718:5
    |
 LL |     #[subdiagnostic(bad, bad)]
    |     ^
 
-error: `#[subdiagnostic(...)]` is not a valid attribute
+error: derive(Diagnostic): `#[subdiagnostic(...)]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:726:5
    |
 LL |     #[subdiagnostic("bad")]
    |     ^
 
-error: `#[subdiagnostic(...)]` is not a valid attribute
+error: derive(Diagnostic): `#[subdiagnostic(...)]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:734:5
    |
 LL |     #[subdiagnostic(eager)]
    |     ^
 
-error: `#[subdiagnostic(...)]` is not a valid attribute
+error: derive(Diagnostic): `#[subdiagnostic(...)]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:742:5
    |
 LL |     #[subdiagnostic(eager)]
    |     ^
 
-error: `#[subdiagnostic(...)]` is not a valid attribute
+error: derive(Diagnostic): `#[subdiagnostic(...)]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:763:5
    |
 LL |     #[subdiagnostic(eager)]
    |     ^
 
-error: expected at least one string literal for `code(...)`
+error: derive(Diagnostic): expected at least one string literal for `code(...)`
   --> $DIR/diagnostic-derive.rs:794:23
    |
 LL |     #[suggestion(code())]
    |                       ^
 
-error: `code(...)` must contain only string literals
+error: derive(Diagnostic): `code(...)` must contain only string literals
   --> $DIR/diagnostic-derive.rs:802:23
    |
 LL |     #[suggestion(code(foo))]
    |                       ^^^
 
-error: `#[suggestion(...)]` is not a valid attribute
+error: derive(Diagnostic): `#[suggestion(...)]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:826:5
    |
 LL |     #[suggestion(no_crate_suggestion, code = "")]
diff --git a/tests/ui-fulldeps/session-diagnostic/enforce_slug_naming.stderr b/tests/ui-fulldeps/session-diagnostic/enforce_slug_naming.stderr
index df1bad3..4f54239 100644
--- a/tests/ui-fulldeps/session-diagnostic/enforce_slug_naming.stderr
+++ b/tests/ui-fulldeps/session-diagnostic/enforce_slug_naming.stderr
@@ -1,4 +1,4 @@
-error: diagnostic slug and crate name do not match
+error: derive(Diagnostic): diagnostic slug and crate name do not match
   --> $DIR/enforce_slug_naming.rs:22:8
    |
 LL | #[diag(compiletest_example, code = E0123)]
diff --git a/tests/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr b/tests/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr
index 96f6ef0..0ae7ba4 100644
--- a/tests/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr
+++ b/tests/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr
@@ -1,142 +1,142 @@
-error: label without `#[primary_span]` field
+error: derive(Diagnostic): label without `#[primary_span]` field
   --> $DIR/subdiagnostic-derive.rs:51:1
    |
 LL | #[label(no_crate_example)]
    | ^
 
-error: diagnostic slug must be first argument of a `#[label(...)]` attribute
+error: derive(Diagnostic): diagnostic slug must be first argument of a `#[label(...)]` attribute
   --> $DIR/subdiagnostic-derive.rs:58:1
    |
 LL | #[label]
    | ^
 
-error: `#[foo]` is not a valid attribute
+error: derive(Diagnostic): `#[foo]` is not a valid attribute
   --> $DIR/subdiagnostic-derive.rs:67:1
    |
 LL | #[foo]
    | ^
 
-error: `#[label = ...]` is not a valid attribute
+error: derive(Diagnostic): `#[label = ...]` is not a valid attribute
   --> $DIR/subdiagnostic-derive.rs:77:1
    |
 LL | #[label = "..."]
    | ^
 
-error: only `no_span` is a valid nested attribute
+error: derive(Diagnostic): only `no_span` is a valid nested attribute
   --> $DIR/subdiagnostic-derive.rs:86:9
    |
 LL | #[label(bug = "...")]
    |         ^^^
 
-error: diagnostic slug must be first argument of a `#[label(...)]` attribute
+error: derive(Diagnostic): diagnostic slug must be first argument of a `#[label(...)]` attribute
   --> $DIR/subdiagnostic-derive.rs:86:1
    |
 LL | #[label(bug = "...")]
    | ^
 
-error: only `no_span` is a valid nested attribute
+error: derive(Diagnostic): only `no_span` is a valid nested attribute
   --> $DIR/subdiagnostic-derive.rs:106:9
    |
 LL | #[label(slug = 4)]
    |         ^^^^
 
-error: diagnostic slug must be first argument of a `#[label(...)]` attribute
+error: derive(Diagnostic): diagnostic slug must be first argument of a `#[label(...)]` attribute
   --> $DIR/subdiagnostic-derive.rs:106:1
    |
 LL | #[label(slug = 4)]
    | ^
 
-error: only `no_span` is a valid nested attribute
+error: derive(Diagnostic): only `no_span` is a valid nested attribute
   --> $DIR/subdiagnostic-derive.rs:116:9
    |
 LL | #[label(slug("..."))]
    |         ^^^^
 
-error: diagnostic slug must be first argument of a `#[label(...)]` attribute
+error: derive(Diagnostic): diagnostic slug must be first argument of a `#[label(...)]` attribute
   --> $DIR/subdiagnostic-derive.rs:116:1
    |
 LL | #[label(slug("..."))]
    | ^
 
-error: diagnostic slug must be first argument of a `#[label(...)]` attribute
+error: derive(Diagnostic): diagnostic slug must be first argument of a `#[label(...)]` attribute
   --> $DIR/subdiagnostic-derive.rs:136:1
    |
 LL | #[label()]
    | ^
 
-error: only `no_span` is a valid nested attribute
+error: derive(Diagnostic): only `no_span` is a valid nested attribute
   --> $DIR/subdiagnostic-derive.rs:145:27
    |
 LL | #[label(no_crate_example, code = "...")]
    |                           ^^^^
 
-error: only `no_span` is a valid nested attribute
+error: derive(Diagnostic): only `no_span` is a valid nested attribute
   --> $DIR/subdiagnostic-derive.rs:154:27
    |
 LL | #[label(no_crate_example, applicability = "machine-applicable")]
    |                           ^^^^^^^^^^^^^
 
-error: unsupported type attribute for subdiagnostic enum
+error: derive(Diagnostic): unsupported type attribute for subdiagnostic enum
   --> $DIR/subdiagnostic-derive.rs:163:1
    |
 LL | #[foo]
    | ^
 
-error: `#[bar]` is not a valid attribute
+error: derive(Diagnostic): `#[bar]` is not a valid attribute
   --> $DIR/subdiagnostic-derive.rs:177:5
    |
 LL |     #[bar]
    |     ^
 
-error: `#[bar = ...]` is not a valid attribute
+error: derive(Diagnostic): `#[bar = ...]` is not a valid attribute
   --> $DIR/subdiagnostic-derive.rs:189:5
    |
 LL |     #[bar = "..."]
    |     ^
 
-error: `#[bar = ...]` is not a valid attribute
+error: derive(Diagnostic): `#[bar = ...]` is not a valid attribute
   --> $DIR/subdiagnostic-derive.rs:201:5
    |
 LL |     #[bar = 4]
    |     ^
 
-error: `#[bar(...)]` is not a valid attribute
+error: derive(Diagnostic): `#[bar(...)]` is not a valid attribute
   --> $DIR/subdiagnostic-derive.rs:213:5
    |
 LL |     #[bar("...")]
    |     ^
 
-error: only `no_span` is a valid nested attribute
+error: derive(Diagnostic): only `no_span` is a valid nested attribute
   --> $DIR/subdiagnostic-derive.rs:225:13
    |
 LL |     #[label(code = "...")]
    |             ^^^^
 
-error: diagnostic slug must be first argument of a `#[label(...)]` attribute
+error: derive(Diagnostic): diagnostic slug must be first argument of a `#[label(...)]` attribute
   --> $DIR/subdiagnostic-derive.rs:225:5
    |
 LL |     #[label(code = "...")]
    |     ^
 
-error: the `#[primary_span]` attribute can only be applied to fields of type `Span` or `MultiSpan`
+error: derive(Diagnostic): the `#[primary_span]` attribute can only be applied to fields of type `Span` or `MultiSpan`
   --> $DIR/subdiagnostic-derive.rs:254:5
    |
 LL |     #[primary_span]
    |     ^
 
-error: label without `#[primary_span]` field
+error: derive(Diagnostic): label without `#[primary_span]` field
   --> $DIR/subdiagnostic-derive.rs:251:1
    |
 LL | #[label(no_crate_example)]
    | ^
 
-error: `#[applicability]` is only valid on suggestions
+error: derive(Diagnostic): `#[applicability]` is only valid on suggestions
   --> $DIR/subdiagnostic-derive.rs:264:5
    |
 LL |     #[applicability]
    |     ^
 
-error: `#[bar]` is not a valid attribute
+error: derive(Diagnostic): `#[bar]` is not a valid attribute
   --> $DIR/subdiagnostic-derive.rs:274:5
    |
 LL |     #[bar]
@@ -144,13 +144,13 @@
    |
    = help: only `primary_span`, `applicability` and `skip_arg` are valid field attributes
 
-error: `#[bar = ...]` is not a valid attribute
+error: derive(Diagnostic): `#[bar = ...]` is not a valid attribute
   --> $DIR/subdiagnostic-derive.rs:285:5
    |
 LL |     #[bar = "..."]
    |     ^
 
-error: `#[bar(...)]` is not a valid attribute
+error: derive(Diagnostic): `#[bar(...)]` is not a valid attribute
   --> $DIR/subdiagnostic-derive.rs:296:5
    |
 LL |     #[bar("...")]
@@ -158,13 +158,13 @@
    |
    = help: only `primary_span`, `applicability` and `skip_arg` are valid field attributes
 
-error: a diagnostic slug must be the first argument to the attribute
+error: derive(Diagnostic): a diagnostic slug must be the first argument to the attribute
   --> $DIR/subdiagnostic-derive.rs:328:44
    |
 LL | #[label(no_crate_example, no_crate::example)]
    |                                            ^
 
-error: specified multiple times
+error: derive(Diagnostic): attribute specified multiple times
   --> $DIR/subdiagnostic-derive.rs:341:5
    |
 LL |     #[primary_span]
@@ -176,13 +176,13 @@
 LL |     #[primary_span]
    |     ^
 
-error: subdiagnostic kind not specified
+error: derive(Diagnostic): subdiagnostic kind not specified
   --> $DIR/subdiagnostic-derive.rs:347:8
    |
 LL | struct AG {
    |        ^^
 
-error: specified multiple times
+error: derive(Diagnostic): attribute specified multiple times
   --> $DIR/subdiagnostic-derive.rs:384:46
    |
 LL | #[suggestion(no_crate_example, code = "...", code = "...")]
@@ -194,7 +194,7 @@
 LL | #[suggestion(no_crate_example, code = "...", code = "...")]
    |                                ^^^^
 
-error: specified multiple times
+error: derive(Diagnostic): attribute specified multiple times
   --> $DIR/subdiagnostic-derive.rs:402:5
    |
 LL |     #[applicability]
@@ -206,49 +206,49 @@
 LL |     #[applicability]
    |     ^
 
-error: the `#[applicability]` attribute can only be applied to fields of type `Applicability`
+error: derive(Diagnostic): the `#[applicability]` attribute can only be applied to fields of type `Applicability`
   --> $DIR/subdiagnostic-derive.rs:412:5
    |
 LL |     #[applicability]
    |     ^
 
-error: suggestion without `code = "..."`
+error: derive(Diagnostic): suggestion without `code = "..."`
   --> $DIR/subdiagnostic-derive.rs:425:1
    |
 LL | #[suggestion(no_crate_example)]
    | ^
 
-error: invalid applicability
+error: derive(Diagnostic): invalid applicability
   --> $DIR/subdiagnostic-derive.rs:435:62
    |
 LL | #[suggestion(no_crate_example, code = "...", applicability = "foo")]
    |                                                              ^^^^^
 
-error: suggestion without `#[primary_span]` field
+error: derive(Diagnostic): suggestion without `#[primary_span]` field
   --> $DIR/subdiagnostic-derive.rs:453:1
    |
 LL | #[suggestion(no_crate_example, code = "...")]
    | ^
 
-error: unsupported type attribute for subdiagnostic enum
+error: derive(Diagnostic): unsupported type attribute for subdiagnostic enum
   --> $DIR/subdiagnostic-derive.rs:467:1
    |
 LL | #[label]
    | ^
 
-error: `var` doesn't refer to a field on this type
+error: derive(Diagnostic): `var` doesn't refer to a field on this type
   --> $DIR/subdiagnostic-derive.rs:487:39
    |
 LL | #[suggestion(no_crate_example, code = "{var}", applicability = "machine-applicable")]
    |                                       ^^^^^^^
 
-error: `var` doesn't refer to a field on this type
+error: derive(Diagnostic): `var` doesn't refer to a field on this type
   --> $DIR/subdiagnostic-derive.rs:506:43
    |
 LL |     #[suggestion(no_crate_example, code = "{var}", applicability = "machine-applicable")]
    |                                           ^^^^^^^
 
-error: `#[suggestion_part]` is not a valid attribute
+error: derive(Diagnostic): `#[suggestion_part]` is not a valid attribute
   --> $DIR/subdiagnostic-derive.rs:529:5
    |
 LL |     #[suggestion_part]
@@ -256,7 +256,7 @@
    |
    = help: `#[suggestion_part(...)]` is only valid in multipart suggestions, use `#[primary_span]` instead
 
-error: `#[suggestion_part(...)]` is not a valid attribute
+error: derive(Diagnostic): `#[suggestion_part(...)]` is not a valid attribute
   --> $DIR/subdiagnostic-derive.rs:532:5
    |
 LL |     #[suggestion_part(code = "...")]
@@ -264,13 +264,13 @@
    |
    = help: `#[suggestion_part(...)]` is only valid in multipart suggestions
 
-error: suggestion without `#[primary_span]` field
+error: derive(Diagnostic): suggestion without `#[primary_span]` field
   --> $DIR/subdiagnostic-derive.rs:526:1
    |
 LL | #[suggestion(no_crate_example, code = "...")]
    | ^
 
-error: invalid nested attribute
+error: derive(Diagnostic): invalid nested attribute
   --> $DIR/subdiagnostic-derive.rs:541:42
    |
 LL | #[multipart_suggestion(no_crate_example, code = "...", applicability = "machine-applicable")]
@@ -278,25 +278,25 @@
    |
    = help: only `no_span`, `style` and `applicability` are valid nested attributes
 
-error: multipart suggestion without any `#[suggestion_part(...)]` fields
+error: derive(Diagnostic): multipart suggestion without any `#[suggestion_part(...)]` fields
   --> $DIR/subdiagnostic-derive.rs:541:1
    |
 LL | #[multipart_suggestion(no_crate_example, code = "...", applicability = "machine-applicable")]
    | ^
 
-error: `#[suggestion_part(...)]` attribute without `code = "..."`
+error: derive(Diagnostic): `#[suggestion_part(...)]` attribute without `code = "..."`
   --> $DIR/subdiagnostic-derive.rs:551:5
    |
 LL |     #[suggestion_part]
    |     ^
 
-error: `#[suggestion_part(...)]` attribute without `code = "..."`
+error: derive(Diagnostic): `#[suggestion_part(...)]` attribute without `code = "..."`
   --> $DIR/subdiagnostic-derive.rs:559:5
    |
 LL |     #[suggestion_part()]
    |     ^
 
-error: `#[primary_span]` is not a valid attribute
+error: derive(Diagnostic): `#[primary_span]` is not a valid attribute
   --> $DIR/subdiagnostic-derive.rs:568:5
    |
 LL |     #[primary_span]
@@ -304,43 +304,43 @@
    |
    = help: multipart suggestions use one or more `#[suggestion_part]`s rather than one `#[primary_span]`
 
-error: multipart suggestion without any `#[suggestion_part(...)]` fields
+error: derive(Diagnostic): multipart suggestion without any `#[suggestion_part(...)]` fields
   --> $DIR/subdiagnostic-derive.rs:565:1
    |
 LL | #[multipart_suggestion(no_crate_example)]
    | ^
 
-error: `#[suggestion_part(...)]` attribute without `code = "..."`
+error: derive(Diagnostic): `#[suggestion_part(...)]` attribute without `code = "..."`
   --> $DIR/subdiagnostic-derive.rs:576:5
    |
 LL |     #[suggestion_part]
    |     ^
 
-error: `#[suggestion_part(...)]` attribute without `code = "..."`
+error: derive(Diagnostic): `#[suggestion_part(...)]` attribute without `code = "..."`
   --> $DIR/subdiagnostic-derive.rs:579:5
    |
 LL |     #[suggestion_part()]
    |     ^
 
-error: `code` is the only valid nested attribute
+error: derive(Diagnostic): `code` is the only valid nested attribute
   --> $DIR/subdiagnostic-derive.rs:582:23
    |
 LL |     #[suggestion_part(foo = "bar")]
    |                       ^^^
 
-error: the `#[suggestion_part(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan`
+error: derive(Diagnostic): the `#[suggestion_part(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan`
   --> $DIR/subdiagnostic-derive.rs:587:5
    |
 LL |     #[suggestion_part(code = "...")]
    |     ^
 
-error: the `#[suggestion_part(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan`
+error: derive(Diagnostic): the `#[suggestion_part(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan`
   --> $DIR/subdiagnostic-derive.rs:590:5
    |
 LL |     #[suggestion_part()]
    |     ^
 
-error: specified multiple times
+error: derive(Diagnostic): attribute specified multiple times
   --> $DIR/subdiagnostic-derive.rs:598:37
    |
 LL |     #[suggestion_part(code = "...", code = ",,,")]
@@ -352,37 +352,37 @@
 LL |     #[suggestion_part(code = "...", code = ",,,")]
    |                       ^^^^
 
-error: `#[applicability]` has no effect if all `#[suggestion]`/`#[multipart_suggestion]` attributes have a static `applicability = "..."`
+error: derive(Diagnostic): `#[applicability]` has no effect if all `#[suggestion]`/`#[multipart_suggestion]` attributes have a static `applicability = "..."`
   --> $DIR/subdiagnostic-derive.rs:627:5
    |
 LL |     #[applicability]
    |     ^
 
-error: expected exactly one string literal for `code = ...`
+error: derive(Diagnostic): expected exactly one string literal for `code = ...`
   --> $DIR/subdiagnostic-derive.rs:675:34
    |
 LL |     #[suggestion_part(code("foo"))]
    |                                  ^
 
-error: expected exactly one string literal for `code = ...`
+error: derive(Diagnostic): expected exactly one string literal for `code = ...`
   --> $DIR/subdiagnostic-derive.rs:686:41
    |
 LL |     #[suggestion_part(code("foo", "bar"))]
    |                                         ^
 
-error: expected exactly one string literal for `code = ...`
+error: derive(Diagnostic): expected exactly one string literal for `code = ...`
   --> $DIR/subdiagnostic-derive.rs:697:30
    |
 LL |     #[suggestion_part(code(3))]
    |                              ^
 
-error: expected exactly one string literal for `code = ...`
+error: derive(Diagnostic): expected exactly one string literal for `code = ...`
   --> $DIR/subdiagnostic-derive.rs:708:29
    |
 LL |     #[suggestion_part(code())]
    |                             ^
 
-error: specified multiple times
+error: derive(Diagnostic): attribute specified multiple times
   --> $DIR/subdiagnostic-derive.rs:763:1
    |
 LL | #[suggestion(no_crate_example, code = "", style = "hidden", style = "normal")]
@@ -394,7 +394,7 @@
 LL | #[suggestion(no_crate_example, code = "", style = "hidden", style = "normal")]
    | ^
 
-error: `#[suggestion_hidden(...)]` is not a valid attribute
+error: derive(Diagnostic): `#[suggestion_hidden(...)]` is not a valid attribute
   --> $DIR/subdiagnostic-derive.rs:772:1
    |
 LL | #[suggestion_hidden(no_crate_example, code = "")]
@@ -402,7 +402,7 @@
    |
    = help: Use `#[suggestion(..., style = "hidden")]` instead
 
-error: `#[suggestion_hidden(...)]` is not a valid attribute
+error: derive(Diagnostic): `#[suggestion_hidden(...)]` is not a valid attribute
   --> $DIR/subdiagnostic-derive.rs:780:1
    |
 LL | #[suggestion_hidden(no_crate_example, code = "", style = "normal")]
@@ -410,7 +410,7 @@
    |
    = help: Use `#[suggestion(..., style = "hidden")]` instead
 
-error: invalid suggestion style
+error: derive(Diagnostic): invalid suggestion style
   --> $DIR/subdiagnostic-derive.rs:788:51
    |
 LL | #[suggestion(no_crate_example, code = "", style = "foo")]
@@ -418,25 +418,25 @@
    |
    = help: valid styles are `normal`, `short`, `hidden`, `verbose` and `tool-only`
 
-error: expected `= "xxx"`
+error: derive(Diagnostic): expected `= "xxx"`
   --> $DIR/subdiagnostic-derive.rs:796:49
    |
 LL | #[suggestion(no_crate_example, code = "", style = 42)]
    |                                                 ^
 
-error: a diagnostic slug must be the first argument to the attribute
+error: derive(Diagnostic): a diagnostic slug must be the first argument to the attribute
   --> $DIR/subdiagnostic-derive.rs:804:48
    |
 LL | #[suggestion(no_crate_example, code = "", style)]
    |                                                ^
 
-error: expected `= "xxx"`
+error: derive(Diagnostic): expected `= "xxx"`
   --> $DIR/subdiagnostic-derive.rs:812:48
    |
 LL | #[suggestion(no_crate_example, code = "", style("foo"))]
    |                                                ^
 
-error: `#[primary_span]` is not a valid attribute
+error: derive(Diagnostic): `#[primary_span]` is not a valid attribute
   --> $DIR/subdiagnostic-derive.rs:825:5
    |
 LL |     #[primary_span]
@@ -445,7 +445,7 @@
    = note: there must be exactly one primary span
    = help: to create a suggestion with multiple spans, use `#[multipart_suggestion]` instead
 
-error: suggestion without `#[primary_span]` field
+error: derive(Diagnostic): suggestion without `#[primary_span]` field
   --> $DIR/subdiagnostic-derive.rs:822:1
    |
 LL | #[suggestion(no_crate_example, code = "")]
diff --git a/tests/ui-fulldeps/try-from-u32/errors.rs b/tests/ui-fulldeps/try-from-u32/errors.rs
new file mode 100644
index 0000000..0470063
--- /dev/null
+++ b/tests/ui-fulldeps/try-from-u32/errors.rs
@@ -0,0 +1,24 @@
+#![feature(rustc_private)]
+//@ edition: 2021
+
+// Checks the error messages produced by `#[derive(TryFromU32)]`.
+
+extern crate rustc_macros;
+
+use rustc_macros::TryFromU32;
+
+#[derive(TryFromU32)]
+struct MyStruct {} //~ type is not an enum
+
+#[derive(TryFromU32)]
+enum NonTrivial {
+    A,
+    B(),
+    C {},
+    D(bool),                //~ enum variant cannot have fields
+    E(bool, bool),          //~ enum variant cannot have fields
+    F { x: bool },          //~ enum variant cannot have fields
+    G { x: bool, y: bool }, //~ enum variant cannot have fields
+}
+
+fn main() {}
diff --git a/tests/ui-fulldeps/try-from-u32/errors.stderr b/tests/ui-fulldeps/try-from-u32/errors.stderr
new file mode 100644
index 0000000..d205670
--- /dev/null
+++ b/tests/ui-fulldeps/try-from-u32/errors.stderr
@@ -0,0 +1,32 @@
+error: type is not an enum (TryFromU32)
+  --> $DIR/errors.rs:11:1
+   |
+LL | struct MyStruct {}
+   | ^^^^^^
+
+error: enum variant cannot have fields (TryFromU32)
+  --> $DIR/errors.rs:18:7
+   |
+LL |     D(bool),
+   |       ^^^^
+
+error: enum variant cannot have fields (TryFromU32)
+  --> $DIR/errors.rs:19:7
+   |
+LL |     E(bool, bool),
+   |       ^^^^
+
+error: enum variant cannot have fields (TryFromU32)
+  --> $DIR/errors.rs:20:9
+   |
+LL |     F { x: bool },
+   |         ^
+
+error: enum variant cannot have fields (TryFromU32)
+  --> $DIR/errors.rs:21:9
+   |
+LL |     G { x: bool, y: bool },
+   |         ^
+
+error: aborting due to 5 previous errors
+
diff --git a/tests/ui-fulldeps/try-from-u32/hygiene.rs b/tests/ui-fulldeps/try-from-u32/hygiene.rs
new file mode 100644
index 0000000..e0655a6
--- /dev/null
+++ b/tests/ui-fulldeps/try-from-u32/hygiene.rs
@@ -0,0 +1,32 @@
+#![feature(rustc_private)]
+//@ edition: 2021
+//@ check-pass
+
+// Checks that the derive macro still works even if the surrounding code has
+// shadowed the relevant library types.
+
+extern crate rustc_macros;
+
+mod submod {
+    use rustc_macros::TryFromU32;
+
+    struct Result;
+    trait TryFrom {}
+    #[allow(non_camel_case_types)]
+    struct u32;
+    struct Ok;
+    struct Err;
+    mod core {}
+    mod std {}
+
+    #[derive(TryFromU32)]
+    pub(crate) enum MyEnum {
+        Zero,
+        One,
+    }
+}
+
+fn main() {
+    use submod::MyEnum;
+    let _: Result<MyEnum, u32> = MyEnum::try_from(1u32);
+}
diff --git a/tests/ui-fulldeps/try-from-u32/values.rs b/tests/ui-fulldeps/try-from-u32/values.rs
new file mode 100644
index 0000000..180a8f2
--- /dev/null
+++ b/tests/ui-fulldeps/try-from-u32/values.rs
@@ -0,0 +1,36 @@
+#![feature(assert_matches)]
+#![feature(rustc_private)]
+//@ edition: 2021
+//@ run-pass
+
+// Checks the values accepted by the `TryFrom<u32>` impl produced by `#[derive(TryFromU32)]`.
+
+extern crate rustc_macros;
+
+use core::assert_matches::assert_matches;
+use rustc_macros::TryFromU32;
+
+#[derive(TryFromU32, Debug, PartialEq)]
+#[repr(u32)]
+enum Repr {
+    Zero,
+    One(),
+    Seven = 7,
+}
+
+#[derive(TryFromU32, Debug)]
+enum NoRepr {
+    Zero,
+    One,
+}
+
+fn main() {
+    assert_eq!(Repr::try_from(0u32), Ok(Repr::Zero));
+    assert_eq!(Repr::try_from(1u32), Ok(Repr::One()));
+    assert_eq!(Repr::try_from(2u32), Err(2));
+    assert_eq!(Repr::try_from(7u32), Ok(Repr::Seven));
+
+    assert_matches!(NoRepr::try_from(0u32), Ok(NoRepr::Zero));
+    assert_matches!(NoRepr::try_from(1u32), Ok(NoRepr::One));
+    assert_matches!(NoRepr::try_from(2u32), Err(2));
+}
diff --git a/tests/ui/abi/compatibility.rs b/tests/ui/abi/compatibility.rs
index 28c8063..408dbea 100644
--- a/tests/ui/abi/compatibility.rs
+++ b/tests/ui/abi/compatibility.rs
@@ -79,10 +79,10 @@
     #[lang = "sized"]
     pub trait Sized {}
 
-    #[lang = "receiver"]
-    pub trait Receiver {}
-    impl<T: ?Sized> Receiver for &T {}
-    impl<T: ?Sized> Receiver for &mut T {}
+    #[lang = "legacy_receiver"]
+    pub trait LegacyReceiver {}
+    impl<T: ?Sized> LegacyReceiver for &T {}
+    impl<T: ?Sized> LegacyReceiver for &mut T {}
 
     #[lang = "copy"]
     pub trait Copy: Sized {}
@@ -211,6 +211,15 @@
     }
 }
 
+enum Either<T, U> {
+    Left(T),
+    Right(U),
+}
+enum Either2<T, U> {
+    Left(T),
+    Right(U, ()),
+}
+
 #[repr(C)]
 enum ReprCEnum<T> {
     Variant1,
@@ -328,7 +337,8 @@
     test_transparent_unsized!(dyn_trait, dyn Any);
 }
 
-// RFC 3391 <https://rust-lang.github.io/rfcs/3391-result_ffi_guarantees.html>.
+// RFC 3391 <https://rust-lang.github.io/rfcs/3391-result_ffi_guarantees.html>, including the
+// extension ratified at <https://github.com/rust-lang/rust/pull/130628#issuecomment-2402761599>.
 macro_rules! test_nonnull {
     ($name:ident, $t:ty) => {
         mod $name {
@@ -340,6 +350,12 @@
             test_abi_compatible!(result_ok_zst, Result<Zst, $t>, $t);
             test_abi_compatible!(result_err_arr, Result<$t, [i8; 0]>, $t);
             test_abi_compatible!(result_ok_arr, Result<[i8; 0], $t>, $t);
+            test_abi_compatible!(result_err_void, Result<$t, Void>, $t);
+            test_abi_compatible!(result_ok_void, Result<Void, $t>, $t);
+            test_abi_compatible!(either_err_zst, Either<$t, Zst>, $t);
+            test_abi_compatible!(either_ok_zst, Either<Zst, $t>, $t);
+            test_abi_compatible!(either2_err_zst, Either2<$t, Zst>, $t);
+            test_abi_compatible!(either2_err_arr, Either2<$t, [i8; 0]>, $t);
         }
     }
 }
diff --git a/tests/ui/async-await/field-in-sync.rs b/tests/ui/async-await/field-in-sync.rs
new file mode 100644
index 0000000..586980c
--- /dev/null
+++ b/tests/ui/async-await/field-in-sync.rs
@@ -0,0 +1,13 @@
+//@ edition: 2021
+
+struct S {
+    field: (),
+}
+
+async fn foo() -> S { todo!() }
+
+fn main() -> Result<(), ()> {
+    foo().field;
+    //~^ ERROR no field `field` on type `impl Future<Output = S>`
+    Ok(())
+}
diff --git a/tests/ui/async-await/field-in-sync.stderr b/tests/ui/async-await/field-in-sync.stderr
new file mode 100644
index 0000000..7be3033
--- /dev/null
+++ b/tests/ui/async-await/field-in-sync.stderr
@@ -0,0 +1,17 @@
+error[E0609]: no field `field` on type `impl Future<Output = S>`
+  --> $DIR/field-in-sync.rs:10:11
+   |
+LL |     foo().field;
+   |           ^^^^^ field not available in `impl Future`, but it is available in its `Output`
+   |
+note: this implements `Future` and its output type has the field, but the future cannot be awaited in a synchronous function
+  --> $DIR/field-in-sync.rs:10:5
+   |
+LL | fn main() -> Result<(), ()> {
+   | --------------------------- this is not `async`
+LL |     foo().field;
+   |     ^^^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0609`.
diff --git a/tests/ui/async-await/in-trait/unconstrained-impl-region.rs b/tests/ui/async-await/in-trait/unconstrained-impl-region.rs
index 95ba1f3..9382c23 100644
--- a/tests/ui/async-await/in-trait/unconstrained-impl-region.rs
+++ b/tests/ui/async-await/in-trait/unconstrained-impl-region.rs
@@ -14,7 +14,6 @@
 //~^ ERROR the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates
     type Message = &'a ();
     async fn on_mount(self, _: impl Inbox<&'a ()>) {}
-    //~^ ERROR the trait bound `impl Inbox<&'a ()>: Inbox<&'a ()>` is not satisfied
 }
 
 fn main() {}
diff --git a/tests/ui/async-await/in-trait/unconstrained-impl-region.stderr b/tests/ui/async-await/in-trait/unconstrained-impl-region.stderr
index 80dc5fd..ef7e4ef 100644
--- a/tests/ui/async-await/in-trait/unconstrained-impl-region.stderr
+++ b/tests/ui/async-await/in-trait/unconstrained-impl-region.stderr
@@ -1,22 +1,9 @@
-error[E0277]: the trait bound `impl Inbox<&'a ()>: Inbox<&'a ()>` is not satisfied
-  --> $DIR/unconstrained-impl-region.rs:16:5
-   |
-LL |     async fn on_mount(self, _: impl Inbox<&'a ()>) {}
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Inbox<&'a ()>` is not implemented for `impl Inbox<&'a ()>`
-   |
-note: required by a bound in `<() as Actor>::on_mount`
-  --> $DIR/unconstrained-impl-region.rs:16:37
-   |
-LL |     async fn on_mount(self, _: impl Inbox<&'a ()>) {}
-   |                                     ^^^^^^^^^^^^^ required by this bound in `<() as Actor>::on_mount`
-
 error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates
   --> $DIR/unconstrained-impl-region.rs:13:6
    |
 LL | impl<'a> Actor for () {
    |      ^^ unconstrained lifetime parameter
 
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
 
-Some errors have detailed explanations: E0207, E0277.
-For more information about an error, try `rustc --explain E0207`.
+For more information about this error, try `rustc --explain E0207`.
diff --git a/tests/ui/async-await/issue-61076.stderr b/tests/ui/async-await/issue-61076.stderr
index 44de282..b8478c8 100644
--- a/tests/ui/async-await/issue-61076.stderr
+++ b/tests/ui/async-await/issue-61076.stderr
@@ -28,7 +28,7 @@
 LL |     let _: i32 = tuple().0;
    |                          ^ field not available in `impl Future`, but it is available in its `Output`
    |
-help: consider `await`ing on the `Future` and access the field of its `Output`
+help: consider `await`ing on the `Future` to access the field
    |
 LL |     let _: i32 = tuple().await.0;
    |                         ++++++
@@ -39,7 +39,7 @@
 LL |     let _: i32 = struct_().a;
    |                            ^ field not available in `impl Future`, but it is available in its `Output`
    |
-help: consider `await`ing on the `Future` and access the field of its `Output`
+help: consider `await`ing on the `Future` to access the field
    |
 LL |     let _: i32 = struct_().await.a;
    |                           ++++++
diff --git a/tests/ui/async-await/try-in-sync.rs b/tests/ui/async-await/try-in-sync.rs
new file mode 100644
index 0000000..81d72c3
--- /dev/null
+++ b/tests/ui/async-await/try-in-sync.rs
@@ -0,0 +1,9 @@
+//@ edition: 2021
+
+async fn foo() -> Result<(), ()> { todo!() }
+
+fn main() -> Result<(), ()> {
+    foo()?;
+    //~^ ERROR the `?` operator can only be applied to values that implement `Try`
+    Ok(())
+}
diff --git a/tests/ui/async-await/try-in-sync.stderr b/tests/ui/async-await/try-in-sync.stderr
new file mode 100644
index 0000000..bc7a6bd
--- /dev/null
+++ b/tests/ui/async-await/try-in-sync.stderr
@@ -0,0 +1,18 @@
+error[E0277]: the `?` operator can only be applied to values that implement `Try`
+  --> $DIR/try-in-sync.rs:6:5
+   |
+LL |     foo()?;
+   |     ^^^^^^ the `?` operator cannot be applied to type `impl Future<Output = Result<(), ()>>`
+   |
+   = help: the trait `Try` is not implemented for `impl Future<Output = Result<(), ()>>`
+note: this implements `Future` and its output type supports `?`, but the future cannot be awaited in a synchronous function
+  --> $DIR/try-in-sync.rs:6:10
+   |
+LL | fn main() -> Result<(), ()> {
+   | --------------------------- this is not `async`
+LL |     foo()?;
+   |          ^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/borrowck/issue-64453.rs b/tests/ui/borrowck/issue-64453.rs
index 33d55be..5f1f35d 100644
--- a/tests/ui/borrowck/issue-64453.rs
+++ b/tests/ui/borrowck/issue-64453.rs
@@ -3,7 +3,6 @@
 
 static settings_dir: String = format!("");
 //~^ ERROR cannot call non-const fn
-//~| ERROR is not yet stable as a const
 
 fn from_string(_: String) -> Value {
     Value
diff --git a/tests/ui/borrowck/issue-64453.stderr b/tests/ui/borrowck/issue-64453.stderr
index e671817..98b05ea 100644
--- a/tests/ui/borrowck/issue-64453.stderr
+++ b/tests/ui/borrowck/issue-64453.stderr
@@ -1,12 +1,3 @@
-error: `Arguments::<'a>::new_const` is not yet stable as a const fn
-  --> $DIR/issue-64453.rs:4:31
-   |
-LL | static settings_dir: String = format!("");
-   |                               ^^^^^^^^^^^
-   |
-   = help: add `#![feature(const_fmt_arguments_new)]` to the crate attributes to enable
-   = note: this error originates in the macro `$crate::__export::format_args` which comes from the expansion of the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
-
 error[E0015]: cannot call non-const fn `format` in statics
   --> $DIR/issue-64453.rs:4:31
    |
@@ -18,7 +9,7 @@
    = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0507]: cannot move out of static item `settings_dir`
-  --> $DIR/issue-64453.rs:14:37
+  --> $DIR/issue-64453.rs:13:37
    |
 LL |     let settings_data = from_string(settings_dir);
    |                                     ^^^^^^^^^^^^ move occurs because `settings_dir` has type `String`, which does not implement the `Copy` trait
@@ -28,7 +19,7 @@
 LL |     let settings_data = from_string(settings_dir.clone());
    |                                                 ++++++++
 
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
 Some errors have detailed explanations: E0015, E0507.
 For more information about an error, try `rustc --explain E0015`.
diff --git a/tests/ui/cast/ptr-to-trait-obj-drop-principal.rs b/tests/ui/cast/ptr-to-trait-obj-drop-principal.rs
new file mode 100644
index 0000000..01dd91f
--- /dev/null
+++ b/tests/ui/cast/ptr-to-trait-obj-drop-principal.rs
@@ -0,0 +1,21 @@
+//! Test that non-coercion casts aren't allowed to drop the principal,
+//! because they cannot modify the pointer metadata.
+//!
+//! We test this in a const context to guard against UB if this is allowed
+//! in the future.
+
+trait Trait {}
+impl Trait for () {}
+
+struct Wrapper<T: ?Sized>(T);
+
+const OBJECT: *const (dyn Trait + Send) = &();
+
+// coercions are allowed
+const _: *const dyn Send = OBJECT as _;
+
+// casts are **not** allowed
+const _: *const Wrapper<dyn Send> = OBJECT as _;
+//~^ ERROR casting `*const (dyn Trait + Send + 'static)` as `*const Wrapper<dyn Send>` is invalid
+
+fn main() {}
diff --git a/tests/ui/cast/ptr-to-trait-obj-drop-principal.stderr b/tests/ui/cast/ptr-to-trait-obj-drop-principal.stderr
new file mode 100644
index 0000000..719e071
--- /dev/null
+++ b/tests/ui/cast/ptr-to-trait-obj-drop-principal.stderr
@@ -0,0 +1,11 @@
+error[E0606]: casting `*const (dyn Trait + Send + 'static)` as `*const Wrapper<dyn Send>` is invalid
+  --> $DIR/ptr-to-trait-obj-drop-principal.rs:18:37
+   |
+LL | const _: *const Wrapper<dyn Send> = OBJECT as _;
+   |                                     ^^^^^^^^^^^
+   |
+   = note: the trait objects may have different vtables
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0606`.
diff --git a/tests/ui/check-cfg/mix.stderr b/tests/ui/check-cfg/mix.stderr
index c21016e..7589551 100644
--- a/tests/ui/check-cfg/mix.stderr
+++ b/tests/ui/check-cfg/mix.stderr
@@ -251,7 +251,7 @@
 LL |     cfg!(target_feature = "zebra");
    |          ^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `amx-bf16`, `amx-complex`, `amx-fp16`, `amx-int8`, `amx-tile`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, and `avx512vpopcntdq` and 245 more
+   = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `amx-bf16`, `amx-complex`, `amx-fp16`, `amx-int8`, `amx-tile`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, and `avx512vpopcntdq` and 246 more
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
 warning: 27 warnings emitted
diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr
index da790bb..b0ca09a 100644
--- a/tests/ui/check-cfg/well-known-values.stderr
+++ b/tests/ui/check-cfg/well-known-values.stderr
@@ -174,7 +174,7 @@
 LL |     target_feature = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `amx-bf16`, `amx-complex`, `amx-fp16`, `amx-int8`, `amx-tile`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, `avx512vpopcntdq`, `avxifma`, `avxneconvert`, `avxvnni`, `avxvnniint16`, `avxvnniint8`, `backchain`, `bf16`, `bmi1`, `bmi2`, `bti`, `bulk-memory`, `c`, `cache`, `cmpxchg16b`, `crc`, `crt-static`, `cssc`, `d`, `d32`, `dit`, `doloop`, `dotprod`, `dpb`, `dpb2`, `dsp`, `dsp1e2`, `dspe60`, `e`, `e1`, `e2`, `ecv`, `edsp`, `elrw`, `ermsb`, `exception-handling`, `extended-const`, `f`, `f16c`, `f32mm`, `f64mm`, `faminmax`, `fcma`, `fdivdu`, `fhm`, `flagm`, `flagm2`, `float1e2`, `float1e3`, `float3e4`, `float7e60`, `floate1`, `fma`, `fp-armv8`, `fp16`, `fp64`, `fp8`, `fp8dot2`, `fp8dot4`, `fp8fma`, `fpuv2_df`, `fpuv2_sf`, `fpuv3_df`, `fpuv3_hf`, `fpuv3_hi`, `fpuv3_sf`, `frecipe`, `frintts`, `fxsr`, `gfni`, `hard-float`, `hard-float-abi`, `hard-tp`, `hbc`, `high-registers`, `hvx`, `hvx-length128b`, `hwdiv`, `i8mm`, `jsconv`, `lahfsahf`, `lasx`, `lbt`, `lor`, `lse`, `lse128`, `lse2`, `lsx`, `lut`, `lvz`, `lzcnt`, `m`, `mclass`, `mops`, `movbe`, `mp`, `mp1e2`, `msa`, `mte`, `multivalue`, `mutable-globals`, `neon`, `nontrapping-fptoint`, `nvic`, `paca`, `pacg`, `pan`, `partword-atomics`, `pclmulqdq`, `pmuv3`, `popcnt`, `power10-vector`, `power8-altivec`, `power8-vector`, `power9-altivec`, `power9-vector`, `prfchw`, `quadword-atomics`, `rand`, `ras`, `rclass`, `rcpc`, `rcpc2`, `rcpc3`, `rdm`, `rdrand`, `rdseed`, `reference-types`, `relax`, `relaxed-simd`, `rtm`, `sb`, `sha`, `sha2`, `sha3`, `sha512`, `sign-ext`, `simd128`, `sm3`, `sm4`, `sme`, `sme-b16b16`, `sme-f16f16`, `sme-f64f64`, `sme-f8f16`, `sme-f8f32`, `sme-fa64`, `sme-i16i64`, `sme-lutv2`, `sme2`, `sme2p1`, `spe`, `ssbs`, `sse`, `sse2`, `sse3`, `sse4.1`, `sse4.2`, `sse4a`, `ssse3`, `ssve-fp8dot2`, `ssve-fp8dot4`, `ssve-fp8fma`, `sve`, `sve-b16b16`, `sve2`, `sve2-aes`, `sve2-bitperm`, `sve2-sha3`, `sve2-sm4`, `sve2p1`, `tbm`, `thumb-mode`, `thumb2`, `tme`, `trust`, `trustzone`, `ual`, `unaligned-scalar-mem`, `v`, `v5te`, `v6`, `v6k`, `v6t2`, `v7`, `v8`, `v8.1a`, `v8.2a`, `v8.3a`, `v8.4a`, `v8.5a`, `v8.6a`, `v8.7a`, `v8.8a`, `v8.9a`, `v9.1a`, `v9.2a`, `v9.3a`, `v9.4a`, `v9.5a`, `v9a`, `vaes`, `vdsp2e60f`, `vdspv1`, `vdspv2`, `vector`, `vfp2`, `vfp3`, `vfp4`, `vh`, `virt`, `virtualization`, `vpclmulqdq`, `vsx`, `wfxt`, `xop`, `xsave`, `xsavec`, `xsaveopt`, `xsaves`, `zaamo`, `zabha`, `zalrsc`, `zba`, `zbb`, `zbc`, `zbkb`, `zbkc`, `zbkx`, `zbs`, `zdinx`, `zfh`, `zfhmin`, `zfinx`, `zhinx`, `zhinxmin`, `zk`, `zkn`, `zknd`, `zkne`, `zknh`, `zkr`, `zks`, `zksed`, `zksh`, and `zkt`
+   = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `amx-bf16`, `amx-complex`, `amx-fp16`, `amx-int8`, `amx-tile`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, `avx512vpopcntdq`, `avxifma`, `avxneconvert`, `avxvnni`, `avxvnniint16`, `avxvnniint8`, `backchain`, `bf16`, `bmi1`, `bmi2`, `bti`, `bulk-memory`, `c`, `cache`, `cmpxchg16b`, `crc`, `crt-static`, `cssc`, `d`, `d32`, `dit`, `doloop`, `dotprod`, `dpb`, `dpb2`, `dsp`, `dsp1e2`, `dspe60`, `e`, `e1`, `e2`, `ecv`, `edsp`, `elrw`, `ermsb`, `exception-handling`, `extended-const`, `f`, `f16c`, `f32mm`, `f64mm`, `faminmax`, `fcma`, `fdivdu`, `fhm`, `flagm`, `flagm2`, `float1e2`, `float1e3`, `float3e4`, `float7e60`, `floate1`, `fma`, `fp-armv8`, `fp16`, `fp64`, `fp8`, `fp8dot2`, `fp8dot4`, `fp8fma`, `fpuv2_df`, `fpuv2_sf`, `fpuv3_df`, `fpuv3_hf`, `fpuv3_hi`, `fpuv3_sf`, `frecipe`, `frintts`, `fxsr`, `gfni`, `hard-float`, `hard-float-abi`, `hard-tp`, `hbc`, `high-registers`, `hvx`, `hvx-length128b`, `hwdiv`, `i8mm`, `jsconv`, `lahfsahf`, `lasx`, `lbt`, `lor`, `lse`, `lse128`, `lse2`, `lsx`, `lut`, `lvz`, `lzcnt`, `m`, `mclass`, `mops`, `movbe`, `mp`, `mp1e2`, `msa`, `mte`, `multivalue`, `mutable-globals`, `neon`, `nontrapping-fptoint`, `nvic`, `paca`, `pacg`, `pan`, `partword-atomics`, `pauth-lr`, `pclmulqdq`, `pmuv3`, `popcnt`, `power10-vector`, `power8-altivec`, `power8-vector`, `power9-altivec`, `power9-vector`, `prfchw`, `quadword-atomics`, `rand`, `ras`, `rclass`, `rcpc`, `rcpc2`, `rcpc3`, `rdm`, `rdrand`, `rdseed`, `reference-types`, `relax`, `relaxed-simd`, `rtm`, `sb`, `sha`, `sha2`, `sha3`, `sha512`, `sign-ext`, `simd128`, `sm3`, `sm4`, `sme`, `sme-b16b16`, `sme-f16f16`, `sme-f64f64`, `sme-f8f16`, `sme-f8f32`, `sme-fa64`, `sme-i16i64`, `sme-lutv2`, `sme2`, `sme2p1`, `spe`, `ssbs`, `sse`, `sse2`, `sse3`, `sse4.1`, `sse4.2`, `sse4a`, `ssse3`, `ssve-fp8dot2`, `ssve-fp8dot4`, `ssve-fp8fma`, `sve`, `sve-b16b16`, `sve2`, `sve2-aes`, `sve2-bitperm`, `sve2-sha3`, `sve2-sm4`, `sve2p1`, `tbm`, `thumb-mode`, `thumb2`, `tme`, `trust`, `trustzone`, `ual`, `unaligned-scalar-mem`, `v`, `v5te`, `v6`, `v6k`, `v6t2`, `v7`, `v8`, `v8.1a`, `v8.2a`, `v8.3a`, `v8.4a`, `v8.5a`, `v8.6a`, `v8.7a`, `v8.8a`, `v8.9a`, `v9.1a`, `v9.2a`, `v9.3a`, `v9.4a`, `v9.5a`, `v9a`, `vaes`, `vdsp2e60f`, `vdspv1`, `vdspv2`, `vector`, `vfp2`, `vfp3`, `vfp4`, `vh`, `virt`, `virtualization`, `vpclmulqdq`, `vsx`, `wfxt`, `xop`, `xsave`, `xsavec`, `xsaveopt`, `xsaves`, `zaamo`, `zabha`, `zalrsc`, `zba`, `zbb`, `zbc`, `zbkb`, `zbkc`, `zbkx`, `zbs`, `zdinx`, `zfh`, `zfhmin`, `zfinx`, `zhinx`, `zhinxmin`, `zk`, `zkn`, `zknd`, `zkne`, `zknh`, `zkr`, `zks`, `zksed`, `zksh`, and `zkt`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
diff --git a/tests/ui/closures/issue-111932.stderr b/tests/ui/closures/issue-111932.stderr
index ff46b10..93488ad 100644
--- a/tests/ui/closures/issue-111932.stderr
+++ b/tests/ui/closures/issue-111932.stderr
@@ -17,7 +17,7 @@
    |                   required by a bound introduced by this call
    |
    = help: the trait `Sized` is not implemented for `dyn Foo`
-note: required by an implicit `Sized` bound in `core::fmt::rt::Argument::<'a>::new_debug`
+note: required by an implicit `Sized` bound in `core::fmt::rt::Argument::<'_>::new_debug`
   --> $SRC_DIR/core/src/fmt/rt.rs:LL:COL
    = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
 
diff --git a/tests/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.stderr b/tests/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.stderr
index bae8249..b8d7c94 100644
--- a/tests/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.stderr
+++ b/tests/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.stderr
@@ -27,11 +27,13 @@
 LL | struct Foo(u8);
    |
 
-error[E0284]: type annotations needed: cannot normalize `foo<N>::{constant#0}`
-  --> $DIR/unify-op-with-fn-call.rs:20:25
+error[E0015]: cannot call non-const operator in constants
+  --> $DIR/unify-op-with-fn-call.rs:20:39
    |
 LL | fn foo<const N: Foo>(a: Evaluatable<{ N + N }>) {
-   |                         ^^^^^^^^^^^^^^^^^^^^^^ cannot normalize `foo<N>::{constant#0}`
+   |                                       ^^^^^
+   |
+   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
 
 error[E0741]: `Foo` must implement `ConstParamTy` to be used as the type of a const generic parameter
   --> $DIR/unify-op-with-fn-call.rs:20:17
@@ -63,11 +65,21 @@
 LL | fn foo2<const N: usize>(a: Evaluatable2<{ N + N }>) {
    |                            ^^^^^^^^^^^^^^^^^^^^^^^ cannot normalize `foo2<N>::{constant#0}`
 
-error[E0284]: type annotations needed: cannot normalize `foo<N>::{constant#0}`
-  --> $DIR/unify-op-with-fn-call.rs:21:11
+error[E0015]: cannot call non-const fn `<Foo as Add>::add` in constants
+  --> $DIR/unify-op-with-fn-call.rs:21:13
    |
 LL |     bar::<{ std::ops::Add::add(N, N) }>();
-   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot normalize `foo<N>::{constant#0}`
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
+
+error[E0015]: cannot call non-const fn `<usize as Add>::add` in constants
+  --> $DIR/unify-op-with-fn-call.rs:30:14
+   |
+LL |     bar2::<{ std::ops::Add::add(N, N) }>();
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
 
 error[E0284]: type annotations needed: cannot normalize `foo2<N>::{constant#0}`
   --> $DIR/unify-op-with-fn-call.rs:30:12
@@ -75,7 +87,7 @@
 LL |     bar2::<{ std::ops::Add::add(N, N) }>();
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot normalize `foo2<N>::{constant#0}`
 
-error: aborting due to 9 previous errors
+error: aborting due to 10 previous errors
 
-Some errors have detailed explanations: E0284, E0741.
-For more information about an error, try `rustc --explain E0284`.
+Some errors have detailed explanations: E0015, E0284, E0741.
+For more information about an error, try `rustc --explain E0015`.
diff --git a/tests/ui/const-generics/infer/issue-77092.stderr b/tests/ui/const-generics/infer/issue-77092.stderr
index 9a6374a..4ab80ce 100644
--- a/tests/ui/const-generics/infer/issue-77092.stderr
+++ b/tests/ui/const-generics/infer/issue-77092.stderr
@@ -25,7 +25,7 @@
    = note: required for `[i32; _]` to implement `Debug`
    = note: 1 redundant requirement hidden
    = note: required for `&mut [i32; _]` to implement `Debug`
-note: required by a bound in `core::fmt::rt::Argument::<'a>::new_debug`
+note: required by a bound in `core::fmt::rt::Argument::<'_>::new_debug`
   --> $SRC_DIR/core/src/fmt/rt.rs:LL:COL
 help: consider specifying the generic arguments
    |
diff --git a/tests/ui/const-generics/issue-93647.stderr b/tests/ui/const-generics/issue-93647.stderr
index 81f50a1..38fb3d7 100644
--- a/tests/ui/const-generics/issue-93647.stderr
+++ b/tests/ui/const-generics/issue-93647.stderr
@@ -6,10 +6,6 @@
    |
    = note: closures need an RFC before allowed to be called in constants
    = note: calls in constants are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/const-generics/issues/issue-88119.stderr b/tests/ui/const-generics/issues/issue-88119.stderr
index 98bb819..a0ca33e 100644
--- a/tests/ui/const-generics/issues/issue-88119.stderr
+++ b/tests/ui/const-generics/issues/issue-88119.stderr
@@ -11,30 +11,12 @@
    |
 LL | impl<T: ?Sized + ConstName> const ConstName for &T
    |                                                 ^^ cannot normalize `<&T as ConstName>::{constant#0}`
-   |
-note: required for `&T` to implement `ConstName`
-  --> $DIR/issue-88119.rs:19:35
-   |
-LL | impl<T: ?Sized + ConstName> const ConstName for &T
-   |                                   ^^^^^^^^^     ^^
-LL | where
-LL |     [(); name_len::<T>()]:,
-   |     --------------------- unsatisfied trait bound introduced here
 
 error[E0284]: type annotations needed: cannot normalize `<&mut T as ConstName>::{constant#0}`
   --> $DIR/issue-88119.rs:26:49
    |
 LL | impl<T: ?Sized + ConstName> const ConstName for &mut T
    |                                                 ^^^^^^ cannot normalize `<&mut T as ConstName>::{constant#0}`
-   |
-note: required for `&mut T` to implement `ConstName`
-  --> $DIR/issue-88119.rs:26:35
-   |
-LL | impl<T: ?Sized + ConstName> const ConstName for &mut T
-   |                                   ^^^^^^^^^     ^^^^^^
-LL | where
-LL |     [(); name_len::<T>()]:,
-   |     --------------------- unsatisfied trait bound introduced here
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/const-generics/issues/issue-90318.stderr b/tests/ui/const-generics/issues/issue-90318.stderr
index a534e8f..9c7cb5c 100644
--- a/tests/ui/const-generics/issues/issue-90318.stderr
+++ b/tests/ui/const-generics/issues/issue-90318.stderr
@@ -29,10 +29,6 @@
 note: impl defined here, but it is not `const`
   --> $SRC_DIR/core/src/any.rs:LL:COL
    = note: calls in constants are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
 
 error[E0015]: cannot call non-const operator in constants
   --> $DIR/issue-90318.rs:22:10
@@ -43,10 +39,6 @@
 note: impl defined here, but it is not `const`
   --> $SRC_DIR/core/src/any.rs:LL:COL
    = note: calls in constants are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/consts/auxiliary/unstable_but_const_stable.rs b/tests/ui/consts/auxiliary/unstable_but_const_stable.rs
deleted file mode 100644
index 88044b0..0000000
--- a/tests/ui/consts/auxiliary/unstable_but_const_stable.rs
+++ /dev/null
@@ -1,13 +0,0 @@
-#![feature(staged_api, rustc_attrs, intrinsics)]
-#![stable(since="1.0.0", feature = "stable")]
-
-extern "rust-intrinsic" {
-    #[unstable(feature = "unstable", issue = "42")]
-    #[rustc_const_stable(feature = "stable", since = "1.0.0")]
-    #[rustc_nounwind]
-    pub fn write_bytes<T>(dst: *mut T, val: u8, count: usize);
-}
-
-#[unstable(feature = "unstable", issue = "42")]
-#[rustc_const_stable(feature = "stable", since = "1.0.0")]
-pub const fn some_unstable_fn() {}
diff --git a/tests/ui/consts/auxiliary/unstable_intrinsic.rs b/tests/ui/consts/auxiliary/unstable_intrinsic.rs
new file mode 100644
index 0000000..edef499
--- /dev/null
+++ b/tests/ui/consts/auxiliary/unstable_intrinsic.rs
@@ -0,0 +1,26 @@
+#![feature(staged_api, rustc_attrs, intrinsics)]
+#![stable(since="1.0.0", feature = "stable")]
+
+#[stable(since="1.0.0", feature = "stable")]
+pub mod old_way {
+    extern "rust-intrinsic" {
+        #[unstable(feature = "unstable", issue = "42")]
+        pub fn size_of_val<T>(x: *const T) -> usize;
+
+        #[unstable(feature = "unstable", issue = "42")]
+        #[rustc_const_unstable(feature = "unstable", issue = "42")]
+        pub fn min_align_of_val<T>(x: *const T) -> usize;
+    }
+}
+
+#[stable(since="1.0.0", feature = "stable")]
+pub mod new_way {
+    #[unstable(feature = "unstable", issue = "42")]
+    #[rustc_intrinsic]
+    pub const unsafe fn size_of_val<T>(x: *const T) -> usize { 42 }
+
+    #[unstable(feature = "unstable", issue = "42")]
+    #[rustc_const_unstable(feature = "unstable", issue = "42")]
+    #[rustc_intrinsic]
+    pub const unsafe fn min_align_of_val<T>(x: *const T) -> usize { 42 }
+}
diff --git a/tests/ui/consts/closure-in-foreign-crate.rs b/tests/ui/consts/closure-in-foreign-crate.rs
index 701cf09..94e40fc 100644
--- a/tests/ui/consts/closure-in-foreign-crate.rs
+++ b/tests/ui/consts/closure-in-foreign-crate.rs
@@ -1,8 +1,8 @@
-//@ aux-build:closure-in-foreign-crate.rs
+// FIXME(effects) aux-build:closure-in-foreign-crate.rs
 //@ build-pass
 
-extern crate closure_in_foreign_crate;
+// FIXME(effects) extern crate closure_in_foreign_crate;
 
-const _: () = closure_in_foreign_crate::test();
+// FIXME(effects) const _: () = closure_in_foreign_crate::test();
 
 fn main() {}
diff --git a/tests/ui/consts/const-block-const-bound.stderr b/tests/ui/consts/const-block-const-bound.stderr
index 42a42ae..5e24959 100644
--- a/tests/ui/consts/const-block-const-bound.stderr
+++ b/tests/ui/consts/const-block-const-bound.stderr
@@ -1,8 +1,16 @@
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-block-const-bound.rs:8:22
+  --> $DIR/const-block-const-bound.rs:8:15
    |
 LL | const fn f<T: ~const Destruct>(x: T) {}
-   |                      ^^^^^^^^
+   |               ^^^^^^
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/const-block-const-bound.rs:8:15
+   |
+LL | const fn f<T: ~const Destruct>(x: T) {}
+   |               ^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0493]: destructor of `T` cannot be evaluated at compile-time
   --> $DIR/const-block-const-bound.rs:8:32
@@ -12,6 +20,6 @@
    |                                |
    |                                the destructor for this type cannot be evaluated in constant functions
 
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0493`.
diff --git a/tests/ui/consts/const-eval/dont_promote_unstable_const_fn.rs b/tests/ui/consts/const-eval/dont_promote_unstable_const_fn.rs
index 4b3cf70..6c93c0e 100644
--- a/tests/ui/consts/const-eval/dont_promote_unstable_const_fn.rs
+++ b/tests/ui/consts/const-eval/dont_promote_unstable_const_fn.rs
@@ -3,7 +3,7 @@
             we're apparently really bad at it",
             issue = "none")]
 
-#![feature(staged_api)]
+#![feature(staged_api, foo)]
 
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_const_unstable(feature="foo", issue = "none")]
@@ -11,7 +11,7 @@
 
 fn meh() -> u32 { 42 }
 
-const fn bar() -> u32 { foo() } //~ ERROR `foo` is not yet stable as a const fn
+const fn bar() -> u32 { foo() } //~ ERROR cannot use `#[feature(foo)]`
 
 fn a() {
     let _: &'static u32 = &foo(); //~ ERROR temporary value dropped while borrowed
diff --git a/tests/ui/consts/const-eval/dont_promote_unstable_const_fn.stderr b/tests/ui/consts/const-eval/dont_promote_unstable_const_fn.stderr
index 2e697b2..1de1c78 100644
--- a/tests/ui/consts/const-eval/dont_promote_unstable_const_fn.stderr
+++ b/tests/ui/consts/const-eval/dont_promote_unstable_const_fn.stderr
@@ -1,10 +1,20 @@
-error: `foo` is not yet stable as a const fn
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo)]`
   --> $DIR/dont_promote_unstable_const_fn.rs:14:25
    |
 LL | const fn bar() -> u32 { foo() }
    |                         ^^^^^
    |
-   = help: add `#![feature(foo)]` to the crate attributes to enable
+   = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features
+help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do)
+   |
+LL + #[rustc_const_unstable(feature = "...", issue = "...")]
+LL | const fn bar() -> u32 { foo() }
+   |
+help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
+   |
+LL + #[rustc_allow_const_fn_unstable(foo)]
+LL | const fn bar() -> u32 { foo() }
+   |
 
 error[E0716]: temporary value dropped while borrowed
   --> $DIR/dont_promote_unstable_const_fn.rs:17:28
diff --git a/tests/ui/consts/const-eval/simd/insert_extract.rs b/tests/ui/consts/const-eval/simd/insert_extract.rs
index f4f2532..57d4b48 100644
--- a/tests/ui/consts/const-eval/simd/insert_extract.rs
+++ b/tests/ui/consts/const-eval/simd/insert_extract.rs
@@ -11,8 +11,11 @@
 #[repr(simd)] struct f32x4([f32; 4]);
 
 extern "rust-intrinsic" {
+    #[stable(feature = "foo", since = "1.3.37")]
     #[rustc_const_stable(feature = "foo", since = "1.3.37")]
     fn simd_insert<T, U>(x: T, idx: u32, val: U) -> T;
+
+    #[stable(feature = "foo", since = "1.3.37")]
     #[rustc_const_stable(feature = "foo", since = "1.3.37")]
     fn simd_extract<T, U>(x: T, idx: u32) -> U;
 }
diff --git a/tests/ui/consts/const-fn-error.stderr b/tests/ui/consts/const-fn-error.stderr
index e886a0b..42a6f27 100644
--- a/tests/ui/consts/const-fn-error.stderr
+++ b/tests/ui/consts/const-fn-error.stderr
@@ -22,10 +22,6 @@
 note: impl defined here, but it is not `const`
   --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
 
 error[E0015]: cannot call non-const fn `<std::ops::Range<usize> as Iterator>::next` in constant functions
   --> $DIR/const-fn-error.rs:5:14
@@ -34,10 +30,6 @@
    |              ^^^^
    |
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/consts/const-for-feature-gate.stderr b/tests/ui/consts/const-for-feature-gate.stderr
index 3344611..6e099a3 100644
--- a/tests/ui/consts/const-for-feature-gate.stderr
+++ b/tests/ui/consts/const-for-feature-gate.stderr
@@ -17,10 +17,6 @@
 note: impl defined here, but it is not `const`
   --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
    = note: calls in constants are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
 
 error[E0015]: cannot call non-const fn `<std::ops::Range<i32> as Iterator>::next` in constants
   --> $DIR/const-for-feature-gate.rs:4:14
@@ -29,10 +25,6 @@
    |              ^^^^
    |
    = note: calls in constants are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/consts/const-for.stderr b/tests/ui/consts/const-for.stderr
index 2b817c2..78336dc 100644
--- a/tests/ui/consts/const-for.stderr
+++ b/tests/ui/consts/const-for.stderr
@@ -7,10 +7,6 @@
 note: impl defined here, but it is not `const`
   --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
    = note: calls in constants are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
 
 error[E0015]: cannot call non-const fn `<std::ops::Range<i32> as Iterator>::next` in constants
   --> $DIR/const-for.rs:4:14
@@ -19,10 +15,6 @@
    |              ^^^^
    |
    = note: calls in constants are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/consts/const-try-feature-gate.stderr b/tests/ui/consts/const-try-feature-gate.stderr
index 0c4c16f..dc1dabc 100644
--- a/tests/ui/consts/const-try-feature-gate.stderr
+++ b/tests/ui/consts/const-try-feature-gate.stderr
@@ -17,10 +17,6 @@
 note: impl defined here, but it is not `const`
   --> $SRC_DIR/core/src/option.rs:LL:COL
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
 
 error[E0015]: `?` cannot convert from residual of `Option<()>` in constant functions
   --> $DIR/const-try-feature-gate.rs:4:5
@@ -31,10 +27,6 @@
 note: impl defined here, but it is not `const`
   --> $SRC_DIR/core/src/option.rs:LL:COL
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/consts/const-try.rs b/tests/ui/consts/const-try.rs
index 9089dd7..758c4dd 100644
--- a/tests/ui/consts/const-try.rs
+++ b/tests/ui/consts/const-try.rs
@@ -1,4 +1,4 @@
-//@ known-bug: #110395
+//@ compile-flags: -Znext-solver
 
 // Demonstrates what's needed to make use of `?` in const contexts.
 
@@ -14,12 +14,14 @@
 struct Error;
 
 impl const FromResidual<Error> for TryMe {
+    //~^ ERROR const `impl` for trait `FromResidual` which is not marked with `#[const_trait]`
     fn from_residual(residual: Error) -> Self {
         TryMe
     }
 }
 
 impl const Try for TryMe {
+    //~^ ERROR const `impl` for trait `Try` which is not marked with `#[const_trait]`
     type Output = ();
     type Residual = Error;
     fn from_output(output: Self::Output) -> Self {
@@ -32,6 +34,8 @@
 
 const fn t() -> TryMe {
     TryMe?;
+    //~^ ERROR `?` cannot determine the branch of `TryMe` in constant functions
+    //~| ERROR `?` cannot convert from residual of `TryMe` in constant functions
     TryMe
 }
 
diff --git a/tests/ui/consts/const-try.stderr b/tests/ui/consts/const-try.stderr
index 8afdd4e..abb1a92 100644
--- a/tests/ui/consts/const-try.stderr
+++ b/tests/ui/consts/const-try.stderr
@@ -1,8 +1,3 @@
-error: using `#![feature(effects)]` without enabling next trait solver globally
-   |
-   = note: the next trait solver must be enabled globally for the effects feature to work correctly
-   = help: use `-Znext-solver` to enable
-
 error: const `impl` for trait `FromResidual` which is not marked with `#[const_trait]`
   --> $DIR/const-try.rs:16:12
    |
@@ -13,7 +8,7 @@
    = note: adding a non-const method body in the future would be a breaking change
 
 error: const `impl` for trait `Try` which is not marked with `#[const_trait]`
-  --> $DIR/const-try.rs:22:12
+  --> $DIR/const-try.rs:23:12
    |
 LL | impl const Try for TryMe {
    |            ^^^
@@ -21,5 +16,22 @@
    = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const`
    = note: adding a non-const method body in the future would be a breaking change
 
-error: aborting due to 3 previous errors
+error[E0015]: `?` cannot determine the branch of `TryMe` in constant functions
+  --> $DIR/const-try.rs:36:5
+   |
+LL |     TryMe?;
+   |     ^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
 
+error[E0015]: `?` cannot convert from residual of `TryMe` in constant functions
+  --> $DIR/const-try.rs:36:5
+   |
+LL |     TryMe?;
+   |     ^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/consts/const-unstable-intrinsic.rs b/tests/ui/consts/const-unstable-intrinsic.rs
new file mode 100644
index 0000000..050abc6
--- /dev/null
+++ b/tests/ui/consts/const-unstable-intrinsic.rs
@@ -0,0 +1,76 @@
+//! Ensure that unstable intrinsics can actually not be called,
+//! neither within a crate nor cross-crate.
+//@ aux-build:unstable_intrinsic.rs
+#![feature(staged_api, rustc_attrs, intrinsics)]
+#![stable(since="1.0.0", feature = "stable")]
+#![feature(local)]
+
+extern crate unstable_intrinsic;
+
+fn main() {
+    const_main();
+}
+
+const fn const_main() {
+    let x = 42;
+    unsafe {
+        unstable_intrinsic::old_way::size_of_val(&x);
+        //~^ERROR: unstable library feature 'unstable'
+        //~|ERROR: cannot call non-const intrinsic
+        unstable_intrinsic::old_way::min_align_of_val(&x);
+        //~^ERROR: unstable library feature 'unstable'
+        //~|ERROR: not yet stable as a const intrinsic
+        unstable_intrinsic::new_way::size_of_val(&x);
+        //~^ERROR: unstable library feature 'unstable'
+        //~|ERROR: cannot be (indirectly) exposed to stable
+        unstable_intrinsic::new_way::min_align_of_val(&x);
+        //~^ERROR: unstable library feature 'unstable'
+        //~|ERROR: not yet stable as a const intrinsic
+
+        old_way::size_of_val(&x);
+        //~^ERROR: cannot call non-const intrinsic
+        old_way::min_align_of_val(&x);
+        //~^ERROR: cannot use `#[feature(local)]`
+        new_way::size_of_val(&x);
+        //~^ERROR: cannot be (indirectly) exposed to stable
+        new_way::min_align_of_val(&x);
+        //~^ERROR: cannot use `#[feature(local)]`
+    }
+}
+
+#[stable(since="1.0.0", feature = "stable")]
+pub mod old_way {
+    extern "rust-intrinsic" {
+        #[unstable(feature = "local", issue = "42")]
+        pub fn size_of_val<T>(x: *const T) -> usize;
+
+        #[unstable(feature = "local", issue = "42")]
+        #[rustc_const_unstable(feature = "local", issue = "42")]
+        pub fn min_align_of_val<T>(x: *const T) -> usize;
+    }
+}
+
+#[stable(since="1.0.0", feature = "stable")]
+pub mod new_way {
+    #[unstable(feature = "local", issue = "42")]
+    #[rustc_intrinsic]
+    pub const unsafe fn size_of_val<T>(x: *const T) -> usize { 42 }
+
+    #[unstable(feature = "local", issue = "42")]
+    #[rustc_const_unstable(feature = "local", issue = "42")]
+    #[rustc_intrinsic]
+    pub const unsafe fn min_align_of_val<T>(x: *const T) -> usize { 42 }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")]
+#[inline]
+pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
+    // Const stability attributes are not inherited from parent items.
+    extern "rust-intrinsic" {
+        fn copy<T>(src: *const T, dst: *mut T, count: usize);
+    }
+
+    unsafe { copy(src, dst, count) }
+    //~^ ERROR cannot call non-const intrinsic
+}
diff --git a/tests/ui/consts/const-unstable-intrinsic.stderr b/tests/ui/consts/const-unstable-intrinsic.stderr
new file mode 100644
index 0000000..33a434c
--- /dev/null
+++ b/tests/ui/consts/const-unstable-intrinsic.stderr
@@ -0,0 +1,127 @@
+error[E0658]: use of unstable library feature 'unstable'
+  --> $DIR/const-unstable-intrinsic.rs:17:9
+   |
+LL |         unstable_intrinsic::old_way::size_of_val(&x);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #42 <https://github.com/rust-lang/rust/issues/42> for more information
+   = help: add `#![feature(unstable)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: use of unstable library feature 'unstable'
+  --> $DIR/const-unstable-intrinsic.rs:20:9
+   |
+LL |         unstable_intrinsic::old_way::min_align_of_val(&x);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #42 <https://github.com/rust-lang/rust/issues/42> for more information
+   = help: add `#![feature(unstable)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: use of unstable library feature 'unstable'
+  --> $DIR/const-unstable-intrinsic.rs:23:9
+   |
+LL |         unstable_intrinsic::new_way::size_of_val(&x);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #42 <https://github.com/rust-lang/rust/issues/42> for more information
+   = help: add `#![feature(unstable)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: use of unstable library feature 'unstable'
+  --> $DIR/const-unstable-intrinsic.rs:26:9
+   |
+LL |         unstable_intrinsic::new_way::min_align_of_val(&x);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #42 <https://github.com/rust-lang/rust/issues/42> for more information
+   = help: add `#![feature(unstable)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error: cannot call non-const intrinsic `size_of_val` in constant functions
+  --> $DIR/const-unstable-intrinsic.rs:17:9
+   |
+LL |         unstable_intrinsic::old_way::size_of_val(&x);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: `min_align_of_val` is not yet stable as a const intrinsic
+  --> $DIR/const-unstable-intrinsic.rs:20:9
+   |
+LL |         unstable_intrinsic::old_way::min_align_of_val(&x);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: add `#![feature(unstable)]` to the crate attributes to enable
+
+error: intrinsic `unstable_intrinsic::new_way::size_of_val` cannot be (indirectly) exposed to stable
+  --> $DIR/const-unstable-intrinsic.rs:23:9
+   |
+LL |         unstable_intrinsic::new_way::size_of_val(&x);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: mark the caller as `#[rustc_const_unstable]`, or mark the intrinsic `#[rustc_const_stable_indirect]` (but this requires team approval)
+
+error: `min_align_of_val` is not yet stable as a const intrinsic
+  --> $DIR/const-unstable-intrinsic.rs:26:9
+   |
+LL |         unstable_intrinsic::new_way::min_align_of_val(&x);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: add `#![feature(unstable)]` to the crate attributes to enable
+
+error: cannot call non-const intrinsic `size_of_val` in constant functions
+  --> $DIR/const-unstable-intrinsic.rs:30:9
+   |
+LL |         old_way::size_of_val(&x);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(local)]`
+  --> $DIR/const-unstable-intrinsic.rs:32:9
+   |
+LL |         old_way::min_align_of_val(&x);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do)
+   |
+LL + #[rustc_const_unstable(feature = "...", issue = "...")]
+LL | const fn const_main() {
+   |
+help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
+   |
+LL + #[rustc_allow_const_fn_unstable(local)]
+LL | const fn const_main() {
+   |
+
+error: intrinsic `new_way::size_of_val` cannot be (indirectly) exposed to stable
+  --> $DIR/const-unstable-intrinsic.rs:34:9
+   |
+LL |         new_way::size_of_val(&x);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: mark the caller as `#[rustc_const_unstable]`, or mark the intrinsic `#[rustc_const_stable_indirect]` (but this requires team approval)
+
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(local)]`
+  --> $DIR/const-unstable-intrinsic.rs:36:9
+   |
+LL |         new_way::min_align_of_val(&x);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do)
+   |
+LL + #[rustc_const_unstable(feature = "...", issue = "...")]
+LL | const fn const_main() {
+   |
+help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
+   |
+LL + #[rustc_allow_const_fn_unstable(local)]
+LL | const fn const_main() {
+   |
+
+error: cannot call non-const intrinsic `copy` in constant functions
+  --> $DIR/const-unstable-intrinsic.rs:74:14
+   |
+LL |     unsafe { copy(src, dst, count) }
+   |              ^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 13 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/consts/const_cmp_type_id.rs b/tests/ui/consts/const_cmp_type_id.rs
index 7748200..3a54764 100644
--- a/tests/ui/consts/const_cmp_type_id.rs
+++ b/tests/ui/consts/const_cmp_type_id.rs
@@ -1,4 +1,3 @@
-//@ check-pass
 //@ compile-flags: -Znext-solver
 #![feature(const_type_id, const_trait_impl, effects)]
 #![allow(incomplete_features)]
@@ -7,11 +6,13 @@
 
 fn main() {
     const {
-        // FIXME(effects) this isn't supposed to pass (right now) but it did.
-        // revisit binops typeck please.
         assert!(TypeId::of::<u8>() == TypeId::of::<u8>());
+        //~^ ERROR cannot call non-const operator in constants
         assert!(TypeId::of::<()>() != TypeId::of::<u8>());
+        //~^ ERROR cannot call non-const operator in constants
         let _a = TypeId::of::<u8>() < TypeId::of::<u16>();
+        //~^ ERROR cannot call non-const operator in constants
         // can't assert `_a` because it is not deterministic
+        // FIXME(effects) make it pass
     }
 }
diff --git a/tests/ui/consts/const_cmp_type_id.stderr b/tests/ui/consts/const_cmp_type_id.stderr
new file mode 100644
index 0000000..12f3536
--- /dev/null
+++ b/tests/ui/consts/const_cmp_type_id.stderr
@@ -0,0 +1,34 @@
+error[E0015]: cannot call non-const operator in constants
+  --> $DIR/const_cmp_type_id.rs:9:17
+   |
+LL |         assert!(TypeId::of::<u8>() == TypeId::of::<u8>());
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: impl defined here, but it is not `const`
+  --> $SRC_DIR/core/src/any.rs:LL:COL
+   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
+
+error[E0015]: cannot call non-const operator in constants
+  --> $DIR/const_cmp_type_id.rs:11:17
+   |
+LL |         assert!(TypeId::of::<()>() != TypeId::of::<u8>());
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: impl defined here, but it is not `const`
+  --> $SRC_DIR/core/src/any.rs:LL:COL
+   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
+
+error[E0015]: cannot call non-const operator in constants
+  --> $DIR/const_cmp_type_id.rs:13:18
+   |
+LL |         let _a = TypeId::of::<u8>() < TypeId::of::<u16>();
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: impl defined here, but it is not `const`
+  --> $SRC_DIR/core/src/any.rs:LL:COL
+   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
+   = note: this error originates in the derive macro `PartialOrd` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/consts/constifconst-call-in-const-position.stderr b/tests/ui/consts/constifconst-call-in-const-position.stderr
index 7de10f0..2195cab 100644
--- a/tests/ui/consts/constifconst-call-in-const-position.stderr
+++ b/tests/ui/consts/constifconst-call-in-const-position.stderr
@@ -3,24 +3,12 @@
    = note: the next trait solver must be enabled globally for the effects feature to work correctly
    = help: use `-Znext-solver` to enable
 
-error[E0308]: mismatched types
+error[E0080]: evaluation of `foo::<()>::{constant#0}` failed
   --> $DIR/constifconst-call-in-const-position.rs:17:38
    |
 LL | const fn foo<T: ~const Tr>() -> [u8; T::a()] {
-   |                                      ^^^^^^ expected `false`, found `host`
-   |
-   = note: expected constant `false`
-              found constant `host`
+   |                                      ^^^^^^ calling non-const function `<() as Tr>::a`
 
-error[E0308]: mismatched types
-  --> $DIR/constifconst-call-in-const-position.rs:18:9
-   |
-LL |     [0; T::a()]
-   |         ^^^^^^ expected `false`, found `host`
-   |
-   = note: expected constant `false`
-              found constant `host`
+error: aborting due to 2 previous errors
 
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0308`.
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/control-flow/loop.stderr b/tests/ui/consts/control-flow/loop.stderr
index 13d5d3e..5e43c70 100644
--- a/tests/ui/consts/control-flow/loop.stderr
+++ b/tests/ui/consts/control-flow/loop.stderr
@@ -35,10 +35,6 @@
 note: impl defined here, but it is not `const`
   --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
    = note: calls in constants are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
 
 error[E0015]: cannot call non-const fn `<std::ops::Range<i32> as Iterator>::next` in constants
   --> $DIR/loop.rs:53:14
@@ -47,10 +43,6 @@
    |              ^^^^
    |
    = note: calls in constants are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
 
 error[E0015]: cannot convert `std::ops::Range<i32>` into an iterator in constants
   --> $DIR/loop.rs:59:14
@@ -61,10 +53,6 @@
 note: impl defined here, but it is not `const`
   --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
    = note: calls in constants are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
 
 error[E0015]: cannot call non-const fn `<std::ops::Range<i32> as Iterator>::next` in constants
   --> $DIR/loop.rs:59:14
@@ -73,10 +61,6 @@
    |              ^^^^
    |
    = note: calls in constants are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
 
 error: aborting due to 6 previous errors
 
diff --git a/tests/ui/consts/control-flow/try.stderr b/tests/ui/consts/control-flow/try.stderr
index e08f523..5e2c773 100644
--- a/tests/ui/consts/control-flow/try.stderr
+++ b/tests/ui/consts/control-flow/try.stderr
@@ -17,10 +17,6 @@
 note: impl defined here, but it is not `const`
   --> $SRC_DIR/core/src/option.rs:LL:COL
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
 
 error[E0015]: `?` cannot convert from residual of `Option<i32>` in constant functions
   --> $DIR/try.rs:6:5
@@ -31,10 +27,6 @@
 note: impl defined here, but it is not `const`
   --> $SRC_DIR/core/src/option.rs:LL:COL
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/consts/copy-intrinsic.rs b/tests/ui/consts/copy-intrinsic.rs
index 805c03d..62917c0 100644
--- a/tests/ui/consts/copy-intrinsic.rs
+++ b/tests/ui/consts/copy-intrinsic.rs
@@ -5,9 +5,11 @@
 use std::mem;
 
 extern "rust-intrinsic" {
+    #[stable(feature = "dummy", since = "1.0.0")]
     #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")]
     fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
 
+    #[stable(feature = "dummy", since = "1.0.0")]
     #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")]
     fn copy<T>(src: *const T, dst: *mut T, count: usize);
 }
diff --git a/tests/ui/consts/copy-intrinsic.stderr b/tests/ui/consts/copy-intrinsic.stderr
index da81391..29a88f6 100644
--- a/tests/ui/consts/copy-intrinsic.stderr
+++ b/tests/ui/consts/copy-intrinsic.stderr
@@ -1,23 +1,23 @@
 error[E0080]: evaluation of constant value failed
-  --> $DIR/copy-intrinsic.rs:28:5
+  --> $DIR/copy-intrinsic.rs:30:5
    |
 LL |     copy_nonoverlapping(0x100 as *const i32, dangle, 1);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got 0x100[noalloc] which is a dangling pointer (it has no provenance)
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/copy-intrinsic.rs:37:5
+  --> $DIR/copy-intrinsic.rs:39:5
    |
 LL |     copy_nonoverlapping(dangle, 0x100 as *mut i32, 1);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got ALLOC0+0x28 which is at or beyond the end of the allocation of size 4 bytes
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/copy-intrinsic.rs:44:5
+  --> $DIR/copy-intrinsic.rs:46:5
    |
 LL |     copy(&x, &mut y, 1usize << (mem::size_of::<usize>() * 8 - 1));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow computing total size of `copy`
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/copy-intrinsic.rs:50:5
+  --> $DIR/copy-intrinsic.rs:52:5
    |
 LL |     copy_nonoverlapping(&x, &mut y, 1usize << (mem::size_of::<usize>() * 8 - 1));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow computing total size of `copy_nonoverlapping`
diff --git a/tests/ui/consts/fn_trait_refs.stderr b/tests/ui/consts/fn_trait_refs.stderr
index 218c90f..a686bc2 100644
--- a/tests/ui/consts/fn_trait_refs.stderr
+++ b/tests/ui/consts/fn_trait_refs.stderr
@@ -11,96 +11,168 @@
    |            ^^^^^^^^^
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/fn_trait_refs.rs:13:15
+  --> $DIR/fn_trait_refs.rs:13:8
    |
 LL |     T: ~const Fn<()> + ~const Destruct,
-   |               ^^^^^^
+   |        ^^^^^^
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/fn_trait_refs.rs:13:31
+  --> $DIR/fn_trait_refs.rs:13:24
    |
 LL |     T: ~const Fn<()> + ~const Destruct,
-   |                               ^^^^^^^^
+   |                        ^^^^^^
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/fn_trait_refs.rs:13:15
+  --> $DIR/fn_trait_refs.rs:13:8
    |
 LL |     T: ~const Fn<()> + ~const Destruct,
-   |               ^^^^^^
+   |        ^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/fn_trait_refs.rs:20:15
+  --> $DIR/fn_trait_refs.rs:13:8
    |
-LL |     T: ~const FnMut<()> + ~const Destruct,
-   |               ^^^^^^^^^
-
-error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/fn_trait_refs.rs:20:34
-   |
-LL |     T: ~const FnMut<()> + ~const Destruct,
-   |                                  ^^^^^^^^
-
-error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/fn_trait_refs.rs:20:15
-   |
-LL |     T: ~const FnMut<()> + ~const Destruct,
-   |               ^^^^^^^^^
+LL |     T: ~const Fn<()> + ~const Destruct,
+   |        ^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/fn_trait_refs.rs:27:15
+  --> $DIR/fn_trait_refs.rs:13:24
+   |
+LL |     T: ~const Fn<()> + ~const Destruct,
+   |                        ^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/fn_trait_refs.rs:20:8
+   |
+LL |     T: ~const FnMut<()> + ~const Destruct,
+   |        ^^^^^^
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/fn_trait_refs.rs:20:27
+   |
+LL |     T: ~const FnMut<()> + ~const Destruct,
+   |                           ^^^^^^
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/fn_trait_refs.rs:20:8
+   |
+LL |     T: ~const FnMut<()> + ~const Destruct,
+   |        ^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/fn_trait_refs.rs:20:8
+   |
+LL |     T: ~const FnMut<()> + ~const Destruct,
+   |        ^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/fn_trait_refs.rs:20:27
+   |
+LL |     T: ~const FnMut<()> + ~const Destruct,
+   |                           ^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/fn_trait_refs.rs:27:8
    |
 LL |     T: ~const FnOnce<()>,
-   |               ^^^^^^^^^^
+   |        ^^^^^^
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/fn_trait_refs.rs:27:15
+  --> $DIR/fn_trait_refs.rs:27:8
    |
 LL |     T: ~const FnOnce<()>,
-   |               ^^^^^^^^^^
+   |        ^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/fn_trait_refs.rs:34:15
+  --> $DIR/fn_trait_refs.rs:27:8
    |
-LL |     T: ~const Fn<()> + ~const Destruct,
-   |               ^^^^^^
-
-error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/fn_trait_refs.rs:34:31
-   |
-LL |     T: ~const Fn<()> + ~const Destruct,
-   |                               ^^^^^^^^
-
-error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/fn_trait_refs.rs:34:15
-   |
-LL |     T: ~const Fn<()> + ~const Destruct,
-   |               ^^^^^^
+LL |     T: ~const FnOnce<()>,
+   |        ^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/fn_trait_refs.rs:48:15
+  --> $DIR/fn_trait_refs.rs:34:8
    |
-LL |     T: ~const FnMut<()> + ~const Destruct,
-   |               ^^^^^^^^^
+LL |     T: ~const Fn<()> + ~const Destruct,
+   |        ^^^^^^
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/fn_trait_refs.rs:48:34
+  --> $DIR/fn_trait_refs.rs:34:24
    |
-LL |     T: ~const FnMut<()> + ~const Destruct,
-   |                                  ^^^^^^^^
+LL |     T: ~const Fn<()> + ~const Destruct,
+   |                        ^^^^^^
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/fn_trait_refs.rs:48:15
+  --> $DIR/fn_trait_refs.rs:34:8
+   |
+LL |     T: ~const Fn<()> + ~const Destruct,
+   |        ^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/fn_trait_refs.rs:34:8
+   |
+LL |     T: ~const Fn<()> + ~const Destruct,
+   |        ^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/fn_trait_refs.rs:34:24
+   |
+LL |     T: ~const Fn<()> + ~const Destruct,
+   |                        ^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/fn_trait_refs.rs:48:8
    |
 LL |     T: ~const FnMut<()> + ~const Destruct,
-   |               ^^^^^^^^^
+   |        ^^^^^^
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/fn_trait_refs.rs:48:27
+   |
+LL |     T: ~const FnMut<()> + ~const Destruct,
+   |                           ^^^^^^
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/fn_trait_refs.rs:48:8
+   |
+LL |     T: ~const FnMut<()> + ~const Destruct,
+   |        ^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/fn_trait_refs.rs:48:8
+   |
+LL |     T: ~const FnMut<()> + ~const Destruct,
+   |        ^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/fn_trait_refs.rs:48:27
+   |
+LL |     T: ~const FnMut<()> + ~const Destruct,
+   |                           ^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
@@ -111,10 +183,6 @@
    |                 ^^^^^^^^^^^^^^^^^^^^^
    |
    = note: calls in constants are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(effects)]` to the crate attributes to enable
-   |
-LL + #![feature(effects)]
-   |
 
 error[E0015]: cannot call non-const operator in constants
   --> $DIR/fn_trait_refs.rs:73:17
@@ -123,10 +191,6 @@
    |                 ^^^^^^^^^^^^^^^^^^
    |
    = note: calls in constants are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(effects)]` to the crate attributes to enable
-   |
-LL + #![feature(effects)]
-   |
 
 error[E0015]: cannot call non-const closure in constant functions
   --> $DIR/fn_trait_refs.rs:15:5
@@ -139,10 +203,6 @@
    |
 LL |     T: ~const Fn<()> + ~const Destruct + ~const Fn(),
    |                                        +++++++++++++
-help: add `#![feature(effects)]` to the crate attributes to enable
-   |
-LL + #![feature(effects)]
-   |
 
 error[E0493]: destructor of `T` cannot be evaluated at compile-time
   --> $DIR/fn_trait_refs.rs:11:23
@@ -164,10 +224,6 @@
    |
 LL |     T: ~const FnMut<()> + ~const Destruct + ~const FnMut(),
    |                                           ++++++++++++++++
-help: add `#![feature(effects)]` to the crate attributes to enable
-   |
-LL + #![feature(effects)]
-   |
 
 error[E0493]: destructor of `T` cannot be evaluated at compile-time
   --> $DIR/fn_trait_refs.rs:18:27
@@ -189,10 +245,6 @@
    |
 LL |     T: ~const FnOnce<()> + ~const FnOnce(),
    |                          +++++++++++++++++
-help: add `#![feature(effects)]` to the crate attributes to enable
-   |
-LL + #![feature(effects)]
-   |
 
 error[E0493]: destructor of `T` cannot be evaluated at compile-time
   --> $DIR/fn_trait_refs.rs:32:21
@@ -212,7 +264,7 @@
 LL | }
    | - value is dropped here
 
-error: aborting due to 25 previous errors
+error: aborting due to 34 previous errors
 
 Some errors have detailed explanations: E0015, E0493, E0635.
 For more information about an error, try `rustc --explain E0015`.
diff --git a/tests/ui/consts/intrinsic_without_const_stab.rs b/tests/ui/consts/intrinsic_without_const_stab.rs
deleted file mode 100644
index 40ec65d..0000000
--- a/tests/ui/consts/intrinsic_without_const_stab.rs
+++ /dev/null
@@ -1,17 +0,0 @@
-#![feature(intrinsics, staged_api)]
-#![stable(feature = "core", since = "1.6.0")]
-
-#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")]
-#[inline]
-pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
-    // Const stability attributes are not inherited from parent items.
-    extern "rust-intrinsic" {
-        fn copy<T>(src: *const T, dst: *mut T, count: usize);
-    }
-
-    unsafe { copy(src, dst, count) }
-    //~^ ERROR cannot call non-const fn
-}
-
-fn main() {}
diff --git a/tests/ui/consts/intrinsic_without_const_stab.stderr b/tests/ui/consts/intrinsic_without_const_stab.stderr
deleted file mode 100644
index e314308..0000000
--- a/tests/ui/consts/intrinsic_without_const_stab.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-error[E0015]: cannot call non-const fn `copy::copy::<T>` in constant functions
-  --> $DIR/intrinsic_without_const_stab.rs:13:14
-   |
-LL |     unsafe { copy(src, dst, count) }
-   |              ^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/consts/intrinsic_without_const_stab_fail.rs b/tests/ui/consts/intrinsic_without_const_stab_fail.rs
deleted file mode 100644
index 2b0745b..0000000
--- a/tests/ui/consts/intrinsic_without_const_stab_fail.rs
+++ /dev/null
@@ -1,15 +0,0 @@
-#![feature(intrinsics, staged_api)]
-#![stable(feature = "core", since = "1.6.0")]
-
-extern "rust-intrinsic" {
-    fn copy<T>(src: *const T, dst: *mut T, count: usize);
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")]
-#[inline]
-pub const unsafe fn stuff<T>(src: *const T, dst: *mut T, count: usize) {
-    unsafe { copy(src, dst, count) } //~ ERROR cannot call non-const fn
-}
-
-fn main() {}
diff --git a/tests/ui/consts/intrinsic_without_const_stab_fail.stderr b/tests/ui/consts/intrinsic_without_const_stab_fail.stderr
deleted file mode 100644
index 8ade68e..0000000
--- a/tests/ui/consts/intrinsic_without_const_stab_fail.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-error[E0015]: cannot call non-const fn `copy::<T>` in constant functions
-  --> $DIR/intrinsic_without_const_stab_fail.rs:12:14
-   |
-LL |     unsafe { copy(src, dst, count) }
-   |              ^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/consts/invalid-inline-const-in-match-arm.stderr b/tests/ui/consts/invalid-inline-const-in-match-arm.stderr
index 0e41053..2e48837 100644
--- a/tests/ui/consts/invalid-inline-const-in-match-arm.stderr
+++ b/tests/ui/consts/invalid-inline-const-in-match-arm.stderr
@@ -6,10 +6,6 @@
    |
    = note: closures need an RFC before allowed to be called in constants
    = note: calls in constants are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
 
 error: could not evaluate constant pattern
   --> $DIR/invalid-inline-const-in-match-arm.rs:5:9
diff --git a/tests/ui/consts/issue-28113.stderr b/tests/ui/consts/issue-28113.stderr
index c2f5387..401536c 100644
--- a/tests/ui/consts/issue-28113.stderr
+++ b/tests/ui/consts/issue-28113.stderr
@@ -6,10 +6,6 @@
    |
    = note: closures need an RFC before allowed to be called in constants
    = note: calls in constants are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/consts/issue-56164.stderr b/tests/ui/consts/issue-56164.stderr
index 6ec4ce0..de5a53c 100644
--- a/tests/ui/consts/issue-56164.stderr
+++ b/tests/ui/consts/issue-56164.stderr
@@ -6,10 +6,6 @@
    |
    = note: closures need an RFC before allowed to be called in constant functions
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
 
 error: function pointer calls are not allowed in constant functions
   --> $DIR/issue-56164.rs:5:5
diff --git a/tests/ui/consts/issue-68542-closure-in-array-len.stderr b/tests/ui/consts/issue-68542-closure-in-array-len.stderr
index b414a6e..9f323b2 100644
--- a/tests/ui/consts/issue-68542-closure-in-array-len.stderr
+++ b/tests/ui/consts/issue-68542-closure-in-array-len.stderr
@@ -6,10 +6,6 @@
    |
    = note: closures need an RFC before allowed to be called in constants
    = note: calls in constants are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/consts/issue-73976-monomorphic.stderr b/tests/ui/consts/issue-73976-monomorphic.stderr
index 79dbed4..ef754b2 100644
--- a/tests/ui/consts/issue-73976-monomorphic.stderr
+++ b/tests/ui/consts/issue-73976-monomorphic.stderr
@@ -7,10 +7,6 @@
 note: impl defined here, but it is not `const`
   --> $SRC_DIR/core/src/any.rs:LL:COL
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(effects)]` to the crate attributes to enable
-   |
-LL + #![feature(effects)]
-   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/consts/issue-90870.rs b/tests/ui/consts/issue-90870.rs
index e1929c6..b62769a 100644
--- a/tests/ui/consts/issue-90870.rs
+++ b/tests/ui/consts/issue-90870.rs
@@ -3,9 +3,6 @@
 #![allow(dead_code)]
 
 const fn f(a: &u8, b: &u8) -> bool {
-//~^ HELP: add `#![feature(const_trait_impl)]`
-//~| HELP: add `#![feature(const_trait_impl)]`
-//~| HELP: add `#![feature(const_trait_impl)]`
     a == b
     //~^ ERROR: cannot call non-const operator in constant functions [E0015]
     //~| HELP: consider dereferencing here
diff --git a/tests/ui/consts/issue-90870.stderr b/tests/ui/consts/issue-90870.stderr
index df88a0c..ea98792 100644
--- a/tests/ui/consts/issue-90870.stderr
+++ b/tests/ui/consts/issue-90870.stderr
@@ -1,5 +1,5 @@
 error[E0015]: cannot call non-const operator in constant functions
-  --> $DIR/issue-90870.rs:9:5
+  --> $DIR/issue-90870.rs:6:5
    |
 LL |     a == b
    |     ^^^^^^
@@ -9,13 +9,9 @@
    |
 LL |     *a == *b
    |     +     +
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
 
 error[E0015]: cannot call non-const operator in constant functions
-  --> $DIR/issue-90870.rs:15:5
+  --> $DIR/issue-90870.rs:12:5
    |
 LL |     a == b
    |     ^^^^^^
@@ -25,13 +21,9 @@
    |
 LL |     ****a == ****b
    |     ++++     ++++
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
 
 error[E0015]: cannot call non-const operator in constant functions
-  --> $DIR/issue-90870.rs:22:12
+  --> $DIR/issue-90870.rs:19:12
    |
 LL |         if l == r {
    |            ^^^^^^
@@ -41,10 +33,6 @@
    |
 LL |         if *l == *r {
    |            +     +
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/consts/issue-94675.stderr b/tests/ui/consts/issue-94675.stderr
index a85c5e1..8cad137 100644
--- a/tests/ui/consts/issue-94675.stderr
+++ b/tests/ui/consts/issue-94675.stderr
@@ -7,10 +7,6 @@
 note: impl defined here, but it is not `const`
   --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(effects)]` to the crate attributes to enable
-   |
-LL + #![feature(effects)]
-   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs b/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs
index 461499e..d6f0799 100644
--- a/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs
+++ b/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs
@@ -5,7 +5,7 @@
             issue = "none")]
 
 #![feature(foo, foo2)]
-#![feature(const_async_blocks, staged_api)]
+#![feature(const_async_blocks, staged_api, rustc_attrs)]
 
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_const_unstable(feature="foo", issue = "none")]
@@ -14,33 +14,55 @@
 #[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 not yet stable as a const fn
+const fn bar() -> u32 { foo() } //~ ERROR cannot use `#[feature(foo)]`
 
 #[unstable(feature = "foo2", issue = "none")]
+#[rustc_const_unstable(feature = "foo2", issue = "none")]
 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 not yet stable as a const fn
+const fn bar2() -> u32 { foo2() } //~ ERROR cannot use `#[feature(foo2)]`
 
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_const_stable(feature = "rust1", since = "1.0.0")]
 // conformity is required
 const fn bar3() -> u32 {
     let x = async { 13 };
-    //~^ ERROR const-stable function cannot use `#[feature(const_async_blocks)]`
+    //~^ ERROR cannot use `#[feature(const_async_blocks)]`
     foo()
-    //~^ ERROR is not yet stable as a const fn
+    //~^ ERROR cannot use `#[feature(foo)]`
 }
 
 // check whether this function cannot be called even with the feature gate active
 #[unstable(feature = "foo2", issue = "none")]
+#[rustc_const_unstable(feature = "foo2", issue = "none")]
 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 not yet stable as a const fn
+const fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR cannot use `#[feature(foo2)]`
+
+// Functions without any attribute are checked like stable functions,
+// even if they are in a stable module.
+mod stable {
+    #![stable(feature = "rust1", since = "1.0.0")]
+
+    pub(crate) const fn bar2_gated_stable_indirect() -> u32 { super::foo2_gated() } //~ ERROR cannot use `#[feature(foo2)]`
+}
+// And same for const-unstable functions that are marked as "stable_indirect".
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_unstable(feature="foo", issue = "none")]
+#[rustc_const_stable_indirect]
+const fn stable_indirect() -> u32 { foo2_gated() } //~ ERROR cannot use `#[feature(foo2)]`
+
+// These functiuons *can* be called from fully stable functions.
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
+const fn bar2_gated_exposed() -> u32 {
+    stable::bar2_gated_stable_indirect() + stable_indirect()
+}
 
 fn main() {}
diff --git a/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr b/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr
index fedc5a4..899cec0 100644
--- a/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr
+++ b/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr
@@ -1,51 +1,127 @@
-error: `foo` is not yet stable as a const fn
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo)]`
   --> $DIR/min_const_fn_libstd_stability.rs:17:25
    |
 LL | const fn bar() -> u32 { foo() }
    |                         ^^^^^
    |
-   = help: const-stable functions can only call other const-stable functions
+   = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features
+help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do)
+   |
+LL + #[rustc_const_unstable(feature = "...", issue = "...")]
+LL | const fn bar() -> u32 { foo() }
+   |
+help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
+   |
+LL + #[rustc_allow_const_fn_unstable(foo)]
+LL | const fn bar() -> u32 { foo() }
+   |
 
-error: `foo2` is not yet stable as a const fn
-  --> $DIR/min_const_fn_libstd_stability.rs:25:26
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo2)]`
+  --> $DIR/min_const_fn_libstd_stability.rs:26:26
    |
 LL | const fn bar2() -> u32 { foo2() }
    |                          ^^^^^^
    |
-   = help: const-stable functions can only call other const-stable functions
+   = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features
+help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do)
+   |
+LL + #[rustc_const_unstable(feature = "...", issue = "...")]
+LL | const fn bar2() -> u32 { foo2() }
+   |
+help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
+   |
+LL + #[rustc_allow_const_fn_unstable(foo2)]
+LL | const fn bar2() -> u32 { foo2() }
+   |
 
-error: const-stable function cannot use `#[feature(const_async_blocks)]`
-  --> $DIR/min_const_fn_libstd_stability.rs:31:13
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(const_async_blocks)]`
+  --> $DIR/min_const_fn_libstd_stability.rs:32:13
    |
 LL |     let x = async { 13 };
    |             ^^^^^^^^^^^^
    |
-help: if the function is not (yet) meant to be stable, make this function unstably const
+help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do)
    |
 LL + #[rustc_const_unstable(feature = "...", issue = "...")]
 LL | const fn bar3() -> u32 {
    |
-help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (but requires team approval)
+help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
    |
 LL + #[rustc_allow_const_fn_unstable(const_async_blocks)]
 LL | const fn bar3() -> u32 {
    |
 
-error: `foo` is not yet stable as a const fn
-  --> $DIR/min_const_fn_libstd_stability.rs:33:5
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo)]`
+  --> $DIR/min_const_fn_libstd_stability.rs:34:5
    |
 LL |     foo()
    |     ^^^^^
    |
-   = help: const-stable functions can only call other const-stable functions
+   = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features
+help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do)
+   |
+LL + #[rustc_const_unstable(feature = "...", issue = "...")]
+LL | const fn bar3() -> u32 {
+   |
+help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
+   |
+LL + #[rustc_allow_const_fn_unstable(foo)]
+LL | const fn bar3() -> u32 {
+   |
 
-error: `foo2_gated` is not yet stable as a const fn
-  --> $DIR/min_const_fn_libstd_stability.rs:44:32
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo2)]`
+  --> $DIR/min_const_fn_libstd_stability.rs:46:32
    |
 LL | const fn bar2_gated() -> u32 { foo2_gated() }
    |                                ^^^^^^^^^^^^
    |
-   = help: const-stable functions can only call other const-stable functions
+   = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features
+help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do)
+   |
+LL + #[rustc_const_unstable(feature = "...", issue = "...")]
+LL | const fn bar2_gated() -> u32 { foo2_gated() }
+   |
+help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
+   |
+LL + #[rustc_allow_const_fn_unstable(foo2)]
+LL | const fn bar2_gated() -> u32 { foo2_gated() }
+   |
 
-error: aborting due to 5 previous errors
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo2)]`
+  --> $DIR/min_const_fn_libstd_stability.rs:53:63
+   |
+LL |     pub(crate) const fn bar2_gated_stable_indirect() -> u32 { super::foo2_gated() }
+   |                                                               ^^^^^^^^^^^^^^^^^^^
+   |
+   = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features
+help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do)
+   |
+LL +     #[rustc_const_unstable(feature = "...", issue = "...")]
+LL |     pub(crate) const fn bar2_gated_stable_indirect() -> u32 { super::foo2_gated() }
+   |
+help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
+   |
+LL +     #[rustc_allow_const_fn_unstable(foo2)]
+LL |     pub(crate) const fn bar2_gated_stable_indirect() -> u32 { super::foo2_gated() }
+   |
+
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo2)]`
+  --> $DIR/min_const_fn_libstd_stability.rs:59:37
+   |
+LL | const fn stable_indirect() -> u32 { foo2_gated() }
+   |                                     ^^^^^^^^^^^^
+   |
+   = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features
+help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do)
+   |
+LL + #[rustc_const_unstable(feature = "...", issue = "...")]
+LL | const fn stable_indirect() -> u32 { foo2_gated() }
+   |
+help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
+   |
+LL + #[rustc_allow_const_fn_unstable(foo2)]
+LL | const fn stable_indirect() -> u32 { foo2_gated() }
+   |
+
+error: aborting due to 7 previous errors
 
diff --git a/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs b/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs
index 274b444..3e82b9f 100644
--- a/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs
+++ b/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs
@@ -13,24 +13,26 @@
 #[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 not yet stable as a const fn
+const unsafe fn bar() -> u32 { unsafe { foo() } } //~ ERROR cannot use `#[feature(foo)]`
 
 #[unstable(feature = "foo2", issue = "none")]
+#[rustc_const_unstable(feature = "foo2", issue = "none")]
 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 not yet stable as a const fn
+const unsafe fn bar2() -> u32 { unsafe { foo2() } } //~ ERROR cannot use `#[feature(foo2)]`
 
 // check whether this function cannot be called even with the feature gate active
 #[unstable(feature = "foo2", issue = "none")]
+#[rustc_const_unstable(feature = "foo2", issue = "none")]
 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 not yet stable as a const fn
+//~^ ERROR cannot use `#[feature(foo2)]`
 
 fn main() {}
diff --git a/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr b/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr
index 353b117..442a079 100644
--- a/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr
+++ b/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr
@@ -1,26 +1,56 @@
-error: `foo` is not yet stable as a const fn
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo)]`
   --> $DIR/min_const_unsafe_fn_libstd_stability.rs:16:41
    |
 LL | const unsafe fn bar() -> u32 { unsafe { foo() } }
    |                                         ^^^^^
    |
-   = help: const-stable functions can only call other const-stable functions
+   = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features
+help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do)
+   |
+LL + #[rustc_const_unstable(feature = "...", issue = "...")]
+LL | const unsafe fn bar() -> u32 { unsafe { foo() } }
+   |
+help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
+   |
+LL + #[rustc_allow_const_fn_unstable(foo)]
+LL | const unsafe fn bar() -> u32 { unsafe { foo() } }
+   |
 
-error: `foo2` is not yet stable as a const fn
-  --> $DIR/min_const_unsafe_fn_libstd_stability.rs:24:42
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo2)]`
+  --> $DIR/min_const_unsafe_fn_libstd_stability.rs:25:42
    |
 LL | const unsafe fn bar2() -> u32 { unsafe { foo2() } }
    |                                          ^^^^^^
    |
-   = help: const-stable functions can only call other const-stable functions
+   = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features
+help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do)
+   |
+LL + #[rustc_const_unstable(feature = "...", issue = "...")]
+LL | const unsafe fn bar2() -> u32 { unsafe { foo2() } }
+   |
+help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
+   |
+LL + #[rustc_allow_const_fn_unstable(foo2)]
+LL | const unsafe fn bar2() -> u32 { unsafe { foo2() } }
+   |
 
-error: `foo2_gated` is not yet stable as a const fn
-  --> $DIR/min_const_unsafe_fn_libstd_stability.rs:33:48
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo2)]`
+  --> $DIR/min_const_unsafe_fn_libstd_stability.rs:35:48
    |
 LL | const unsafe fn bar2_gated() -> u32 { unsafe { foo2_gated() } }
    |                                                ^^^^^^^^^^^^
    |
-   = help: const-stable functions can only call other const-stable functions
+   = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features
+help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do)
+   |
+LL + #[rustc_const_unstable(feature = "...", issue = "...")]
+LL | const unsafe fn bar2_gated() -> u32 { unsafe { foo2_gated() } }
+   |
+help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
+   |
+LL + #[rustc_allow_const_fn_unstable(foo2)]
+LL | const unsafe fn bar2_gated() -> u32 { unsafe { foo2_gated() } }
+   |
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs b/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs
index 94b6207..cc7eaa5 100644
--- a/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs
+++ b/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs
@@ -13,23 +13,25 @@
 #[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 not yet stable as a const fn
+const unsafe fn bar() -> u32 { foo() } //~ ERROR cannot use `#[feature(foo)]`
 
 #[unstable(feature = "foo2", issue = "none")]
+#[rustc_const_unstable(feature="foo2", issue = "none")]
 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 not yet stable as a const fn
+const unsafe fn bar2() -> u32 { foo2() } //~ ERROR cannot use `#[feature(foo2)]`
 
 // check whether this function cannot be called even with the feature gate active
 #[unstable(feature = "foo2", issue = "none")]
+#[rustc_const_unstable(feature="foo2", issue = "none")]
 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 not yet stable as a const fn
+const unsafe fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR cannot use `#[feature(foo2)]`
 
 fn main() {}
diff --git a/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr b/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr
index e90ba9b..ff37cba 100644
--- a/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr
+++ b/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr
@@ -1,26 +1,56 @@
-error: `foo` is not yet stable as a const fn
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo)]`
   --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:16:32
    |
 LL | const unsafe fn bar() -> u32 { foo() }
    |                                ^^^^^
    |
-   = help: const-stable functions can only call other const-stable functions
+   = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features
+help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do)
+   |
+LL + #[rustc_const_unstable(feature = "...", issue = "...")]
+LL | const unsafe fn bar() -> u32 { foo() }
+   |
+help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
+   |
+LL + #[rustc_allow_const_fn_unstable(foo)]
+LL | const unsafe fn bar() -> u32 { foo() }
+   |
 
-error: `foo2` is not yet stable as a const fn
-  --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:24:33
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo2)]`
+  --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:25:33
    |
 LL | const unsafe fn bar2() -> u32 { foo2() }
    |                                 ^^^^^^
    |
-   = help: const-stable functions can only call other const-stable functions
+   = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features
+help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do)
+   |
+LL + #[rustc_const_unstable(feature = "...", issue = "...")]
+LL | const unsafe fn bar2() -> u32 { foo2() }
+   |
+help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
+   |
+LL + #[rustc_allow_const_fn_unstable(foo2)]
+LL | const unsafe fn bar2() -> u32 { foo2() }
+   |
 
-error: `foo2_gated` is not yet stable as a const fn
-  --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:33:39
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo2)]`
+  --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:35:39
    |
 LL | const unsafe fn bar2_gated() -> u32 { foo2_gated() }
    |                                       ^^^^^^^^^^^^
    |
-   = help: const-stable functions can only call other const-stable functions
+   = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features
+help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do)
+   |
+LL + #[rustc_const_unstable(feature = "...", issue = "...")]
+LL | const unsafe fn bar2_gated() -> u32 { foo2_gated() }
+   |
+help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
+   |
+LL + #[rustc_allow_const_fn_unstable(foo2)]
+LL | const unsafe fn bar2_gated() -> u32 { foo2_gated() }
+   |
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/consts/rustc-const-stability-require-const.rs b/tests/ui/consts/rustc-const-stability-require-const.rs
index 4fb259b..6cc3f0f 100644
--- a/tests/ui/consts/rustc-const-stability-require-const.rs
+++ b/tests/ui/consts/rustc-const-stability-require-const.rs
@@ -1,16 +1,16 @@
 #![crate_type = "lib"]
-#![feature(staged_api)]
+#![feature(staged_api, rustc_attrs)]
 #![stable(feature = "foo", since = "1.0.0")]
 
 #[stable(feature = "foo", since = "1.0.0")]
 #[rustc_const_unstable(feature = "const_foo", issue = "none")]
 pub fn foo() {}
-//~^ ERROR attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const`
+//~^ ERROR require the function or method to be `const`
 
 #[stable(feature = "bar", since = "1.0.0")]
 #[rustc_const_stable(feature = "const_bar", since = "1.0.0")]
 pub fn bar() {}
-//~^ ERROR attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const`
+//~^ ERROR require the function or method to be `const`
 
 #[stable(feature = "potato", since = "1.0.0")]
 pub struct Potato;
@@ -19,23 +19,23 @@
     #[stable(feature = "salad", since = "1.0.0")]
     #[rustc_const_unstable(feature = "const_salad", issue = "none")]
     pub fn salad(&self) -> &'static str { "mmmmmm" }
-    //~^ ERROR attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const`
+    //~^ ERROR require the function or method to be `const`
 
     #[stable(feature = "roasted", since = "1.0.0")]
     #[rustc_const_unstable(feature = "const_roasted", issue = "none")]
     pub fn roasted(&self) -> &'static str { "mmmmmmmmmm" }
-    //~^ ERROR attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const`
+    //~^ ERROR require the function or method to be `const`
 }
 
 #[stable(feature = "bar", since = "1.0.0")]
 #[rustc_const_stable(feature = "const_bar", since = "1.0.0")]
 pub extern "C" fn bar_c() {}
-//~^ ERROR attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const`
+//~^ ERROR require the function or method to be `const`
 
 #[stable(feature = "foo", since = "1.0.0")]
 #[rustc_const_unstable(feature = "const_foo", issue = "none")]
 pub extern "C" fn foo_c() {}
-//~^ ERROR attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const`
+//~^ ERROR require the function or method to be `const`
 
 
 #[stable(feature = "foobar", since = "1.0.0")]
@@ -45,3 +45,20 @@
 #[stable(feature = "barfoo", since = "1.0.0")]
 #[rustc_const_stable(feature = "barfoo_const", since = "1.0.0")]
 pub const fn barfoo() {}
+
+// `rustc_const_stable` also requires the function to be stable.
+
+#[rustc_const_stable(feature = "barfoo_const", since = "1.0.0")]
+const fn barfoo_unmarked() {}
+//~^ ERROR can only be applied to functions that are declared `#[stable]`
+
+#[unstable(feature = "unstable", issue = "none")]
+#[rustc_const_stable(feature = "barfoo_const", since = "1.0.0")]
+pub const fn barfoo_unstable() {}
+//~^ ERROR can only be applied to functions that are declared `#[stable]`
+
+// `#[rustc_const_stable_indirect]` also requires a const fn
+#[rustc_const_stable_indirect]
+#[unstable(feature = "unstable", issue = "none")]
+pub fn not_a_const_fn() {}
+//~^ ERROR require the function or method to be `const`
diff --git a/tests/ui/consts/rustc-const-stability-require-const.stderr b/tests/ui/consts/rustc-const-stability-require-const.stderr
index 1027b93..d9a7d37 100644
--- a/tests/ui/consts/rustc-const-stability-require-const.stderr
+++ b/tests/ui/consts/rustc-const-stability-require-const.stderr
@@ -1,8 +1,6 @@
-error: attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const`
+error: attributes `#[rustc_const_unstable]`, `#[rustc_const_stable]` and `#[rustc_const_stable_indirect]` require the function or method to be `const`
   --> $DIR/rustc-const-stability-require-const.rs:7:1
    |
-LL | #[rustc_const_unstable(feature = "const_foo", issue = "none")]
-   | -------------------------------------------------------------- attribute specified here
 LL | pub fn foo() {}
    | ^^^^^^^^^^^^
    |
@@ -12,11 +10,9 @@
 LL | pub fn foo() {}
    | ^^^^^^^^^^^^
 
-error: attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const`
+error: attributes `#[rustc_const_unstable]`, `#[rustc_const_stable]` and `#[rustc_const_stable_indirect]` require the function or method to be `const`
   --> $DIR/rustc-const-stability-require-const.rs:12:1
    |
-LL | #[rustc_const_stable(feature = "const_bar", since = "1.0.0")]
-   | ------------------------------------------------------------- attribute specified here
 LL | pub fn bar() {}
    | ^^^^^^^^^^^^
    |
@@ -26,11 +22,9 @@
 LL | pub fn bar() {}
    | ^^^^^^^^^^^^
 
-error: attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const`
+error: attributes `#[rustc_const_unstable]`, `#[rustc_const_stable]` and `#[rustc_const_stable_indirect]` require the function or method to be `const`
   --> $DIR/rustc-const-stability-require-const.rs:21:5
    |
-LL |     #[rustc_const_unstable(feature = "const_salad", issue = "none")]
-   |     ---------------------------------------------------------------- attribute specified here
 LL |     pub fn salad(&self) -> &'static str { "mmmmmm" }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
@@ -40,11 +34,9 @@
 LL |     pub fn salad(&self) -> &'static str { "mmmmmm" }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const`
+error: attributes `#[rustc_const_unstable]`, `#[rustc_const_stable]` and `#[rustc_const_stable_indirect]` require the function or method to be `const`
   --> $DIR/rustc-const-stability-require-const.rs:26:5
    |
-LL |     #[rustc_const_unstable(feature = "const_roasted", issue = "none")]
-   |     ------------------------------------------------------------------ attribute specified here
 LL |     pub fn roasted(&self) -> &'static str { "mmmmmmmmmm" }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
@@ -54,11 +46,9 @@
 LL |     pub fn roasted(&self) -> &'static str { "mmmmmmmmmm" }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const`
+error: attributes `#[rustc_const_unstable]`, `#[rustc_const_stable]` and `#[rustc_const_stable_indirect]` require the function or method to be `const`
   --> $DIR/rustc-const-stability-require-const.rs:32:1
    |
-LL | #[rustc_const_stable(feature = "const_bar", since = "1.0.0")]
-   | ------------------------------------------------------------- attribute specified here
 LL | pub extern "C" fn bar_c() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
@@ -68,11 +58,9 @@
 LL | pub extern "C" fn bar_c() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const`
+error: attributes `#[rustc_const_unstable]`, `#[rustc_const_stable]` and `#[rustc_const_stable_indirect]` require the function or method to be `const`
   --> $DIR/rustc-const-stability-require-const.rs:37:1
    |
-LL | #[rustc_const_unstable(feature = "const_foo", issue = "none")]
-   | -------------------------------------------------------------- attribute specified here
 LL | pub extern "C" fn foo_c() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
@@ -82,5 +70,33 @@
 LL | pub extern "C" fn foo_c() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 6 previous errors
+error: attribute `#[rustc_const_stable]` can only be applied to functions that are declared `#[stable]`
+  --> $DIR/rustc-const-stability-require-const.rs:52:1
+   |
+LL | #[rustc_const_stable(feature = "barfoo_const", since = "1.0.0")]
+   | ---------------------------------------------------------------- attribute specified here
+LL | const fn barfoo_unmarked() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: attribute `#[rustc_const_stable]` can only be applied to functions that are declared `#[stable]`
+  --> $DIR/rustc-const-stability-require-const.rs:57:1
+   |
+LL | #[rustc_const_stable(feature = "barfoo_const", since = "1.0.0")]
+   | ---------------------------------------------------------------- attribute specified here
+LL | pub const fn barfoo_unstable() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: attributes `#[rustc_const_unstable]`, `#[rustc_const_stable]` and `#[rustc_const_stable_indirect]` require the function or method to be `const`
+  --> $DIR/rustc-const-stability-require-const.rs:63:1
+   |
+LL | pub fn not_a_const_fn() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: make the function or method const
+  --> $DIR/rustc-const-stability-require-const.rs:63:1
+   |
+LL | pub fn not_a_const_fn() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 9 previous errors
 
diff --git a/tests/ui/consts/try-operator.stderr b/tests/ui/consts/try-operator.stderr
index 2c8b4c7..40d96ed 100644
--- a/tests/ui/consts/try-operator.stderr
+++ b/tests/ui/consts/try-operator.stderr
@@ -13,10 +13,6 @@
 note: impl defined here, but it is not `const`
   --> $SRC_DIR/core/src/result.rs:LL:COL
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(effects)]` to the crate attributes to enable
-   |
-LL + #![feature(effects)]
-   |
 
 error[E0015]: `?` cannot convert from residual of `Result<bool, ()>` in constant functions
   --> $DIR/try-operator.rs:10:9
@@ -27,10 +23,6 @@
 note: impl defined here, but it is not `const`
   --> $SRC_DIR/core/src/result.rs:LL:COL
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(effects)]` to the crate attributes to enable
-   |
-LL + #![feature(effects)]
-   |
 
 error[E0015]: `?` cannot determine the branch of `Option<()>` in constant functions
   --> $DIR/try-operator.rs:18:9
@@ -41,10 +33,6 @@
 note: impl defined here, but it is not `const`
   --> $SRC_DIR/core/src/option.rs:LL:COL
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(effects)]` to the crate attributes to enable
-   |
-LL + #![feature(effects)]
-   |
 
 error[E0015]: `?` cannot convert from residual of `Option<()>` in constant functions
   --> $DIR/try-operator.rs:18:9
@@ -55,10 +43,6 @@
 note: impl defined here, but it is not `const`
   --> $SRC_DIR/core/src/option.rs:LL:COL
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(effects)]` to the crate attributes to enable
-   |
-LL + #![feature(effects)]
-   |
 
 error: aborting due to 5 previous errors
 
diff --git a/tests/ui/consts/unstable-const-fn-in-libcore.stderr b/tests/ui/consts/unstable-const-fn-in-libcore.stderr
index 6c83eff..2bdec1b 100644
--- a/tests/ui/consts/unstable-const-fn-in-libcore.stderr
+++ b/tests/ui/consts/unstable-const-fn-in-libcore.stderr
@@ -1,8 +1,16 @@
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/unstable-const-fn-in-libcore.rs:19:39
+  --> $DIR/unstable-const-fn-in-libcore.rs:19:32
    |
 LL |     const fn unwrap_or_else<F: ~const FnOnce() -> T>(self, f: F) -> T {
-   |                                       ^^^^^^^^^^^^^
+   |                                ^^^^^^
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/unstable-const-fn-in-libcore.rs:19:32
+   |
+LL |     const fn unwrap_or_else<F: ~const FnOnce() -> T>(self, f: F) -> T {
+   |                                ^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0015]: cannot call non-const closure in constant functions
   --> $DIR/unstable-const-fn-in-libcore.rs:24:26
@@ -15,10 +23,6 @@
    |
 LL |     const fn unwrap_or_else<F: ~const FnOnce() -> T + ~const FnOnce()>(self, f: F) -> T {
    |                                                     +++++++++++++++++
-help: add `#![feature(effects)]` to the crate attributes to enable
-   |
-LL + #![feature(effects)]
-   |
 
 error[E0493]: destructor of `F` cannot be evaluated at compile-time
   --> $DIR/unstable-const-fn-in-libcore.rs:19:60
@@ -38,7 +42,7 @@
 LL |     }
    |     - value is dropped here
 
-error: aborting due to 4 previous errors
+error: aborting due to 5 previous errors
 
 Some errors have detailed explanations: E0015, E0493.
 For more information about an error, try `rustc --explain E0015`.
diff --git a/tests/ui/consts/unstable-const-stable.rs b/tests/ui/consts/unstable-const-stable.rs
deleted file mode 100644
index f69e8d0..0000000
--- a/tests/ui/consts/unstable-const-stable.rs
+++ /dev/null
@@ -1,14 +0,0 @@
-//@ aux-build:unstable_but_const_stable.rs
-
-extern crate unstable_but_const_stable;
-use unstable_but_const_stable::*;
-
-fn main() {
-    some_unstable_fn(); //~ERROR use of unstable library feature
-    unsafe { write_bytes(4 as *mut u8, 0, 0) }; //~ERROR use of unstable library feature
-}
-
-const fn const_main() {
-    some_unstable_fn(); //~ERROR use of unstable library feature
-    unsafe { write_bytes(4 as *mut u8, 0, 0) }; //~ERROR use of unstable library feature
-}
diff --git a/tests/ui/consts/unstable-const-stable.stderr b/tests/ui/consts/unstable-const-stable.stderr
deleted file mode 100644
index c4ffbbb..0000000
--- a/tests/ui/consts/unstable-const-stable.stderr
+++ /dev/null
@@ -1,43 +0,0 @@
-error[E0658]: use of unstable library feature 'unstable'
-  --> $DIR/unstable-const-stable.rs:7:5
-   |
-LL |     some_unstable_fn();
-   |     ^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #42 <https://github.com/rust-lang/rust/issues/42> for more information
-   = help: add `#![feature(unstable)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: use of unstable library feature 'unstable'
-  --> $DIR/unstable-const-stable.rs:8:14
-   |
-LL |     unsafe { write_bytes(4 as *mut u8, 0, 0) };
-   |              ^^^^^^^^^^^
-   |
-   = note: see issue #42 <https://github.com/rust-lang/rust/issues/42> for more information
-   = help: add `#![feature(unstable)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: use of unstable library feature 'unstable'
-  --> $DIR/unstable-const-stable.rs:12:5
-   |
-LL |     some_unstable_fn();
-   |     ^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #42 <https://github.com/rust-lang/rust/issues/42> for more information
-   = help: add `#![feature(unstable)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: use of unstable library feature 'unstable'
-  --> $DIR/unstable-const-stable.rs:13:14
-   |
-LL |     unsafe { write_bytes(4 as *mut u8, 0, 0) };
-   |              ^^^^^^^^^^^
-   |
-   = note: see issue #42 <https://github.com/rust-lang/rust/issues/42> for more information
-   = help: add `#![feature(unstable)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error: aborting due to 4 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/consts/zst_no_llvm_alloc.rs b/tests/ui/consts/zst_no_llvm_alloc.rs
index 48ef11e..1e92e3b 100644
--- a/tests/ui/consts/zst_no_llvm_alloc.rs
+++ b/tests/ui/consts/zst_no_llvm_alloc.rs
@@ -17,8 +17,11 @@
 
     // The exact addresses returned by these library functions are not necessarily stable guarantees
     // but for now we assert that we're still matching.
-    assert_eq!(<Vec<i32>>::new().as_ptr(), <&[i32]>::default().as_ptr());
-    assert_eq!(<Box<[i32]>>::default().as_ptr(), (&[]).as_ptr());
+    #[allow(dangling_pointers_from_temporaries)]
+    {
+        assert_eq!(<Vec<i32>>::new().as_ptr(), <&[i32]>::default().as_ptr());
+        assert_eq!(<Box<[i32]>>::default().as_ptr(), (&[]).as_ptr());
+    };
 
     // statics must have a unique address (see https://github.com/rust-lang/rust/issues/18297, not
     // clear whether this is a stable guarantee)
diff --git a/tests/ui/delegation/ice-issue-124347.rs b/tests/ui/delegation/ice-issue-124347.rs
index ee2bf9e..b2b3c61 100644
--- a/tests/ui/delegation/ice-issue-124347.rs
+++ b/tests/ui/delegation/ice-issue-124347.rs
@@ -4,7 +4,7 @@
 // FIXME(fn_delegation): `recursive delegation` error should be emitted here
 trait Trait {
     reuse Trait::foo { &self.0 }
-    //~^ ERROR cycle detected when computing generics of `Trait::foo`
+    //~^ ERROR recursive delegation is not supported yet
 }
 
 reuse foo;
diff --git a/tests/ui/delegation/ice-issue-124347.stderr b/tests/ui/delegation/ice-issue-124347.stderr
index bd0bc97..74c4b5c 100644
--- a/tests/ui/delegation/ice-issue-124347.stderr
+++ b/tests/ui/delegation/ice-issue-124347.stderr
@@ -1,16 +1,8 @@
-error[E0391]: cycle detected when computing generics of `Trait::foo`
+error: recursive delegation is not supported yet
   --> $DIR/ice-issue-124347.rs:6:18
    |
 LL |     reuse Trait::foo { &self.0 }
-   |                  ^^^
-   |
-   = note: ...which immediately requires computing generics of `Trait::foo` again
-note: cycle used when inheriting delegation signature
-  --> $DIR/ice-issue-124347.rs:6:18
-   |
-LL |     reuse Trait::foo { &self.0 }
-   |                  ^^^
-   = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
+   |                  ^^^ callee defined here
 
 error[E0391]: cycle detected when computing generics of `foo`
   --> $DIR/ice-issue-124347.rs:10:7
diff --git a/tests/ui/delegation/unsupported.rs b/tests/ui/delegation/unsupported.rs
index e57efff..56296db 100644
--- a/tests/ui/delegation/unsupported.rs
+++ b/tests/ui/delegation/unsupported.rs
@@ -51,7 +51,7 @@
     }
 
     reuse Trait::foo;
-    //~^ ERROR delegation to a function with effect parameter is not supported yet
+    //~^ ERROR type annotations needed
 }
 
 fn main() {}
diff --git a/tests/ui/delegation/unsupported.stderr b/tests/ui/delegation/unsupported.stderr
index 6a627be..1c79a60 100644
--- a/tests/ui/delegation/unsupported.stderr
+++ b/tests/ui/delegation/unsupported.stderr
@@ -81,15 +81,15 @@
 LL |     reuse to_reuse1::foo;
    |                      ^^^
 
-error: delegation to a function with effect parameter is not supported yet
+error[E0283]: type annotations needed
   --> $DIR/unsupported.rs:53:18
    |
-LL |         fn foo();
-   |         --------- callee defined here
-...
 LL |     reuse Trait::foo;
-   |                  ^^^
+   |                  ^^^ cannot infer type
+   |
+   = note: cannot satisfy `_: effects::Trait`
 
 error: aborting due to 5 previous errors; 2 warnings emitted
 
-For more information about this error, try `rustc --explain E0391`.
+Some errors have detailed explanations: E0283, E0391.
+For more information about an error, try `rustc --explain E0283`.
diff --git a/tests/ui/deriving/auxiliary/another-proc-macro.rs b/tests/ui/deriving/auxiliary/another-proc-macro.rs
index a05175c..c992cde 100644
--- a/tests/ui/deriving/auxiliary/another-proc-macro.rs
+++ b/tests/ui/deriving/auxiliary/another-proc-macro.rs
@@ -6,7 +6,7 @@
 
 extern crate proc_macro;
 
-use proc_macro::{quote, TokenStream};
+use proc_macro::{TokenStream, quote};
 
 #[proc_macro_derive(AnotherMacro, attributes(pointee))]
 pub fn derive(_input: TokenStream) -> TokenStream {
diff --git a/tests/ui/deriving/built-in-proc-macro-scope.rs b/tests/ui/deriving/built-in-proc-macro-scope.rs
index 41c95f6..6c473ae 100644
--- a/tests/ui/deriving/built-in-proc-macro-scope.rs
+++ b/tests/ui/deriving/built-in-proc-macro-scope.rs
@@ -2,14 +2,14 @@
 //@ aux-build: another-proc-macro.rs
 //@ compile-flags: -Zunpretty=expanded
 
-#![feature(derive_smart_pointer)]
+#![feature(derive_coerce_pointee)]
 
 #[macro_use]
 extern crate another_proc_macro;
 
-use another_proc_macro::{pointee, AnotherMacro};
+use another_proc_macro::{AnotherMacro, pointee};
 
-#[derive(core::marker::SmartPointer)]
+#[derive(core::marker::CoercePointee)]
 #[repr(transparent)]
 pub struct Ptr<'a, #[pointee] T: ?Sized> {
     data: &'a mut T,
diff --git a/tests/ui/deriving/built-in-proc-macro-scope.stdout b/tests/ui/deriving/built-in-proc-macro-scope.stdout
index c649b7a..07767dc 100644
--- a/tests/ui/deriving/built-in-proc-macro-scope.stdout
+++ b/tests/ui/deriving/built-in-proc-macro-scope.stdout
@@ -4,7 +4,7 @@
 //@ aux-build: another-proc-macro.rs
 //@ compile-flags: -Zunpretty=expanded
 
-#![feature(derive_smart_pointer)]
+#![feature(derive_coerce_pointee)]
 #[prelude_import]
 use ::std::prelude::rust_2015::*;
 #[macro_use]
@@ -13,7 +13,7 @@
 #[macro_use]
 extern crate another_proc_macro;
 
-use another_proc_macro::{pointee, AnotherMacro};
+use another_proc_macro::{AnotherMacro, pointee};
 
 #[repr(transparent)]
 pub struct Ptr<'a, #[pointee] T: ?Sized> {
diff --git a/tests/ui/deriving/smart-pointer-bounds-issue-127647.rs b/tests/ui/deriving/coerce-pointee-bounds-issue-127647.rs
similarity index 82%
rename from tests/ui/deriving/smart-pointer-bounds-issue-127647.rs
rename to tests/ui/deriving/coerce-pointee-bounds-issue-127647.rs
index 4cae1b3..a1aabf1 100644
--- a/tests/ui/deriving/smart-pointer-bounds-issue-127647.rs
+++ b/tests/ui/deriving/coerce-pointee-bounds-issue-127647.rs
@@ -1,8 +1,8 @@
 //@ check-pass
 
-#![feature(derive_smart_pointer)]
+#![feature(derive_coerce_pointee)]
 
-#[derive(core::marker::SmartPointer)]
+#[derive(core::marker::CoercePointee)]
 #[repr(transparent)]
 pub struct Ptr<'a, #[pointee] T: OnDrop + ?Sized, X> {
     data: &'a mut T,
@@ -13,7 +13,7 @@
     fn on_drop(&mut self);
 }
 
-#[derive(core::marker::SmartPointer)]
+#[derive(core::marker::CoercePointee)]
 #[repr(transparent)]
 pub struct Ptr2<'a, #[pointee] T: ?Sized, X>
 where
@@ -25,7 +25,7 @@
 
 pub trait MyTrait<T: ?Sized> {}
 
-#[derive(core::marker::SmartPointer)]
+#[derive(core::marker::CoercePointee)]
 #[repr(transparent)]
 pub struct Ptr3<'a, #[pointee] T: ?Sized, X>
 where
@@ -35,14 +35,14 @@
     x: core::marker::PhantomData<X>,
 }
 
-#[derive(core::marker::SmartPointer)]
+#[derive(core::marker::CoercePointee)]
 #[repr(transparent)]
 pub struct Ptr4<'a, #[pointee] T: MyTrait<T> + ?Sized, X> {
     data: &'a mut T,
     x: core::marker::PhantomData<X>,
 }
 
-#[derive(core::marker::SmartPointer)]
+#[derive(core::marker::CoercePointee)]
 #[repr(transparent)]
 pub struct Ptr5<'a, #[pointee] T: ?Sized, X>
 where
@@ -56,7 +56,7 @@
 pub struct Ptr5Companion<T: ?Sized>(core::marker::PhantomData<T>);
 pub struct Ptr5Companion2;
 
-#[derive(core::marker::SmartPointer)]
+#[derive(core::marker::CoercePointee)]
 #[repr(transparent)]
 pub struct Ptr6<'a, #[pointee] T: ?Sized, X: MyTrait<T> = (), const PARAM: usize = 0> {
     data: &'a mut T,
@@ -65,7 +65,7 @@
 
 // a reduced example from https://lore.kernel.org/all/20240402-linked-list-v1-1-b1c59ba7ae3b@google.com/
 #[repr(transparent)]
-#[derive(core::marker::SmartPointer)]
+#[derive(core::marker::CoercePointee)]
 pub struct ListArc<#[pointee] T, const ID: u64 = 0>
 where
     T: ListArcSafe<ID> + ?Sized,
diff --git a/tests/ui/deriving/deriving-smart-pointer-expanded.rs b/tests/ui/deriving/deriving-coerce-pointee-expanded.rs
similarity index 74%
rename from tests/ui/deriving/deriving-smart-pointer-expanded.rs
rename to tests/ui/deriving/deriving-coerce-pointee-expanded.rs
index e48ad3d..94be703 100644
--- a/tests/ui/deriving/deriving-smart-pointer-expanded.rs
+++ b/tests/ui/deriving/deriving-coerce-pointee-expanded.rs
@@ -1,17 +1,17 @@
 //@ check-pass
 //@ compile-flags: -Zunpretty=expanded
-#![feature(derive_smart_pointer)]
-use std::marker::SmartPointer;
+#![feature(derive_coerce_pointee)]
+use std::marker::CoercePointee;
 
 pub trait MyTrait<T: ?Sized> {}
 
-#[derive(SmartPointer)]
+#[derive(CoercePointee)]
 #[repr(transparent)]
 struct MyPointer<'a, #[pointee] T: ?Sized> {
     ptr: &'a T,
 }
 
-#[derive(core::marker::SmartPointer)]
+#[derive(core::marker::CoercePointee)]
 #[repr(transparent)]
 pub struct MyPointer2<'a, Y, Z: MyTrait<T>, #[pointee] T: ?Sized + MyTrait<T>, X: MyTrait<T> = ()>
 where
@@ -21,7 +21,7 @@
     x: core::marker::PhantomData<X>,
 }
 
-#[derive(SmartPointer)]
+#[derive(CoercePointee)]
 #[repr(transparent)]
 struct MyPointerWithoutPointee<'a, T: ?Sized> {
     ptr: &'a T,
diff --git a/tests/ui/deriving/deriving-smart-pointer-expanded.stdout b/tests/ui/deriving/deriving-coerce-pointee-expanded.stdout
similarity index 96%
rename from tests/ui/deriving/deriving-smart-pointer-expanded.stdout
rename to tests/ui/deriving/deriving-coerce-pointee-expanded.stdout
index 68ef17f..d6eaca5 100644
--- a/tests/ui/deriving/deriving-smart-pointer-expanded.stdout
+++ b/tests/ui/deriving/deriving-coerce-pointee-expanded.stdout
@@ -2,12 +2,12 @@
 #![no_std]
 //@ check-pass
 //@ compile-flags: -Zunpretty=expanded
-#![feature(derive_smart_pointer)]
+#![feature(derive_coerce_pointee)]
 #[prelude_import]
 use ::std::prelude::rust_2015::*;
 #[macro_use]
 extern crate std;
-use std::marker::SmartPointer;
+use std::marker::CoercePointee;
 
 pub trait MyTrait<T: ?Sized> {}
 
diff --git a/tests/ui/deriving/deriving-coerce-pointee-neg.rs b/tests/ui/deriving/deriving-coerce-pointee-neg.rs
new file mode 100644
index 0000000..deef35c
--- /dev/null
+++ b/tests/ui/deriving/deriving-coerce-pointee-neg.rs
@@ -0,0 +1,134 @@
+#![feature(derive_coerce_pointee, arbitrary_self_types)]
+
+extern crate core;
+use std::marker::CoercePointee;
+
+#[derive(CoercePointee)]
+//~^ ERROR: `CoercePointee` can only be derived on `struct`s with `#[repr(transparent)]`
+enum NotStruct<'a, T: ?Sized> {
+    Variant(&'a T),
+}
+
+#[derive(CoercePointee)]
+//~^ ERROR: `CoercePointee` can only be derived on `struct`s with at least one field
+#[repr(transparent)]
+struct NoField<'a, #[pointee] T: ?Sized> {}
+//~^ ERROR: lifetime parameter `'a` is never used
+//~| ERROR: type parameter `T` is never used
+
+#[derive(CoercePointee)]
+//~^ ERROR: `CoercePointee` can only be derived on `struct`s with at least one field
+#[repr(transparent)]
+struct NoFieldUnit<'a, #[pointee] T: ?Sized>();
+//~^ ERROR: lifetime parameter `'a` is never used
+//~| ERROR: type parameter `T` is never used
+
+#[derive(CoercePointee)]
+//~^ ERROR: `CoercePointee` can only be derived on `struct`s that are generic over at least one type
+#[repr(transparent)]
+struct NoGeneric<'a>(&'a u8);
+
+#[derive(CoercePointee)]
+//~^ ERROR: exactly one generic type parameter must be marked as #[pointee] to derive CoercePointee traits
+#[repr(transparent)]
+struct AmbiguousPointee<'a, T1: ?Sized, T2: ?Sized> {
+    a: (&'a T1, &'a T2),
+}
+
+#[derive(CoercePointee)]
+#[repr(transparent)]
+struct TooManyPointees<'a, #[pointee] A: ?Sized, #[pointee] B: ?Sized>((&'a A, &'a B));
+//~^ ERROR: only one type parameter can be marked as `#[pointee]` when deriving CoercePointee traits
+
+#[derive(CoercePointee)]
+//~^ ERROR: `CoercePointee` can only be derived on `struct`s with `#[repr(transparent)]`
+struct NotTransparent<'a, #[pointee] T: ?Sized> {
+    ptr: &'a T,
+}
+
+#[derive(CoercePointee)]
+#[repr(transparent)]
+struct NoMaybeSized<'a, #[pointee] T> {
+    //~^ ERROR: `derive(CoercePointee)` requires T to be marked `?Sized`
+    ptr: &'a T,
+}
+
+#[derive(CoercePointee)]
+#[repr(transparent)]
+struct PointeeOnField<'a, #[pointee] T: ?Sized> {
+    #[pointee]
+    //~^ ERROR: the `#[pointee]` attribute may only be used on generic parameters
+    ptr: &'a T,
+}
+
+#[derive(CoercePointee)]
+#[repr(transparent)]
+struct PointeeInTypeConstBlock<
+    'a,
+    T: ?Sized = [u32; const {
+                    struct UhOh<#[pointee] T>(T);
+                    //~^ ERROR: the `#[pointee]` attribute may only be used on generic parameters
+                    10
+                }],
+> {
+    ptr: &'a T,
+}
+
+#[derive(CoercePointee)]
+#[repr(transparent)]
+struct PointeeInConstConstBlock<
+    'a,
+    T: ?Sized,
+    const V: u32 = {
+        struct UhOh<#[pointee] T>(T);
+        //~^ ERROR: the `#[pointee]` attribute may only be used on generic parameters
+        10
+    },
+> {
+    ptr: &'a T,
+}
+
+#[derive(CoercePointee)]
+#[repr(transparent)]
+struct PointeeInAnotherTypeConstBlock<'a, #[pointee] T: ?Sized> {
+    ptr: PointeeInConstConstBlock<
+        'a,
+        T,
+        {
+            struct UhOh<#[pointee] T>(T);
+            //~^ ERROR: the `#[pointee]` attribute may only be used on generic parameters
+            0
+        },
+    >,
+}
+
+// However, reordering attributes should work nevertheless.
+#[repr(transparent)]
+#[derive(CoercePointee)]
+struct ThisIsAPossibleCoercePointee<'a, #[pointee] T: ?Sized> {
+    ptr: &'a T,
+}
+
+// Also, these paths to Sized should work
+#[derive(CoercePointee)]
+#[repr(transparent)]
+struct StdSized<'a, #[pointee] T: ?std::marker::Sized> {
+    ptr: &'a T,
+}
+#[derive(CoercePointee)]
+#[repr(transparent)]
+struct CoreSized<'a, #[pointee] T: ?core::marker::Sized> {
+    ptr: &'a T,
+}
+#[derive(CoercePointee)]
+#[repr(transparent)]
+struct GlobalStdSized<'a, #[pointee] T: ?::std::marker::Sized> {
+    ptr: &'a T,
+}
+#[derive(CoercePointee)]
+#[repr(transparent)]
+struct GlobalCoreSized<'a, #[pointee] T: ?::core::marker::Sized> {
+    ptr: &'a T,
+}
+
+fn main() {}
diff --git a/tests/ui/deriving/deriving-coerce-pointee-neg.stderr b/tests/ui/deriving/deriving-coerce-pointee-neg.stderr
new file mode 100644
index 0000000..e590d63
--- /dev/null
+++ b/tests/ui/deriving/deriving-coerce-pointee-neg.stderr
@@ -0,0 +1,119 @@
+error: `CoercePointee` can only be derived on `struct`s with `#[repr(transparent)]`
+  --> $DIR/deriving-coerce-pointee-neg.rs:6:10
+   |
+LL | #[derive(CoercePointee)]
+   |          ^^^^^^^^^^^^^
+   |
+   = note: this error originates in the derive macro `CoercePointee` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: `CoercePointee` can only be derived on `struct`s with at least one field
+  --> $DIR/deriving-coerce-pointee-neg.rs:12:10
+   |
+LL | #[derive(CoercePointee)]
+   |          ^^^^^^^^^^^^^
+   |
+   = note: this error originates in the derive macro `CoercePointee` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: `CoercePointee` can only be derived on `struct`s with at least one field
+  --> $DIR/deriving-coerce-pointee-neg.rs:19:10
+   |
+LL | #[derive(CoercePointee)]
+   |          ^^^^^^^^^^^^^
+   |
+   = note: this error originates in the derive macro `CoercePointee` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: `CoercePointee` can only be derived on `struct`s that are generic over at least one type
+  --> $DIR/deriving-coerce-pointee-neg.rs:26:10
+   |
+LL | #[derive(CoercePointee)]
+   |          ^^^^^^^^^^^^^
+   |
+   = note: this error originates in the derive macro `CoercePointee` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: exactly one generic type parameter must be marked as #[pointee] to derive CoercePointee traits
+  --> $DIR/deriving-coerce-pointee-neg.rs:31:10
+   |
+LL | #[derive(CoercePointee)]
+   |          ^^^^^^^^^^^^^
+   |
+   = note: this error originates in the derive macro `CoercePointee` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: only one type parameter can be marked as `#[pointee]` when deriving CoercePointee traits
+  --> $DIR/deriving-coerce-pointee-neg.rs:40:39
+   |
+LL | struct TooManyPointees<'a, #[pointee] A: ?Sized, #[pointee] B: ?Sized>((&'a A, &'a B));
+   |                                       ^                     ^
+
+error: `CoercePointee` can only be derived on `struct`s with `#[repr(transparent)]`
+  --> $DIR/deriving-coerce-pointee-neg.rs:43:10
+   |
+LL | #[derive(CoercePointee)]
+   |          ^^^^^^^^^^^^^
+   |
+   = note: this error originates in the derive macro `CoercePointee` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: `derive(CoercePointee)` requires T to be marked `?Sized`
+  --> $DIR/deriving-coerce-pointee-neg.rs:51:36
+   |
+LL | struct NoMaybeSized<'a, #[pointee] T> {
+   |                                    ^
+
+error: the `#[pointee]` attribute may only be used on generic parameters
+  --> $DIR/deriving-coerce-pointee-neg.rs:59:5
+   |
+LL |     #[pointee]
+   |     ^^^^^^^^^^
+
+error: the `#[pointee]` attribute may only be used on generic parameters
+  --> $DIR/deriving-coerce-pointee-neg.rs:69:33
+   |
+LL |                     struct UhOh<#[pointee] T>(T);
+   |                                 ^^^^^^^^^^
+
+error: the `#[pointee]` attribute may only be used on generic parameters
+  --> $DIR/deriving-coerce-pointee-neg.rs:83:21
+   |
+LL |         struct UhOh<#[pointee] T>(T);
+   |                     ^^^^^^^^^^
+
+error: the `#[pointee]` attribute may only be used on generic parameters
+  --> $DIR/deriving-coerce-pointee-neg.rs:98:25
+   |
+LL |             struct UhOh<#[pointee] T>(T);
+   |                         ^^^^^^^^^^
+
+error[E0392]: lifetime parameter `'a` is never used
+  --> $DIR/deriving-coerce-pointee-neg.rs:15:16
+   |
+LL | struct NoField<'a, #[pointee] T: ?Sized> {}
+   |                ^^ unused lifetime parameter
+   |
+   = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData`
+
+error[E0392]: type parameter `T` is never used
+  --> $DIR/deriving-coerce-pointee-neg.rs:15:31
+   |
+LL | struct NoField<'a, #[pointee] T: ?Sized> {}
+   |                               ^ unused type parameter
+   |
+   = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
+
+error[E0392]: lifetime parameter `'a` is never used
+  --> $DIR/deriving-coerce-pointee-neg.rs:22:20
+   |
+LL | struct NoFieldUnit<'a, #[pointee] T: ?Sized>();
+   |                    ^^ unused lifetime parameter
+   |
+   = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData`
+
+error[E0392]: type parameter `T` is never used
+  --> $DIR/deriving-coerce-pointee-neg.rs:22:35
+   |
+LL | struct NoFieldUnit<'a, #[pointee] T: ?Sized>();
+   |                                   ^ unused type parameter
+   |
+   = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
+
+error: aborting due to 16 previous errors
+
+For more information about this error, try `rustc --explain E0392`.
diff --git a/tests/ui/deriving/deriving-smart-pointer.rs b/tests/ui/deriving/deriving-coerce-pointee.rs
similarity index 90%
rename from tests/ui/deriving/deriving-smart-pointer.rs
rename to tests/ui/deriving/deriving-coerce-pointee.rs
index d34a502..26762e4 100644
--- a/tests/ui/deriving/deriving-smart-pointer.rs
+++ b/tests/ui/deriving/deriving-coerce-pointee.rs
@@ -1,9 +1,9 @@
 //@ run-pass
-#![feature(derive_smart_pointer, arbitrary_self_types)]
+#![feature(derive_coerce_pointee, arbitrary_self_types)]
 
-use std::marker::SmartPointer;
+use std::marker::CoercePointee;
 
-#[derive(SmartPointer)]
+#[derive(CoercePointee)]
 #[repr(transparent)]
 struct MyPointer<'a, #[pointee] T: ?Sized> {
     ptr: &'a T,
diff --git a/tests/ui/deriving/deriving-smart-pointer-neg.rs b/tests/ui/deriving/deriving-smart-pointer-neg.rs
deleted file mode 100644
index 41d3039..0000000
--- a/tests/ui/deriving/deriving-smart-pointer-neg.rs
+++ /dev/null
@@ -1,118 +0,0 @@
-#![feature(derive_smart_pointer, arbitrary_self_types)]
-
-extern crate core;
-use std::marker::SmartPointer;
-
-#[derive(SmartPointer)]
-//~^ ERROR: `SmartPointer` can only be derived on `struct`s with `#[repr(transparent)]`
-enum NotStruct<'a, T: ?Sized> {
-    Variant(&'a T),
-}
-
-#[derive(SmartPointer)]
-//~^ ERROR: `SmartPointer` can only be derived on `struct`s with at least one field
-#[repr(transparent)]
-struct NoField<'a, #[pointee] T: ?Sized> {}
-//~^ ERROR: lifetime parameter `'a` is never used
-//~| ERROR: type parameter `T` is never used
-
-#[derive(SmartPointer)]
-//~^ ERROR: `SmartPointer` can only be derived on `struct`s with at least one field
-#[repr(transparent)]
-struct NoFieldUnit<'a, #[pointee] T: ?Sized>();
-//~^ ERROR: lifetime parameter `'a` is never used
-//~| ERROR: type parameter `T` is never used
-
-#[derive(SmartPointer)]
-//~^ ERROR: `SmartPointer` can only be derived on `struct`s that are generic over at least one type
-#[repr(transparent)]
-struct NoGeneric<'a>(&'a u8);
-
-#[derive(SmartPointer)]
-//~^ ERROR: exactly one generic type parameter must be marked as #[pointee] to derive SmartPointer traits
-#[repr(transparent)]
-struct AmbiguousPointee<'a, T1: ?Sized, T2: ?Sized> {
-    a: (&'a T1, &'a T2),
-}
-
-#[derive(SmartPointer)]
-#[repr(transparent)]
-struct TooManyPointees<'a, #[pointee] A: ?Sized, #[pointee] B: ?Sized>((&'a A, &'a B));
-//~^ ERROR: only one type parameter can be marked as `#[pointee]` when deriving SmartPointer traits
-
-#[derive(SmartPointer)]
-//~^ ERROR: `SmartPointer` can only be derived on `struct`s with `#[repr(transparent)]`
-struct NotTransparent<'a, #[pointee] T: ?Sized> {
-    ptr: &'a T,
-}
-
-#[derive(SmartPointer)]
-#[repr(transparent)]
-struct NoMaybeSized<'a, #[pointee] T> {
-    //~^ ERROR: `derive(SmartPointer)` requires T to be marked `?Sized`
-    ptr: &'a T,
-}
-
-#[derive(SmartPointer)]
-#[repr(transparent)]
-struct PointeeOnField<'a, #[pointee] T: ?Sized> {
-    #[pointee]
-    //~^ ERROR: the `#[pointee]` attribute may only be used on generic parameters
-    ptr: &'a T
-}
-
-#[derive(SmartPointer)]
-#[repr(transparent)]
-struct PointeeInTypeConstBlock<'a, T: ?Sized = [u32; const { struct UhOh<#[pointee] T>(T); 10 }]> {
-    //~^ ERROR: the `#[pointee]` attribute may only be used on generic parameters
-    ptr: &'a T,
-}
-
-#[derive(SmartPointer)]
-#[repr(transparent)]
-struct PointeeInConstConstBlock<
-    'a,
-    T: ?Sized,
-    const V: u32 = { struct UhOh<#[pointee] T>(T); 10 }>
-    //~^ ERROR: the `#[pointee]` attribute may only be used on generic parameters
-{
-    ptr: &'a T,
-}
-
-#[derive(SmartPointer)]
-#[repr(transparent)]
-struct PointeeInAnotherTypeConstBlock<'a, #[pointee] T: ?Sized> {
-    ptr: PointeeInConstConstBlock<'a, T, { struct UhOh<#[pointee] T>(T); 0 }>
-    //~^ ERROR: the `#[pointee]` attribute may only be used on generic parameters
-}
-
-// However, reordering attributes should work nevertheless.
-#[repr(transparent)]
-#[derive(SmartPointer)]
-struct ThisIsAPossibleSmartPointer<'a, #[pointee] T: ?Sized> {
-    ptr: &'a T,
-}
-
-// Also, these paths to Sized should work
-#[derive(SmartPointer)]
-#[repr(transparent)]
-struct StdSized<'a, #[pointee] T: ?std::marker::Sized> {
-    ptr: &'a T,
-}
-#[derive(SmartPointer)]
-#[repr(transparent)]
-struct CoreSized<'a, #[pointee] T: ?core::marker::Sized> {
-    ptr: &'a T,
-}
-#[derive(SmartPointer)]
-#[repr(transparent)]
-struct GlobalStdSized<'a, #[pointee] T: ?::std::marker::Sized> {
-    ptr: &'a T,
-}
-#[derive(SmartPointer)]
-#[repr(transparent)]
-struct GlobalCoreSized<'a, #[pointee] T: ?::core::marker::Sized> {
-    ptr: &'a T,
-}
-
-fn main() {}
diff --git a/tests/ui/deriving/deriving-smart-pointer-neg.stderr b/tests/ui/deriving/deriving-smart-pointer-neg.stderr
deleted file mode 100644
index 9ab1176..0000000
--- a/tests/ui/deriving/deriving-smart-pointer-neg.stderr
+++ /dev/null
@@ -1,119 +0,0 @@
-error: `SmartPointer` can only be derived on `struct`s with `#[repr(transparent)]`
-  --> $DIR/deriving-smart-pointer-neg.rs:6:10
-   |
-LL | #[derive(SmartPointer)]
-   |          ^^^^^^^^^^^^
-   |
-   = note: this error originates in the derive macro `SmartPointer` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: `SmartPointer` can only be derived on `struct`s with at least one field
-  --> $DIR/deriving-smart-pointer-neg.rs:12:10
-   |
-LL | #[derive(SmartPointer)]
-   |          ^^^^^^^^^^^^
-   |
-   = note: this error originates in the derive macro `SmartPointer` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: `SmartPointer` can only be derived on `struct`s with at least one field
-  --> $DIR/deriving-smart-pointer-neg.rs:19:10
-   |
-LL | #[derive(SmartPointer)]
-   |          ^^^^^^^^^^^^
-   |
-   = note: this error originates in the derive macro `SmartPointer` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: `SmartPointer` can only be derived on `struct`s that are generic over at least one type
-  --> $DIR/deriving-smart-pointer-neg.rs:26:10
-   |
-LL | #[derive(SmartPointer)]
-   |          ^^^^^^^^^^^^
-   |
-   = note: this error originates in the derive macro `SmartPointer` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: exactly one generic type parameter must be marked as #[pointee] to derive SmartPointer traits
-  --> $DIR/deriving-smart-pointer-neg.rs:31:10
-   |
-LL | #[derive(SmartPointer)]
-   |          ^^^^^^^^^^^^
-   |
-   = note: this error originates in the derive macro `SmartPointer` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: only one type parameter can be marked as `#[pointee]` when deriving SmartPointer traits
-  --> $DIR/deriving-smart-pointer-neg.rs:40:39
-   |
-LL | struct TooManyPointees<'a, #[pointee] A: ?Sized, #[pointee] B: ?Sized>((&'a A, &'a B));
-   |                                       ^                     ^
-
-error: `SmartPointer` can only be derived on `struct`s with `#[repr(transparent)]`
-  --> $DIR/deriving-smart-pointer-neg.rs:43:10
-   |
-LL | #[derive(SmartPointer)]
-   |          ^^^^^^^^^^^^
-   |
-   = note: this error originates in the derive macro `SmartPointer` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: `derive(SmartPointer)` requires T to be marked `?Sized`
-  --> $DIR/deriving-smart-pointer-neg.rs:51:36
-   |
-LL | struct NoMaybeSized<'a, #[pointee] T> {
-   |                                    ^
-
-error: the `#[pointee]` attribute may only be used on generic parameters
-  --> $DIR/deriving-smart-pointer-neg.rs:59:5
-   |
-LL |     #[pointee]
-   |     ^^^^^^^^^^
-
-error: the `#[pointee]` attribute may only be used on generic parameters
-  --> $DIR/deriving-smart-pointer-neg.rs:66:74
-   |
-LL | struct PointeeInTypeConstBlock<'a, T: ?Sized = [u32; const { struct UhOh<#[pointee] T>(T); 10 }]> {
-   |                                                                          ^^^^^^^^^^
-
-error: the `#[pointee]` attribute may only be used on generic parameters
-  --> $DIR/deriving-smart-pointer-neg.rs:76:34
-   |
-LL |     const V: u32 = { struct UhOh<#[pointee] T>(T); 10 }>
-   |                                  ^^^^^^^^^^
-
-error: the `#[pointee]` attribute may only be used on generic parameters
-  --> $DIR/deriving-smart-pointer-neg.rs:85:56
-   |
-LL |     ptr: PointeeInConstConstBlock<'a, T, { struct UhOh<#[pointee] T>(T); 0 }>
-   |                                                        ^^^^^^^^^^
-
-error[E0392]: lifetime parameter `'a` is never used
-  --> $DIR/deriving-smart-pointer-neg.rs:15:16
-   |
-LL | struct NoField<'a, #[pointee] T: ?Sized> {}
-   |                ^^ unused lifetime parameter
-   |
-   = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData`
-
-error[E0392]: type parameter `T` is never used
-  --> $DIR/deriving-smart-pointer-neg.rs:15:31
-   |
-LL | struct NoField<'a, #[pointee] T: ?Sized> {}
-   |                               ^ unused type parameter
-   |
-   = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
-
-error[E0392]: lifetime parameter `'a` is never used
-  --> $DIR/deriving-smart-pointer-neg.rs:22:20
-   |
-LL | struct NoFieldUnit<'a, #[pointee] T: ?Sized>();
-   |                    ^^ unused lifetime parameter
-   |
-   = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData`
-
-error[E0392]: type parameter `T` is never used
-  --> $DIR/deriving-smart-pointer-neg.rs:22:35
-   |
-LL | struct NoFieldUnit<'a, #[pointee] T: ?Sized>();
-   |                                   ^ unused type parameter
-   |
-   = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
-
-error: aborting due to 16 previous errors
-
-For more information about this error, try `rustc --explain E0392`.
diff --git a/tests/ui/deriving/proc-macro-attribute-mixing.rs b/tests/ui/deriving/proc-macro-attribute-mixing.rs
index 489665e..80a0d06 100644
--- a/tests/ui/deriving/proc-macro-attribute-mixing.rs
+++ b/tests/ui/deriving/proc-macro-attribute-mixing.rs
@@ -1,5 +1,5 @@
 // This test certify that we can mix attribute macros from Rust and external proc-macros.
-// For instance, `#[derive(Default)]` uses `#[default]` and `#[derive(SmartPointer)]` uses
+// For instance, `#[derive(Default)]` uses `#[default]` and `#[derive(CoercePointee)]` uses
 // `#[pointee]`.
 // The scoping rule should allow the use of the said two attributes when external proc-macros
 // are in scope.
@@ -8,7 +8,7 @@
 //@ aux-build: another-proc-macro.rs
 //@ compile-flags: -Zunpretty=expanded
 
-#![feature(derive_smart_pointer)]
+#![feature(derive_coerce_pointee)]
 
 #[macro_use]
 extern crate another_proc_macro;
diff --git a/tests/ui/deriving/proc-macro-attribute-mixing.stdout b/tests/ui/deriving/proc-macro-attribute-mixing.stdout
index f314f6e..03128c6 100644
--- a/tests/ui/deriving/proc-macro-attribute-mixing.stdout
+++ b/tests/ui/deriving/proc-macro-attribute-mixing.stdout
@@ -1,7 +1,7 @@
 #![feature(prelude_import)]
 #![no_std]
 // This test certify that we can mix attribute macros from Rust and external proc-macros.
-// For instance, `#[derive(Default)]` uses `#[default]` and `#[derive(SmartPointer)]` uses
+// For instance, `#[derive(Default)]` uses `#[default]` and `#[derive(CoercePointee)]` uses
 // `#[pointee]`.
 // The scoping rule should allow the use of the said two attributes when external proc-macros
 // are in scope.
@@ -10,7 +10,7 @@
 //@ aux-build: another-proc-macro.rs
 //@ compile-flags: -Zunpretty=expanded
 
-#![feature(derive_smart_pointer)]
+#![feature(derive_coerce_pointee)]
 #[prelude_import]
 use ::std::prelude::rust_2015::*;
 #[macro_use]
diff --git a/tests/ui/drop/drop_order.rs b/tests/ui/drop/drop_order.rs
index cf06253..29b68d6 100644
--- a/tests/ui/drop/drop_order.rs
+++ b/tests/ui/drop/drop_order.rs
@@ -105,6 +105,7 @@
             () => self.print(10),
         }
 
+        #[cfg(edition2021)]
         match {
             match self.option_loud_drop(14) {
                 _ => {
@@ -115,6 +116,17 @@
         } {
             _ => self.print(12),
         }
+        #[cfg(edition2024)]
+        match {
+            match self.option_loud_drop(12) {
+                _ => {
+                    self.print(11);
+                    self.option_loud_drop(14)
+                }
+            }
+        } {
+            _ => self.print(13),
+        }
 
         match {
             loop {
diff --git a/tests/ui/drop/lint-tail-expr-drop-order-gated.rs b/tests/ui/drop/lint-tail-expr-drop-order-gated.rs
index b22e72b..fde542c 100644
--- a/tests/ui/drop/lint-tail-expr-drop-order-gated.rs
+++ b/tests/ui/drop/lint-tail-expr-drop-order-gated.rs
@@ -1,15 +1,11 @@
-// This test ensures that `tail_expr_drop_order` does not activate in case Edition 2024 is not used
-// or the feature gate `shorter_tail_lifetimes` is disabled.
+// This test is to demonstrate that the lint is gated behind Edition and
+// is triggered only for Edition 2021 and before.
 
-//@ revisions: neither no_feature_gate edition_less_than_2024
 //@ check-pass
-//@ [neither] edition: 2021
-//@ [no_feature_gate] compile-flags: -Z unstable-options
-//@ [no_feature_gate] edition: 2024
-//@ [edition_less_than_2024] edition: 2021
+//@ edition: 2024
+//@ compile-flags: -Z unstable-options
 
 #![deny(tail_expr_drop_order)]
-#![cfg_attr(edition_less_than_2024, feature(shorter_tail_lifetimes))]
 
 struct LoudDropper;
 impl Drop for LoudDropper {
diff --git a/tests/ui/drop/lint-tail-expr-drop-order.rs b/tests/ui/drop/lint-tail-expr-drop-order.rs
index 0aa0ef0..d61abae 100644
--- a/tests/ui/drop/lint-tail-expr-drop-order.rs
+++ b/tests/ui/drop/lint-tail-expr-drop-order.rs
@@ -1,12 +1,10 @@
-//@ compile-flags: -Z unstable-options
-//@ edition: 2024
+//@ edition: 2021
 
 // Edition 2024 lint for change in drop order at tail expression
 // This lint is to capture potential change in program semantics
 // due to implementation of RFC 3606 <https://github.com/rust-lang/rfcs/pull/3606>
 
 #![deny(tail_expr_drop_order)]
-#![feature(shorter_tail_lifetimes)]
 
 struct LoudDropper;
 impl Drop for LoudDropper {
diff --git a/tests/ui/drop/lint-tail-expr-drop-order.stderr b/tests/ui/drop/lint-tail-expr-drop-order.stderr
index 630f0a8..6775c4c 100644
--- a/tests/ui/drop/lint-tail-expr-drop-order.stderr
+++ b/tests/ui/drop/lint-tail-expr-drop-order.stderr
@@ -1,5 +1,5 @@
 error: these values and local bindings have significant drop implementation that will have a different drop order from that of Edition 2021
-  --> $DIR/lint-tail-expr-drop-order.rs:29:15
+  --> $DIR/lint-tail-expr-drop-order.rs:27:15
    |
 LL |     let x = LoudDropper;
    |         - these values have significant drop implementation and will observe changes in drop order under Edition 2024
@@ -10,13 +10,13 @@
    = warning: this changes meaning in Rust 2024
    = note: for more information, see issue #123739 <https://github.com/rust-lang/rust/issues/123739>
 note: the lint level is defined here
-  --> $DIR/lint-tail-expr-drop-order.rs:8:9
+  --> $DIR/lint-tail-expr-drop-order.rs:7:9
    |
 LL | #![deny(tail_expr_drop_order)]
    |         ^^^^^^^^^^^^^^^^^^^^
 
 error: these values and local bindings have significant drop implementation that will have a different drop order from that of Edition 2021
-  --> $DIR/lint-tail-expr-drop-order.rs:36:23
+  --> $DIR/lint-tail-expr-drop-order.rs:34:23
    |
 LL |     let x = LoudDropper;
    |         - these values have significant drop implementation and will observe changes in drop order under Edition 2024
@@ -27,7 +27,7 @@
    = note: for more information, see issue #123739 <https://github.com/rust-lang/rust/issues/123739>
 
 error: these values and local bindings have significant drop implementation that will have a different drop order from that of Edition 2021
-  --> $DIR/lint-tail-expr-drop-order.rs:65:19
+  --> $DIR/lint-tail-expr-drop-order.rs:63:19
    |
 LL |         let x = LoudDropper;
    |             - these values have significant drop implementation and will observe changes in drop order under Edition 2024
diff --git a/tests/ui/drop/tail-expr-drop-order-negative.edition2024.stderr b/tests/ui/drop/tail-expr-drop-order-negative.edition2024.stderr
index 75fc34e..bcce796 100644
--- a/tests/ui/drop/tail-expr-drop-order-negative.edition2024.stderr
+++ b/tests/ui/drop/tail-expr-drop-order-negative.edition2024.stderr
@@ -1,5 +1,5 @@
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/tail-expr-drop-order-negative.rs:11:15
+  --> $DIR/tail-expr-drop-order-negative.rs:9:15
    |
 LL |     x.replace(std::cell::RefCell::new(123).borrow()).is_some()
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^                   - temporary value is freed at the end of this statement
diff --git a/tests/ui/drop/tail-expr-drop-order-negative.rs b/tests/ui/drop/tail-expr-drop-order-negative.rs
index c570b3a..5ad04d0 100644
--- a/tests/ui/drop/tail-expr-drop-order-negative.rs
+++ b/tests/ui/drop/tail-expr-drop-order-negative.rs
@@ -3,8 +3,6 @@
 //@ [edition2024] edition: 2024
 //@ [edition2021] check-pass
 
-#![feature(shorter_tail_lifetimes)]
-
 fn why_would_you_do_this() -> bool {
     let mut x = None;
     // Make a temporary `RefCell` and put a `Ref` that borrows it in `x`.
diff --git a/tests/ui/drop/tail-expr-drop-order.rs b/tests/ui/drop/tail-expr-drop-order.rs
index 5d87f98..80968b8 100644
--- a/tests/ui/drop/tail-expr-drop-order.rs
+++ b/tests/ui/drop/tail-expr-drop-order.rs
@@ -4,7 +4,6 @@
 //@ edition: 2024
 //@ run-pass
 
-#![feature(shorter_tail_lifetimes)]
 #![allow(unused_imports)]
 #![allow(dead_code)]
 #![allow(unused_variables)]
diff --git a/tests/ui/error-codes/E0081.rs b/tests/ui/error-codes/E0081.rs
index f53fda8..8fdb27c 100644
--- a/tests/ui/error-codes/E0081.rs
+++ b/tests/ui/error-codes/E0081.rs
@@ -50,5 +50,47 @@
     //~^ NOTE `-2` assigned here
 }
 
+// Test for #131902
+// Ensure that casting an enum with too many variants for its repr
+// does not ICE
+#[repr(u8)]
+enum TooManyVariants {
+    //~^ ERROR discriminant value `0` assigned more than once
+    X000, X001, X002, X003, X004, X005, X006, X007, X008, X009,
+    //~^ NOTE `0` assigned here
+    //~| NOTE discriminant for `X256` incremented from this startpoint
+    X010, X011, X012, X013, X014, X015, X016, X017, X018, X019,
+    X020, X021, X022, X023, X024, X025, X026, X027, X028, X029,
+    X030, X031, X032, X033, X034, X035, X036, X037, X038, X039,
+    X040, X041, X042, X043, X044, X045, X046, X047, X048, X049,
+    X050, X051, X052, X053, X054, X055, X056, X057, X058, X059,
+    X060, X061, X062, X063, X064, X065, X066, X067, X068, X069,
+    X070, X071, X072, X073, X074, X075, X076, X077, X078, X079,
+    X080, X081, X082, X083, X084, X085, X086, X087, X088, X089,
+    X090, X091, X092, X093, X094, X095, X096, X097, X098, X099,
+    X100, X101, X102, X103, X104, X105, X106, X107, X108, X109,
+    X110, X111, X112, X113, X114, X115, X116, X117, X118, X119,
+    X120, X121, X122, X123, X124, X125, X126, X127, X128, X129,
+    X130, X131, X132, X133, X134, X135, X136, X137, X138, X139,
+    X140, X141, X142, X143, X144, X145, X146, X147, X148, X149,
+    X150, X151, X152, X153, X154, X155, X156, X157, X158, X159,
+    X160, X161, X162, X163, X164, X165, X166, X167, X168, X169,
+    X170, X171, X172, X173, X174, X175, X176, X177, X178, X179,
+    X180, X181, X182, X183, X184, X185, X186, X187, X188, X189,
+    X190, X191, X192, X193, X194, X195, X196, X197, X198, X199,
+    X200, X201, X202, X203, X204, X205, X206, X207, X208, X209,
+    X210, X211, X212, X213, X214, X215, X216, X217, X218, X219,
+    X220, X221, X222, X223, X224, X225, X226, X227, X228, X229,
+    X230, X231, X232, X233, X234, X235, X236, X237, X238, X239,
+    X240, X241, X242, X243, X244, X245, X246, X247, X248, X249,
+    X250, X251, X252, X253, X254, X255,
+    X256,
+    //~^ ERROR enum discriminant overflowed
+    //~| NOTE overflowed on value after 255
+    //~| NOTE explicitly set `X256 = 0`
+    //~| NOTE `0` assigned here
+}
+
 fn main() {
+    TooManyVariants::X256 as u8;
 }
diff --git a/tests/ui/error-codes/E0081.stderr b/tests/ui/error-codes/E0081.stderr
index d4b21f6..91445ee 100644
--- a/tests/ui/error-codes/E0081.stderr
+++ b/tests/ui/error-codes/E0081.stderr
@@ -73,6 +73,30 @@
 LL |     V9,
    |     -- `-2` assigned here
 
-error: aborting due to 5 previous errors
+error[E0370]: enum discriminant overflowed
+  --> $DIR/E0081.rs:87:5
+   |
+LL |     X256,
+   |     ^^^^ overflowed on value after 255
+   |
+   = note: explicitly set `X256 = 0` if that is desired outcome
 
-For more information about this error, try `rustc --explain E0081`.
+error[E0081]: discriminant value `0` assigned more than once
+  --> $DIR/E0081.rs:57:1
+   |
+LL | enum TooManyVariants {
+   | ^^^^^^^^^^^^^^^^^^^^
+LL |
+LL |     X000, X001, X002, X003, X004, X005, X006, X007, X008, X009,
+   |     ----
+   |     |
+   |     `0` assigned here
+   |     discriminant for `X256` incremented from this startpoint (`X000` + 256 variants later => `X256` = 0)
+...
+LL |     X256,
+   |     ---- `0` assigned here
+
+error: aborting due to 7 previous errors
+
+Some errors have detailed explanations: E0081, E0370.
+For more information about an error, try `rustc --explain E0081`.
diff --git a/tests/ui/feature-gates/duplicate-features.rs b/tests/ui/feature-gates/duplicate-features.rs
index d8f7818..1fae71c 100644
--- a/tests/ui/feature-gates/duplicate-features.rs
+++ b/tests/ui/feature-gates/duplicate-features.rs
@@ -1,9 +1,9 @@
 #![allow(stable_features)]
 
 #![feature(rust1)]
-#![feature(rust1)] //~ ERROR the feature `rust1` has already been declared
+#![feature(rust1)] //~ ERROR the feature `rust1` has already been enabled
 
 #![feature(if_let)]
-#![feature(if_let)] //~ ERROR the feature `if_let` has already been declared
+#![feature(if_let)] //~ ERROR the feature `if_let` has already been enabled
 
 fn main() {}
diff --git a/tests/ui/feature-gates/duplicate-features.stderr b/tests/ui/feature-gates/duplicate-features.stderr
index dbde806..f667a5b 100644
--- a/tests/ui/feature-gates/duplicate-features.stderr
+++ b/tests/ui/feature-gates/duplicate-features.stderr
@@ -1,10 +1,10 @@
-error[E0636]: the feature `if_let` has already been declared
+error[E0636]: the feature `if_let` has already been enabled
   --> $DIR/duplicate-features.rs:7:12
    |
 LL | #![feature(if_let)]
    |            ^^^^^^
 
-error[E0636]: the feature `rust1` has already been declared
+error[E0636]: the feature `rust1` has already been enabled
   --> $DIR/duplicate-features.rs:4:12
    |
 LL | #![feature(rust1)]
diff --git a/tests/ui/feature-gates/feature-gate-derive-coerce-pointee.rs b/tests/ui/feature-gates/feature-gate-derive-coerce-pointee.rs
new file mode 100644
index 0000000..69bc70e
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-derive-coerce-pointee.rs
@@ -0,0 +1,9 @@
+use std::marker::CoercePointee; //~ ERROR use of unstable library feature 'derive_coerce_pointee'
+
+#[derive(CoercePointee)] //~ ERROR use of unstable library feature 'derive_coerce_pointee'
+#[repr(transparent)]
+struct MyPointer<'a, #[pointee] T: ?Sized> {
+    ptr: &'a T,
+}
+
+fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-derive-coerce-pointee.stderr b/tests/ui/feature-gates/feature-gate-derive-coerce-pointee.stderr
new file mode 100644
index 0000000..0b52ceb
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-derive-coerce-pointee.stderr
@@ -0,0 +1,23 @@
+error[E0658]: use of unstable library feature 'derive_coerce_pointee'
+  --> $DIR/feature-gate-derive-coerce-pointee.rs:3:10
+   |
+LL | #[derive(CoercePointee)]
+   |          ^^^^^^^^^^^^^
+   |
+   = note: see issue #123430 <https://github.com/rust-lang/rust/issues/123430> for more information
+   = help: add `#![feature(derive_coerce_pointee)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: use of unstable library feature 'derive_coerce_pointee'
+  --> $DIR/feature-gate-derive-coerce-pointee.rs:1:5
+   |
+LL | use std::marker::CoercePointee;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #123430 <https://github.com/rust-lang/rust/issues/123430> for more information
+   = help: add `#![feature(derive_coerce_pointee)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/feature-gates/feature-gate-derive-smart-pointer.rs b/tests/ui/feature-gates/feature-gate-derive-smart-pointer.rs
deleted file mode 100644
index 7b4764e..0000000
--- a/tests/ui/feature-gates/feature-gate-derive-smart-pointer.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-use std::marker::SmartPointer; //~ ERROR use of unstable library feature 'derive_smart_pointer'
-
-#[derive(SmartPointer)] //~ ERROR use of unstable library feature 'derive_smart_pointer'
-#[repr(transparent)]
-struct MyPointer<'a, #[pointee] T: ?Sized> {
-    ptr: &'a T,
-}
-
-fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-derive-smart-pointer.stderr b/tests/ui/feature-gates/feature-gate-derive-smart-pointer.stderr
deleted file mode 100644
index ea4d127..0000000
--- a/tests/ui/feature-gates/feature-gate-derive-smart-pointer.stderr
+++ /dev/null
@@ -1,23 +0,0 @@
-error[E0658]: use of unstable library feature 'derive_smart_pointer'
-  --> $DIR/feature-gate-derive-smart-pointer.rs:3:10
-   |
-LL | #[derive(SmartPointer)]
-   |          ^^^^^^^^^^^^
-   |
-   = note: see issue #123430 <https://github.com/rust-lang/rust/issues/123430> for more information
-   = help: add `#![feature(derive_smart_pointer)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: use of unstable library feature 'derive_smart_pointer'
-  --> $DIR/feature-gate-derive-smart-pointer.rs:1:5
-   |
-LL | use std::marker::SmartPointer;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #123430 <https://github.com/rust-lang/rust/issues/123430> for more information
-   = help: add `#![feature(derive_smart_pointer)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/feature-gates/unstable-attribute-rejects-already-stable-features.stderr b/tests/ui/feature-gates/unstable-attribute-rejects-already-stable-features.stderr
index 319056a..d599523 100644
--- a/tests/ui/feature-gates/unstable-attribute-rejects-already-stable-features.stderr
+++ b/tests/ui/feature-gates/unstable-attribute-rejects-already-stable-features.stderr
@@ -1,4 +1,18 @@
 error: can't mark as unstable using an already stable feature
+  --> $DIR/unstable-attribute-rejects-already-stable-features.rs:7:1
+   |
+LL | #[rustc_const_unstable(feature = "arbitrary_enum_discriminant", issue = "42")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this feature is already stable
+LL | const fn my_fun() {}
+   | -------------------- the stability attribute annotates this item
+   |
+help: consider removing the attribute
+  --> $DIR/unstable-attribute-rejects-already-stable-features.rs:7:1
+   |
+LL | #[rustc_const_unstable(feature = "arbitrary_enum_discriminant", issue = "42")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: can't mark as unstable using an already stable feature
   --> $DIR/unstable-attribute-rejects-already-stable-features.rs:6:1
    |
 LL | #[unstable(feature = "arbitrary_enum_discriminant", issue = "42")]
@@ -13,19 +27,5 @@
 LL | #[unstable(feature = "arbitrary_enum_discriminant", issue = "42")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: can't mark as unstable using an already stable feature
-  --> $DIR/unstable-attribute-rejects-already-stable-features.rs:7:1
-   |
-LL | #[rustc_const_unstable(feature = "arbitrary_enum_discriminant", issue = "42")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this feature is already stable
-LL | const fn my_fun() {}
-   | -------------------- the stability attribute annotates this item
-   |
-help: consider removing the attribute
-  --> $DIR/unstable-attribute-rejects-already-stable-features.rs:7:1
-   |
-LL | #[rustc_const_unstable(feature = "arbitrary_enum_discriminant", issue = "42")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/fmt/ifmt-unimpl.stderr b/tests/ui/fmt/ifmt-unimpl.stderr
index a22bba0..f83e7c8 100644
--- a/tests/ui/fmt/ifmt-unimpl.stderr
+++ b/tests/ui/fmt/ifmt-unimpl.stderr
@@ -17,7 +17,7 @@
              i32
            and 9 others
    = note: required for `&str` to implement `UpperHex`
-note: required by a bound in `core::fmt::rt::Argument::<'a>::new_upper_hex`
+note: required by a bound in `core::fmt::rt::Argument::<'_>::new_upper_hex`
   --> $SRC_DIR/core/src/fmt/rt.rs:LL:COL
    = note: this error originates in the macro `$crate::__export::format_args` which comes from the expansion of the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
 
diff --git a/tests/ui/impl-trait/diagnostics/highlight-difference-between-expected-trait-and-found-trait.rs b/tests/ui/impl-trait/diagnostics/highlight-difference-between-expected-trait-and-found-trait.rs
new file mode 100644
index 0000000..f1c196a
--- /dev/null
+++ b/tests/ui/impl-trait/diagnostics/highlight-difference-between-expected-trait-and-found-trait.rs
@@ -0,0 +1,20 @@
+//@ only-linux
+//@ compile-flags: --error-format=human --color=always
+//@ error-pattern: the trait bound
+
+trait Foo<T>: Bar<T> {}
+
+trait Bar<T> {}
+
+struct Struct;
+
+impl<T, K> Foo<K> for T where T: Bar<K>
+{}
+
+impl<'a> Bar<()> for Struct {}
+
+fn foo() -> impl Foo<i32> {
+    Struct
+}
+
+fn main() {}
diff --git a/tests/ui/impl-trait/diagnostics/highlight-difference-between-expected-trait-and-found-trait.svg b/tests/ui/impl-trait/diagnostics/highlight-difference-between-expected-trait-and-found-trait.svg
new file mode 100644
index 0000000..e09b96e
--- /dev/null
+++ b/tests/ui/impl-trait/diagnostics/highlight-difference-between-expected-trait-and-found-trait.svg
@@ -0,0 +1,62 @@
+<svg width="1104px" height="344px" xmlns="http://www.w3.org/2000/svg">
+  <style>
+    .fg { fill: #AAAAAA }
+    .bg { background: #000000 }
+    .fg-ansi256-009 { fill: #FF5555 }
+    .fg-ansi256-010 { fill: #55FF55 }
+    .fg-ansi256-012 { fill: #5555FF }
+    .fg-magenta { fill: #AA00AA }
+    .container {
+      padding: 0 10px;
+      line-height: 18px;
+    }
+    .bold { font-weight: bold; }
+    tspan {
+      font: 14px SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;
+      white-space: pre;
+      line-height: 18px;
+    }
+  </style>
+
+  <rect width="100%" height="100%" y="0" rx="4.5" class="bg" />
+
+  <text xml:space="preserve" class="container fg">
+    <tspan x="10px" y="28px"><tspan class="fg-ansi256-009 bold">error[E0277]</tspan><tspan class="bold">: the trait bound `Struct: Foo&lt;i32&gt;` is not satisfied</tspan>
+</tspan>
+    <tspan x="10px" y="46px"><tspan>  </tspan><tspan class="fg-ansi256-012 bold">--&gt; </tspan><tspan>$DIR/highlight-difference-between-expected-trait-and-found-trait.rs:16:13</tspan>
+</tspan>
+    <tspan x="10px" y="64px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan>
+</tspan>
+    <tspan x="10px" y="82px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> fn foo() -&gt; impl Foo&lt;i32&gt; {</tspan>
+</tspan>
+    <tspan x="10px" y="100px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan>             </tspan><tspan class="fg-ansi256-009 bold">^^^^^^^^^^^^^</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">the trait `Bar&lt;i32&gt;` is not implemented for `Struct`, which is required by `Struct: Foo&lt;i32&gt;`</tspan>
+</tspan>
+    <tspan x="10px" y="118px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan>
+</tspan>
+    <tspan x="10px" y="136px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">help</tspan><tspan>: the trait `Bar&lt;()&gt;` </tspan><tspan class="fg-magenta bold">is</tspan><tspan> implemented for `Struct`</tspan>
+</tspan>
+    <tspan x="10px" y="154px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">help</tspan><tspan>: for that trait implementation, expected `</tspan><tspan class="fg-magenta bold">()</tspan><tspan>`, found `</tspan><tspan class="fg-magenta bold">i32</tspan><tspan>`</tspan>
+</tspan>
+    <tspan x="10px" y="172px"><tspan class="fg-ansi256-010 bold">note</tspan><tspan>: required for `Struct` to implement `Foo&lt;i32&gt;`</tspan>
+</tspan>
+    <tspan x="10px" y="190px"><tspan>  </tspan><tspan class="fg-ansi256-012 bold">--&gt; </tspan><tspan>$DIR/highlight-difference-between-expected-trait-and-found-trait.rs:11:12</tspan>
+</tspan>
+    <tspan x="10px" y="208px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan>
+</tspan>
+    <tspan x="10px" y="226px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> impl&lt;T, K&gt; Foo&lt;K&gt; for T where T: Bar&lt;K&gt;</tspan>
+</tspan>
+    <tspan x="10px" y="244px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan>            </tspan><tspan class="fg-ansi256-010 bold">^^^^^^</tspan><tspan>     </tspan><tspan class="fg-ansi256-010 bold">^</tspan><tspan>          </tspan><tspan class="fg-ansi256-012 bold">------</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">unsatisfied trait bound introduced here</tspan>
+</tspan>
+    <tspan x="10px" y="262px">
+</tspan>
+    <tspan x="10px" y="280px"><tspan class="fg-ansi256-009 bold">error</tspan><tspan class="bold">: aborting due to 1 previous error</tspan>
+</tspan>
+    <tspan x="10px" y="298px">
+</tspan>
+    <tspan x="10px" y="316px"><tspan class="bold">For more information about this error, try `rustc --explain E0277`.</tspan>
+</tspan>
+    <tspan x="10px" y="334px">
+</tspan>
+  </text>
+
+</svg>
diff --git a/tests/ui/impl-trait/impl_trait_projections.rs b/tests/ui/impl-trait/impl_trait_projections.rs
index 365ac85..2c277ae 100644
--- a/tests/ui/impl-trait/impl_trait_projections.rs
+++ b/tests/ui/impl-trait/impl_trait_projections.rs
@@ -10,30 +10,27 @@
 }
 
 fn projection_is_disallowed(x: impl Iterator) -> <impl Iterator>::Item {
-//~^ ERROR `impl Trait` is not allowed in path parameters
-//~| ERROR `impl Trait` is not allowed in path parameters
+//~^ ERROR `impl Trait` is not allowed in paths
     x.next().unwrap()
 }
 
 fn projection_with_named_trait_is_disallowed(mut x: impl Iterator)
     -> <impl Iterator as Iterator>::Item
-//~^ ERROR `impl Trait` is not allowed in path parameters
+//~^ ERROR `impl Trait` is not allowed in paths
 {
     x.next().unwrap()
 }
 
 fn projection_with_named_trait_inside_path_is_disallowed()
     -> <::std::ops::Range<impl Debug> as Iterator>::Item
-//~^ ERROR `impl Trait` is not allowed in path parameters
-//~| ERROR `impl Debug: Step` is not satisfied
+//~^ ERROR `impl Trait` is not allowed in paths
 {
-    //~^ ERROR `impl Debug: Step` is not satisfied
     (1i32..100).next().unwrap()
 }
 
 fn projection_from_impl_trait_inside_dyn_trait_is_disallowed()
     -> <dyn Iterator<Item = impl Debug> as Iterator>::Item
-//~^ ERROR `impl Trait` is not allowed in path parameters
+//~^ ERROR `impl Trait` is not allowed in paths
 {
     panic!()
 }
diff --git a/tests/ui/impl-trait/impl_trait_projections.stderr b/tests/ui/impl-trait/impl_trait_projections.stderr
index d62e3ac..5e0b80f 100644
--- a/tests/ui/impl-trait/impl_trait_projections.stderr
+++ b/tests/ui/impl-trait/impl_trait_projections.stderr
@@ -1,73 +1,35 @@
-error[E0667]: `impl Trait` is not allowed in path parameters
+error[E0562]: `impl Trait` is not allowed in paths
   --> $DIR/impl_trait_projections.rs:12:51
    |
 LL | fn projection_is_disallowed(x: impl Iterator) -> <impl Iterator>::Item {
    |                                                   ^^^^^^^^^^^^^
+   |
+   = note: `impl Trait` is only allowed in arguments and return types of functions and methods
 
-error[E0667]: `impl Trait` is not allowed in path parameters
-  --> $DIR/impl_trait_projections.rs:19:9
+error[E0562]: `impl Trait` is not allowed in paths
+  --> $DIR/impl_trait_projections.rs:18:9
    |
 LL |     -> <impl Iterator as Iterator>::Item
    |         ^^^^^^^^^^^^^
+   |
+   = note: `impl Trait` is only allowed in arguments and return types of functions and methods
 
-error[E0667]: `impl Trait` is not allowed in path parameters
-  --> $DIR/impl_trait_projections.rs:26:27
+error[E0562]: `impl Trait` is not allowed in paths
+  --> $DIR/impl_trait_projections.rs:25:27
    |
 LL |     -> <::std::ops::Range<impl Debug> as Iterator>::Item
    |                           ^^^^^^^^^^
+   |
+   = note: `impl Trait` is only allowed in arguments and return types of functions and methods
 
-error[E0667]: `impl Trait` is not allowed in path parameters
-  --> $DIR/impl_trait_projections.rs:35:29
+error[E0562]: `impl Trait` is not allowed in paths
+  --> $DIR/impl_trait_projections.rs:32:29
    |
 LL |     -> <dyn Iterator<Item = impl Debug> as Iterator>::Item
    |                             ^^^^^^^^^^
-
-error[E0667]: `impl Trait` is not allowed in path parameters
-  --> $DIR/impl_trait_projections.rs:12:51
    |
-LL | fn projection_is_disallowed(x: impl Iterator) -> <impl Iterator>::Item {
-   |                                                   ^^^^^^^^^^^^^
+   = note: `impl Trait` is only allowed in arguments and return types of functions and methods
 
-error[E0277]: the trait bound `impl Debug: Step` is not satisfied
-  --> $DIR/impl_trait_projections.rs:26:8
-   |
-LL |     -> <::std::ops::Range<impl Debug> as Iterator>::Item
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Step` is not implemented for `impl Debug`, which is required by `std::ops::Range<impl Debug>: Iterator`
-   |
-   = help: the following other types implement trait `Step`:
-             Char
-             Ipv4Addr
-             Ipv6Addr
-             char
-             i128
-             i16
-             i32
-             i64
-           and 8 others
-   = note: required for `std::ops::Range<impl Debug>` to implement `Iterator`
+error: aborting due to 4 previous errors
 
-error[E0277]: the trait bound `impl Debug: Step` is not satisfied
-  --> $DIR/impl_trait_projections.rs:29:1
-   |
-LL | / {
-LL | |
-LL | |     (1i32..100).next().unwrap()
-LL | | }
-   | |_^ the trait `Step` is not implemented for `impl Debug`, which is required by `std::ops::Range<impl Debug>: Iterator`
-   |
-   = help: the following other types implement trait `Step`:
-             Char
-             Ipv4Addr
-             Ipv6Addr
-             char
-             i128
-             i16
-             i32
-             i64
-           and 8 others
-   = note: required for `std::ops::Range<impl Debug>` to implement `Iterator`
-
-error: aborting due to 7 previous errors
-
-Some errors have detailed explanations: E0277, E0667.
-For more information about an error, try `rustc --explain E0277`.
+For more information about this error, try `rustc --explain E0562`.
diff --git a/tests/ui/impl-trait/in-trait/bad-projection-from-opaque.rs b/tests/ui/impl-trait/in-trait/bad-projection-from-opaque.rs
new file mode 100644
index 0000000..c2c22cd
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/bad-projection-from-opaque.rs
@@ -0,0 +1,22 @@
+// issue: rust-lang/rust#126725
+
+trait Foo {
+    fn foo<'a>() -> <&'a impl Sized as Bar>::Output;
+    //~^ ERROR `impl Trait` is not allowed in paths
+}
+
+trait Bar {
+    type Output;
+}
+
+impl<'a> Bar for &'a () {
+    type Output = &'a i32;
+}
+
+impl Foo for () {
+    fn foo<'a>() -> <&'a Self as Bar>::Output {
+        &0
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/impl-trait/in-trait/bad-projection-from-opaque.stderr b/tests/ui/impl-trait/in-trait/bad-projection-from-opaque.stderr
new file mode 100644
index 0000000..bea7ccd
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/bad-projection-from-opaque.stderr
@@ -0,0 +1,11 @@
+error[E0562]: `impl Trait` is not allowed in paths
+  --> $DIR/bad-projection-from-opaque.rs:4:26
+   |
+LL |     fn foo<'a>() -> <&'a impl Sized as Bar>::Output;
+   |                          ^^^^^^^^^^
+   |
+   = note: `impl Trait` is only allowed in arguments and return types of functions and methods
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0562`.
diff --git a/tests/ui/impl-trait/issues/issue-57979-impl-trait-in-path.rs b/tests/ui/impl-trait/issues/issue-57979-impl-trait-in-path.rs
index c5ecd1c..9466668 100644
--- a/tests/ui/impl-trait/issues/issue-57979-impl-trait-in-path.rs
+++ b/tests/ui/impl-trait/issues/issue-57979-impl-trait-in-path.rs
@@ -6,7 +6,7 @@
 pub trait Bar { }
 pub trait Quux<T> { type Assoc; }
 pub fn demo(_: impl Quux<(), Assoc=<() as Quux<impl Bar>>::Assoc>) { }
-//~^ ERROR `impl Trait` is not allowed in path parameters
+//~^ ERROR `impl Trait` is not allowed in paths
 impl<T> Quux<T> for () { type Assoc = u32; }
 
 fn main() { }
diff --git a/tests/ui/impl-trait/issues/issue-57979-impl-trait-in-path.stderr b/tests/ui/impl-trait/issues/issue-57979-impl-trait-in-path.stderr
index 55f4778..25547df 100644
--- a/tests/ui/impl-trait/issues/issue-57979-impl-trait-in-path.stderr
+++ b/tests/ui/impl-trait/issues/issue-57979-impl-trait-in-path.stderr
@@ -1,9 +1,11 @@
-error[E0667]: `impl Trait` is not allowed in path parameters
+error[E0562]: `impl Trait` is not allowed in paths
   --> $DIR/issue-57979-impl-trait-in-path.rs:8:48
    |
 LL | pub fn demo(_: impl Quux<(), Assoc=<() as Quux<impl Bar>>::Assoc>) { }
    |                                                ^^^^^^^^
+   |
+   = note: `impl Trait` is only allowed in arguments and return types of functions and methods
 
 error: aborting due to 1 previous error
 
-For more information about this error, try `rustc --explain E0667`.
+For more information about this error, try `rustc --explain E0562`.
diff --git a/tests/ui/impl-trait/normalize-tait-in-const.stderr b/tests/ui/impl-trait/normalize-tait-in-const.stderr
index e0d193b..f914266 100644
--- a/tests/ui/impl-trait/normalize-tait-in-const.stderr
+++ b/tests/ui/impl-trait/normalize-tait-in-const.stderr
@@ -1,14 +1,30 @@
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/normalize-tait-in-const.rs:26:42
+  --> $DIR/normalize-tait-in-const.rs:26:35
    |
 LL | const fn with_positive<F: for<'a> ~const Fn(&'a Alias<'a>) + ~const Destruct>(fun: F) {
-   |                                          ^^^^^^^^^^^^^^^^^
+   |                                   ^^^^^^
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/normalize-tait-in-const.rs:26:69
+  --> $DIR/normalize-tait-in-const.rs:26:62
    |
 LL | const fn with_positive<F: for<'a> ~const Fn(&'a Alias<'a>) + ~const Destruct>(fun: F) {
-   |                                                                     ^^^^^^^^
+   |                                                              ^^^^^^
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/normalize-tait-in-const.rs:26:35
+   |
+LL | const fn with_positive<F: for<'a> ~const Fn(&'a Alias<'a>) + ~const Destruct>(fun: F) {
+   |                                   ^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/normalize-tait-in-const.rs:26:62
+   |
+LL | const fn with_positive<F: for<'a> ~const Fn(&'a Alias<'a>) + ~const Destruct>(fun: F) {
+   |                                                              ^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0015]: cannot call non-const closure in constant functions
   --> $DIR/normalize-tait-in-const.rs:27:5
@@ -21,10 +37,6 @@
    |
 LL | const fn with_positive<F: for<'a> ~const Fn(&'a Alias<'a>) + ~const Destruct + ~const Fn(&foo::Alias<'_>)>(fun: F) {
    |                                                                              ++++++++++++++++++++++++++++
-help: add `#![feature(effects)]` to the crate attributes to enable
-   |
-LL + #![feature(effects)]
-   |
 
 error[E0493]: destructor of `F` cannot be evaluated at compile-time
   --> $DIR/normalize-tait-in-const.rs:26:79
@@ -35,7 +47,7 @@
 LL | }
    | - value is dropped here
 
-error: aborting due to 4 previous errors
+error: aborting due to 6 previous errors
 
 Some errors have detailed explanations: E0015, E0493.
 For more information about an error, try `rustc --explain E0015`.
diff --git a/tests/ui/intrinsics/const-eval-select-stability.rs b/tests/ui/intrinsics/const-eval-select-stability.rs
index 575bc0c..25cbada 100644
--- a/tests/ui/intrinsics/const-eval-select-stability.rs
+++ b/tests/ui/intrinsics/const-eval-select-stability.rs
@@ -15,7 +15,7 @@
 #[rustc_const_stable(since = "1.0", feature = "const_hey")]
 pub const fn hey() {
     const_eval_select((), nothing, log);
-    //~^ ERROR `const_eval_select` is not yet stable as a const fn
+    //~^ ERROR cannot use `#[feature(const_eval_select)]`
 }
 
 fn main() {}
diff --git a/tests/ui/intrinsics/const-eval-select-stability.stderr b/tests/ui/intrinsics/const-eval-select-stability.stderr
index 335b987..5f443b1 100644
--- a/tests/ui/intrinsics/const-eval-select-stability.stderr
+++ b/tests/ui/intrinsics/const-eval-select-stability.stderr
@@ -1,10 +1,19 @@
-error: `const_eval_select` is not yet stable as a const fn
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(const_eval_select)]`
   --> $DIR/const-eval-select-stability.rs:17:5
    |
 LL |     const_eval_select((), nothing, log);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: const-stable functions can only call other const-stable functions
+help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do)
+   |
+LL + #[rustc_const_unstable(feature = "...", issue = "...")]
+LL | pub const fn hey() {
+   |
+help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
+   |
+LL + #[rustc_allow_const_fn_unstable(const_eval_select)]
+LL | pub const fn hey() {
+   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/invalid-compile-flags/regparm/regparm-valid-values.regparm4.stderr b/tests/ui/invalid-compile-flags/regparm/regparm-valid-values.regparm4.stderr
new file mode 100644
index 0000000..8fc04ad
--- /dev/null
+++ b/tests/ui/invalid-compile-flags/regparm/regparm-valid-values.regparm4.stderr
@@ -0,0 +1,4 @@
+error: `-Zregparm=4` is unsupported (valid values 0-3)
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/invalid-compile-flags/regparm/regparm-valid-values.rs b/tests/ui/invalid-compile-flags/regparm/regparm-valid-values.rs
new file mode 100644
index 0000000..b548d67
--- /dev/null
+++ b/tests/ui/invalid-compile-flags/regparm/regparm-valid-values.rs
@@ -0,0 +1,24 @@
+//@ revisions: regparm0 regparm1 regparm2 regparm3 regparm4
+
+//@ needs-llvm-components: x86
+//@ compile-flags: --target i686-unknown-linux-gnu
+
+//@[regparm0] check-pass
+//@[regparm0] compile-flags: -Zregparm=0
+
+//@[regparm1] check-pass
+//@[regparm1] compile-flags: -Zregparm=1
+
+//@[regparm2] check-pass
+//@[regparm2] compile-flags: -Zregparm=2
+
+//@[regparm3] check-pass
+//@[regparm3] compile-flags: -Zregparm=3
+
+//@[regparm4] check-fail
+//@[regparm4] compile-flags: -Zregparm=4
+//@[regparm4] error-pattern: `-Zregparm=4` is unsupported (valid values 0-3)
+
+#![feature(no_core)]
+#![no_core]
+#![no_main]
diff --git a/tests/ui/invalid-compile-flags/regparm/requires-x86.aarch64.stderr b/tests/ui/invalid-compile-flags/regparm/requires-x86.aarch64.stderr
new file mode 100644
index 0000000..2433519
--- /dev/null
+++ b/tests/ui/invalid-compile-flags/regparm/requires-x86.aarch64.stderr
@@ -0,0 +1,4 @@
+error: `-Zregparm=N` is only supported on x86
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/invalid-compile-flags/regparm/requires-x86.rs b/tests/ui/invalid-compile-flags/regparm/requires-x86.rs
new file mode 100644
index 0000000..ce6e437
--- /dev/null
+++ b/tests/ui/invalid-compile-flags/regparm/requires-x86.rs
@@ -0,0 +1,21 @@
+//@ revisions: x86 x86_64 aarch64
+
+//@ compile-flags: -Zregparm=3
+
+//@[x86] check-pass
+//@[x86] needs-llvm-components: x86
+//@[x86] compile-flags: --target i686-unknown-linux-gnu
+
+//@[x86_64] check-fail
+//@[x86_64] needs-llvm-components: x86
+//@[x86_64] compile-flags: --target x86_64-unknown-linux-gnu
+//@[x86_64] error-pattern: `-Zregparm=N` is only supported on x86
+
+//@[aarch64] check-fail
+//@[aarch64] needs-llvm-components: aarch64
+//@[aarch64] compile-flags: --target aarch64-unknown-linux-gnu
+//@[aarch64] error-pattern: `-Zregparm=N` is only supported on x86
+
+#![feature(no_core)]
+#![no_core]
+#![no_main]
diff --git a/tests/ui/invalid-compile-flags/regparm/requires-x86.x86_64.stderr b/tests/ui/invalid-compile-flags/regparm/requires-x86.x86_64.stderr
new file mode 100644
index 0000000..2433519
--- /dev/null
+++ b/tests/ui/invalid-compile-flags/regparm/requires-x86.x86_64.stderr
@@ -0,0 +1,4 @@
+error: `-Zregparm=N` is only supported on x86
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/issues/issue-25901.stderr b/tests/ui/issues/issue-25901.stderr
index 3fedfd9..bcbc805 100644
--- a/tests/ui/issues/issue-25901.stderr
+++ b/tests/ui/issues/issue-25901.stderr
@@ -17,10 +17,6 @@
    | ^^^^^^^^^^^^^^^^
    = note: calls in statics are limited to constant functions, tuple structs and tuple variants
    = note: consider wrapping this expression in `std::sync::LazyLock::new(|| ...)`
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/lifetimes/refcell-in-tail-expr.edition2021.stderr b/tests/ui/lifetimes/refcell-in-tail-expr.edition2021.stderr
index 858be42..157a1c5 100644
--- a/tests/ui/lifetimes/refcell-in-tail-expr.edition2021.stderr
+++ b/tests/ui/lifetimes/refcell-in-tail-expr.edition2021.stderr
@@ -1,5 +1,5 @@
 error[E0597]: `cell` does not live long enough
-  --> $DIR/refcell-in-tail-expr.rs:12:27
+  --> $DIR/refcell-in-tail-expr.rs:10:27
    |
 LL |     let cell = std::cell::RefCell::new(0u8);
    |         ---- binding `cell` declared here
diff --git a/tests/ui/lifetimes/refcell-in-tail-expr.rs b/tests/ui/lifetimes/refcell-in-tail-expr.rs
index b1814c1..595e951 100644
--- a/tests/ui/lifetimes/refcell-in-tail-expr.rs
+++ b/tests/ui/lifetimes/refcell-in-tail-expr.rs
@@ -4,8 +4,6 @@
 //@ [edition2024] compile-flags: -Zunstable-options
 //@ [edition2024] check-pass
 
-#![cfg_attr(edition2024, feature(shorter_tail_lifetimes))]
-
 fn main() {
     let cell = std::cell::RefCell::new(0u8);
 
diff --git a/tests/ui/lifetimes/shorter-tail-expr-lifetime.edition2021.stderr b/tests/ui/lifetimes/shorter-tail-expr-lifetime.edition2021.stderr
index ad28ae2..3c074c5 100644
--- a/tests/ui/lifetimes/shorter-tail-expr-lifetime.edition2021.stderr
+++ b/tests/ui/lifetimes/shorter-tail-expr-lifetime.edition2021.stderr
@@ -1,5 +1,5 @@
 error[E0597]: `c` does not live long enough
-  --> $DIR/shorter-tail-expr-lifetime.rs:10:5
+  --> $DIR/shorter-tail-expr-lifetime.rs:8:5
    |
 LL |     let c = std::cell::RefCell::new("..");
    |         - binding `c` declared here
diff --git a/tests/ui/lifetimes/shorter-tail-expr-lifetime.rs b/tests/ui/lifetimes/shorter-tail-expr-lifetime.rs
index 0392b6c..4195a8b 100644
--- a/tests/ui/lifetimes/shorter-tail-expr-lifetime.rs
+++ b/tests/ui/lifetimes/shorter-tail-expr-lifetime.rs
@@ -3,8 +3,6 @@
 //@ [edition2024] edition: 2024
 //@ [edition2024] run-pass
 
-#![cfg_attr(edition2024, feature(shorter_tail_lifetimes))]
-
 fn f() -> usize {
     let c = std::cell::RefCell::new("..");
     c.borrow().len() //[edition2021]~ ERROR: `c` does not live long enough
diff --git a/tests/ui/lifetimes/tail-expr-in-nested-expr.rs b/tests/ui/lifetimes/tail-expr-in-nested-expr.rs
index a8989f2..2ac97af 100644
--- a/tests/ui/lifetimes/tail-expr-in-nested-expr.rs
+++ b/tests/ui/lifetimes/tail-expr-in-nested-expr.rs
@@ -1,8 +1,6 @@
 //@ edition: 2024
 //@ compile-flags: -Zunstable-options
 
-#![feature(shorter_tail_lifetimes)]
-
 fn main() {
     let _ = { String::new().as_str() }.len();
     //~^ ERROR temporary value dropped while borrowed
diff --git a/tests/ui/lifetimes/tail-expr-in-nested-expr.stderr b/tests/ui/lifetimes/tail-expr-in-nested-expr.stderr
index f699d18..96e88ea 100644
--- a/tests/ui/lifetimes/tail-expr-in-nested-expr.stderr
+++ b/tests/ui/lifetimes/tail-expr-in-nested-expr.stderr
@@ -1,5 +1,5 @@
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/tail-expr-in-nested-expr.rs:7:15
+  --> $DIR/tail-expr-in-nested-expr.rs:5:15
    |
 LL |     let _ = { String::new().as_str() }.len();
    |               ^^^^^^^^^^^^^---------
diff --git a/tests/ui/lifetimes/tail-expr-lock-poisoning.rs b/tests/ui/lifetimes/tail-expr-lock-poisoning.rs
index cdfd353..ec74596 100644
--- a/tests/ui/lifetimes/tail-expr-lock-poisoning.rs
+++ b/tests/ui/lifetimes/tail-expr-lock-poisoning.rs
@@ -4,7 +4,6 @@
 //@ [edition2024] edition: 2024
 //@ run-pass
 //@ needs-unwind
-#![cfg_attr(edition2024, feature(shorter_tail_lifetimes))]
 
 use std::sync::Mutex;
 
diff --git a/tests/ui/linkage-attr/framework.omit.stderr b/tests/ui/linkage-attr/framework.omit.stderr
deleted file mode 100644
index 23e017c..0000000
--- a/tests/ui/linkage-attr/framework.omit.stderr
+++ /dev/null
@@ -1,8 +0,0 @@
-error: linking with `LINKER` failed: exit status: 1
-   |
-           ld: Undefined symbols:
-             _CFRunLoopGetTypeID, referenced from:
-           clang: error: linker command failed with exit code 1 (use -v to see invocation)
-
-
-error: aborting due to 1 previous error
diff --git a/tests/ui/linkage-attr/framework.rs b/tests/ui/linkage-attr/framework.rs
deleted file mode 100644
index 08f4394..0000000
--- a/tests/ui/linkage-attr/framework.rs
+++ /dev/null
@@ -1,32 +0,0 @@
-// Check that linking frameworks on Apple platforms works.
-//@ only-apple
-//@ revisions: omit link weak both
-//@ [omit]build-fail
-//@ [link]run-pass
-//@ [weak]run-pass
-//@ [both]run-pass
-
-// The linker's exact error output changes between Xcode versions, depends on
-// linker invocation details, and the linker sometimes outputs more warnings.
-//@ compare-output-lines-by-subset
-//@ normalize-stderr-test: "linking with `.*` failed" -> "linking with `LINKER` failed"
-//@ normalize-stderr-test: "Undefined symbols for architecture .*" -> "ld: Undefined symbols:"
-//@ normalize-stderr-test: "._CFRunLoopGetTypeID.," -> "_CFRunLoopGetTypeID,"
-
-#![cfg_attr(any(weak, both), feature(link_arg_attribute))]
-
-#[cfg_attr(any(link, both), link(name = "CoreFoundation", kind = "framework"))]
-#[cfg_attr(
-    any(weak, both),
-    link(name = "-weak_framework", kind = "link-arg", modifiers = "+verbatim"),
-    link(name = "CoreFoundation", kind = "link-arg", modifiers = "+verbatim")
-)]
-extern "C" {
-    fn CFRunLoopGetTypeID() -> core::ffi::c_ulong;
-}
-
-pub fn main() {
-    unsafe {
-        CFRunLoopGetTypeID();
-    }
-}
diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/allow.rs b/tests/ui/lint/dangling-pointers-from-temporaries/allow.rs
new file mode 100644
index 0000000..d892ebd
--- /dev/null
+++ b/tests/ui/lint/dangling-pointers-from-temporaries/allow.rs
@@ -0,0 +1,23 @@
+#![allow(dangling_pointers_from_temporaries)]
+
+fn main() {
+    dbg!(String::new().as_ptr());
+    // ^ no error
+
+    #[deny(dangling_pointers_from_temporaries)]
+    {
+        dbg!(String::new().as_ptr());
+        //~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped
+    }
+    S.foo()
+}
+
+struct S;
+
+impl S {
+    #[warn(dangling_pointers_from_temporaries)]
+    fn foo(self) {
+        dbg!(String::new().as_ptr());
+        //~^ WARNING a dangling pointer will be produced because the temporary `String` will be dropped
+    }
+}
diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/allow.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/allow.stderr
new file mode 100644
index 0000000..fd434ea
--- /dev/null
+++ b/tests/ui/lint/dangling-pointers-from-temporaries/allow.stderr
@@ -0,0 +1,34 @@
+error: a dangling pointer will be produced because the temporary `String` will be dropped
+  --> $DIR/allow.rs:9:28
+   |
+LL |         dbg!(String::new().as_ptr());
+   |              ------------- ^^^^^^ this pointer will immediately be invalid
+   |              |
+   |              this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+   |
+   = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+note: the lint level is defined here
+  --> $DIR/allow.rs:7:12
+   |
+LL |     #[deny(dangling_pointers_from_temporaries)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: a dangling pointer will be produced because the temporary `String` will be dropped
+  --> $DIR/allow.rs:20:28
+   |
+LL |         dbg!(String::new().as_ptr());
+   |              ------------- ^^^^^^ this pointer will immediately be invalid
+   |              |
+   |              this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+   |
+   = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+note: the lint level is defined here
+  --> $DIR/allow.rs:18:12
+   |
+LL |     #[warn(dangling_pointers_from_temporaries)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error; 1 warning emitted
+
diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/calls.rs b/tests/ui/lint/dangling-pointers-from-temporaries/calls.rs
new file mode 100644
index 0000000..b376582
--- /dev/null
+++ b/tests/ui/lint/dangling-pointers-from-temporaries/calls.rs
@@ -0,0 +1,52 @@
+#![deny(dangling_pointers_from_temporaries)]
+
+use std::ffi::{c_char, CString};
+
+fn cstring() -> CString {
+    CString::new("hello").unwrap()
+}
+
+fn consume(ptr: *const c_char) {
+    let c = unsafe { ptr.read() };
+    dbg!(c);
+}
+
+// None of these should trigger the lint.
+fn ok() {
+    consume(cstring().as_ptr());
+    consume({ cstring() }.as_ptr());
+    consume({ cstring().as_ptr() });
+    consume(cstring().as_ptr().cast());
+    consume({ cstring() }.as_ptr().cast());
+    consume({ cstring().as_ptr() }.cast());
+}
+
+// All of these should trigger the lint.
+fn not_ok() {
+    {
+        let ptr = cstring().as_ptr();
+        //~^ ERROR a dangling pointer will be produced because the temporary `CString` will be dropped
+        consume(ptr);
+    }
+    consume({
+        let ptr = cstring().as_ptr();
+        //~^ ERROR a dangling pointer will be produced because the temporary `CString` will be dropped
+        ptr
+    });
+    consume({
+        let s = cstring();
+        s.as_ptr()
+        //^ FIXME: should error
+    });
+    let _ptr: *const u8 = cstring().as_ptr().cast();
+    //~^ ERROR a dangling pointer will be produced because the temporary `CString` will be dropped
+    let _ptr: *const u8 = { cstring() }.as_ptr().cast();
+    //~^ ERROR a dangling pointer will be produced because the temporary `CString` will be dropped
+    let _ptr: *const u8 = { cstring().as_ptr() }.cast();
+    //~^ ERROR a dangling pointer will be produced because the temporary `CString` will be dropped
+}
+
+fn main() {
+    ok();
+    not_ok();
+}
diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/calls.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/calls.stderr
new file mode 100644
index 0000000..d1615b7
--- /dev/null
+++ b/tests/ui/lint/dangling-pointers-from-temporaries/calls.stderr
@@ -0,0 +1,62 @@
+error: a dangling pointer will be produced because the temporary `CString` will be dropped
+  --> $DIR/calls.rs:27:29
+   |
+LL |         let ptr = cstring().as_ptr();
+   |                   --------- ^^^^^^ this pointer will immediately be invalid
+   |                   |
+   |                   this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+   |
+   = note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+note: the lint level is defined here
+  --> $DIR/calls.rs:1:9
+   |
+LL | #![deny(dangling_pointers_from_temporaries)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: a dangling pointer will be produced because the temporary `CString` will be dropped
+  --> $DIR/calls.rs:32:29
+   |
+LL |         let ptr = cstring().as_ptr();
+   |                   --------- ^^^^^^ this pointer will immediately be invalid
+   |                   |
+   |                   this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+   |
+   = note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: a dangling pointer will be produced because the temporary `CString` will be dropped
+  --> $DIR/calls.rs:41:37
+   |
+LL |     let _ptr: *const u8 = cstring().as_ptr().cast();
+   |                           --------- ^^^^^^ this pointer will immediately be invalid
+   |                           |
+   |                           this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+   |
+   = note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: a dangling pointer will be produced because the temporary `CString` will be dropped
+  --> $DIR/calls.rs:43:41
+   |
+LL |     let _ptr: *const u8 = { cstring() }.as_ptr().cast();
+   |                           ------------- ^^^^^^ this pointer will immediately be invalid
+   |                           |
+   |                           this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+   |
+   = note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: a dangling pointer will be produced because the temporary `CString` will be dropped
+  --> $DIR/calls.rs:45:39
+   |
+LL |     let _ptr: *const u8 = { cstring().as_ptr() }.cast();
+   |                             --------- ^^^^^^ this pointer will immediately be invalid
+   |                             |
+   |                             this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+   |
+   = note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: aborting due to 5 previous errors
+
diff --git a/tests/ui/lint/lint-temporary-cstring-as-param.rs b/tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-param.rs
similarity index 62%
rename from tests/ui/lint/lint-temporary-cstring-as-param.rs
rename to tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-param.rs
index 9f58053..fb6ed36 100644
--- a/tests/ui/lint/lint-temporary-cstring-as-param.rs
+++ b/tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-param.rs
@@ -1,4 +1,7 @@
+//@ check-pass
+
 #![deny(temporary_cstring_as_ptr)]
+//~^ WARNING lint `temporary_cstring_as_ptr` has been renamed to `dangling_pointers_from_temporaries`
 
 use std::ffi::CString;
 use std::os::raw::c_char;
@@ -7,5 +10,4 @@
 
 fn main() {
     some_function(CString::new("").unwrap().as_ptr());
-    //~^ ERROR getting the inner pointer of a temporary `CString`
 }
diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-param.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-param.stderr
new file mode 100644
index 0000000..dd54b49
--- /dev/null
+++ b/tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-param.stderr
@@ -0,0 +1,10 @@
+warning: lint `temporary_cstring_as_ptr` has been renamed to `dangling_pointers_from_temporaries`
+  --> $DIR/cstring-as-param.rs:3:9
+   |
+LL | #![deny(temporary_cstring_as_ptr)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `dangling_pointers_from_temporaries`
+   |
+   = note: `#[warn(renamed_and_removed_lints)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-ptr.rs b/tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-ptr.rs
new file mode 100644
index 0000000..a983787
--- /dev/null
+++ b/tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-ptr.rs
@@ -0,0 +1,18 @@
+// this program is not technically incorrect, but is an obscure enough style to be worth linting
+#![deny(temporary_cstring_as_ptr)]
+//~^ WARNING lint `temporary_cstring_as_ptr` has been renamed to `dangling_pointers_from_temporaries`
+
+use std::ffi::CString;
+
+macro_rules! mymacro {
+    () => {
+        let s = CString::new("some text").unwrap().as_ptr();
+        //~^ ERROR a dangling pointer will be produced because the temporary `CString` will be dropped
+    }
+}
+
+fn main() {
+    let s = CString::new("some text").unwrap().as_ptr();
+    //~^ ERROR a dangling pointer will be produced because the temporary `CString` will be dropped
+    mymacro!();
+}
diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-ptr.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-ptr.stderr
new file mode 100644
index 0000000..5289fbb
--- /dev/null
+++ b/tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-ptr.stderr
@@ -0,0 +1,41 @@
+warning: lint `temporary_cstring_as_ptr` has been renamed to `dangling_pointers_from_temporaries`
+  --> $DIR/cstring-as-ptr.rs:2:9
+   |
+LL | #![deny(temporary_cstring_as_ptr)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `dangling_pointers_from_temporaries`
+   |
+   = note: `#[warn(renamed_and_removed_lints)]` on by default
+
+error: a dangling pointer will be produced because the temporary `CString` will be dropped
+  --> $DIR/cstring-as-ptr.rs:15:48
+   |
+LL |     let s = CString::new("some text").unwrap().as_ptr();
+   |             ---------------------------------- ^^^^^^ this pointer will immediately be invalid
+   |             |
+   |             this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+   |
+   = note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+note: the lint level is defined here
+  --> $DIR/cstring-as-ptr.rs:2:9
+   |
+LL | #![deny(temporary_cstring_as_ptr)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: a dangling pointer will be produced because the temporary `CString` will be dropped
+  --> $DIR/cstring-as-ptr.rs:9:52
+   |
+LL |         let s = CString::new("some text").unwrap().as_ptr();
+   |                 ---------------------------------- ^^^^^^ this pointer will immediately be invalid
+   |                 |
+   |                 this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+...
+LL |     mymacro!();
+   |     ---------- in this macro invocation
+   |
+   = note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+   = note: this error originates in the macro `mymacro` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 2 previous errors; 1 warning emitted
+
diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/emacs.rs b/tests/ui/lint/dangling-pointers-from-temporaries/emacs.rs
new file mode 100644
index 0000000..b9b7bd3
--- /dev/null
+++ b/tests/ui/lint/dangling-pointers-from-temporaries/emacs.rs
@@ -0,0 +1,19 @@
+//@ check-pass
+
+#![deny(dangling_pointers_from_temporaries)]
+
+// The original code example comes from bindgen-produced code for emacs.
+// Hence the name of the test.
+// https://github.com/rust-lang/rust/pull/128985#issuecomment-2338951363
+
+use std::ffi::{c_char, CString};
+
+fn read(ptr: *const c_char) -> c_char {
+    unsafe { ptr.read() }
+}
+
+fn main() {
+    let fnptr: Option<fn(ptr: *const c_char) -> c_char> = Some(read);
+    let x = fnptr.unwrap()(CString::new("foo").unwrap().as_ptr());
+    assert_eq!(x as u8, b'f');
+}
diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/example-from-issue123613.rs b/tests/ui/lint/dangling-pointers-from-temporaries/example-from-issue123613.rs
new file mode 100644
index 0000000..0fb07a3
--- /dev/null
+++ b/tests/ui/lint/dangling-pointers-from-temporaries/example-from-issue123613.rs
@@ -0,0 +1,13 @@
+#![deny(dangling_pointers_from_temporaries)]
+
+const MAX_PATH: usize = 260;
+fn main() {
+    let str1 = String::with_capacity(MAX_PATH).as_mut_ptr();
+    //~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped
+    let str2 = String::from("TotototototototototototototototototoT").as_ptr();
+    //~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped
+    unsafe {
+        std::ptr::copy_nonoverlapping(str2, str1, 30);
+        println!("{:?}", String::from_raw_parts(str1, 30, 30));
+    }
+}
diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/example-from-issue123613.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/example-from-issue123613.stderr
new file mode 100644
index 0000000..0de794f
--- /dev/null
+++ b/tests/ui/lint/dangling-pointers-from-temporaries/example-from-issue123613.stderr
@@ -0,0 +1,29 @@
+error: a dangling pointer will be produced because the temporary `String` will be dropped
+  --> $DIR/example-from-issue123613.rs:5:48
+   |
+LL |     let str1 = String::with_capacity(MAX_PATH).as_mut_ptr();
+   |                ------------------------------- ^^^^^^^^^^ this pointer will immediately be invalid
+   |                |
+   |                this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+   |
+   = note: pointers do not have a lifetime; when calling `as_mut_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+note: the lint level is defined here
+  --> $DIR/example-from-issue123613.rs:1:9
+   |
+LL | #![deny(dangling_pointers_from_temporaries)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: a dangling pointer will be produced because the temporary `String` will be dropped
+  --> $DIR/example-from-issue123613.rs:7:70
+   |
+LL |     let str2 = String::from("TotototototototototototototototototoT").as_ptr();
+   |                ----------------------------------------------------- ^^^^^^ this pointer will immediately be invalid
+   |                |
+   |                this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+   |
+   = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/ext.rs b/tests/ui/lint/dangling-pointers-from-temporaries/ext.rs
new file mode 100644
index 0000000..a5e84d3
--- /dev/null
+++ b/tests/ui/lint/dangling-pointers-from-temporaries/ext.rs
@@ -0,0 +1,32 @@
+#![deny(dangling_pointers_from_temporaries)]
+
+use std::fmt::Debug;
+
+trait Ext1 {
+    fn dbg(self) -> Self
+    where
+        Self: Sized + Debug,
+    {
+        dbg!(&self);
+        self
+    }
+}
+
+impl<T> Ext1 for *const T {}
+
+trait Ext2 {
+    fn foo(self);
+}
+
+impl Ext2 for *const u32 {
+    fn foo(self) {
+        dbg!(unsafe { self.read() });
+    }
+}
+
+fn main() {
+    let _ptr1 = Vec::<u32>::new().as_ptr().dbg();
+    //~^ ERROR a dangling pointer will be produced because the temporary `Vec<u32>` will be dropped
+    let _ptr2 = vec![0].as_ptr().foo();
+    //~^ ERROR a dangling pointer will be produced because the temporary `Vec<u32>` will be dropped
+}
diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/ext.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/ext.stderr
new file mode 100644
index 0000000..5d401c8
--- /dev/null
+++ b/tests/ui/lint/dangling-pointers-from-temporaries/ext.stderr
@@ -0,0 +1,29 @@
+error: a dangling pointer will be produced because the temporary `Vec<u32>` will be dropped
+  --> $DIR/ext.rs:28:35
+   |
+LL |     let _ptr1 = Vec::<u32>::new().as_ptr().dbg();
+   |                 ----------------- ^^^^^^ this pointer will immediately be invalid
+   |                 |
+   |                 this `Vec<u32>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+   |
+   = note: pointers do not have a lifetime; when calling `as_ptr` the `Vec<u32>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+note: the lint level is defined here
+  --> $DIR/ext.rs:1:9
+   |
+LL | #![deny(dangling_pointers_from_temporaries)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: a dangling pointer will be produced because the temporary `Vec<u32>` will be dropped
+  --> $DIR/ext.rs:30:25
+   |
+LL |     let _ptr2 = vec![0].as_ptr().foo();
+   |                 ------- ^^^^^^ this pointer will immediately be invalid
+   |                 |
+   |                 this `Vec<u32>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+   |
+   = note: pointers do not have a lifetime; when calling `as_ptr` the `Vec<u32>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/methods.rs b/tests/ui/lint/dangling-pointers-from-temporaries/methods.rs
new file mode 100644
index 0000000..26019b3
--- /dev/null
+++ b/tests/ui/lint/dangling-pointers-from-temporaries/methods.rs
@@ -0,0 +1,8 @@
+#![deny(dangling_pointers_from_temporaries)]
+
+fn main() {
+    vec![0u8].as_ptr();
+    //~^ ERROR a dangling pointer will be produced because the temporary `Vec<u8>` will be dropped
+    vec![0u8].as_mut_ptr();
+    //~^ ERROR a dangling pointer will be produced because the temporary `Vec<u8>` will be dropped
+}
diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/methods.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/methods.stderr
new file mode 100644
index 0000000..11c052c
--- /dev/null
+++ b/tests/ui/lint/dangling-pointers-from-temporaries/methods.stderr
@@ -0,0 +1,29 @@
+error: a dangling pointer will be produced because the temporary `Vec<u8>` will be dropped
+  --> $DIR/methods.rs:4:15
+   |
+LL |     vec![0u8].as_ptr();
+   |     --------- ^^^^^^ this pointer will immediately be invalid
+   |     |
+   |     this `Vec<u8>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+   |
+   = note: pointers do not have a lifetime; when calling `as_ptr` the `Vec<u8>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+note: the lint level is defined here
+  --> $DIR/methods.rs:1:9
+   |
+LL | #![deny(dangling_pointers_from_temporaries)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: a dangling pointer will be produced because the temporary `Vec<u8>` will be dropped
+  --> $DIR/methods.rs:6:15
+   |
+LL |     vec![0u8].as_mut_ptr();
+   |     --------- ^^^^^^^^^^ this pointer will immediately be invalid
+   |     |
+   |     this `Vec<u8>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+   |
+   = note: pointers do not have a lifetime; when calling `as_mut_ptr` the `Vec<u8>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/temporaries.rs b/tests/ui/lint/dangling-pointers-from-temporaries/temporaries.rs
new file mode 100644
index 0000000..1f21658
--- /dev/null
+++ b/tests/ui/lint/dangling-pointers-from-temporaries/temporaries.rs
@@ -0,0 +1,136 @@
+#![allow(unused)]
+#![deny(dangling_pointers_from_temporaries)]
+
+fn string() -> String {
+    "hello".into()
+}
+
+struct Wrapper(String);
+
+fn main() {
+    // ConstBlock
+    const { String::new() }.as_ptr();
+
+    // Array
+    {
+        [string()].as_ptr(); // False negative
+        [true].as_ptr();
+    }
+
+    // Call
+    string().as_ptr();
+    //~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped
+
+    // MethodCall
+    "hello".to_string().as_ptr();
+    //~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped
+
+    // Tup
+    // impossible
+
+    // Binary
+    (string() + "hello").as_ptr();
+    //~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped
+
+    // Path
+    {
+        let x = string();
+        x.as_ptr();
+    }
+
+    // Unary
+    {
+        let x = string();
+        let x: &String = &x;
+        (*x).as_ptr();
+        (&[0u8]).as_ptr();
+        (&string()).as_ptr(); // False negative
+        (*&string()).as_ptr(); // False negative
+    }
+
+    // Lit
+    "hello".as_ptr();
+
+    // Cast
+    // impossible
+
+    // Type
+    // impossible
+
+    // DropTemps
+    // impossible
+
+    // Let
+    // impossible
+
+    // If
+    {
+        (if true { String::new() } else { "hello".into() }).as_ptr();
+        //~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped
+    }
+
+    // Loop
+    {
+        (loop {
+            break String::new();
+        })
+        .as_ptr();
+        //~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped
+    }
+
+    // Match
+    {
+        match string() {
+            s => s,
+        }
+        .as_ptr();
+        //~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped
+    }
+
+    // Closure
+    // impossible
+
+    // Block
+    { string() }.as_ptr();
+    //~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped
+
+    // Assign, AssignOp
+    // impossible
+
+    // Field
+    {
+        Wrapper(string()).0.as_ptr(); // False negative
+        let x = Wrapper(string());
+        x.0.as_ptr();
+    }
+
+    // Index
+    {
+        vec![string()][0].as_ptr(); // False negative
+        let x = vec![string()];
+        x[0].as_ptr();
+    }
+
+    // AddrOf, InlineAsm, OffsetOf
+    // impossible
+
+    // Break, Continue, Ret
+    // are !
+
+    // Become, Yield
+    // unstable, are !
+
+    // Repeat
+    [0u8; 100].as_ptr();
+    [const { String::new() }; 100].as_ptr();
+
+    // Struct
+    // Cannot test this without access to private fields of the linted types.
+
+    // Err
+    // impossible
+
+    // Macro
+    vec![0u8].as_ptr();
+    //~^ ERROR a dangling pointer will be produced because the temporary `Vec<u8>` will be dropped
+}
diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/temporaries.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/temporaries.stderr
new file mode 100644
index 0000000..d2e9ac8
--- /dev/null
+++ b/tests/ui/lint/dangling-pointers-from-temporaries/temporaries.stderr
@@ -0,0 +1,99 @@
+error: a dangling pointer will be produced because the temporary `String` will be dropped
+  --> $DIR/temporaries.rs:21:14
+   |
+LL |     string().as_ptr();
+   |     -------- ^^^^^^ this pointer will immediately be invalid
+   |     |
+   |     this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+   |
+   = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+note: the lint level is defined here
+  --> $DIR/temporaries.rs:2:9
+   |
+LL | #![deny(dangling_pointers_from_temporaries)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: a dangling pointer will be produced because the temporary `String` will be dropped
+  --> $DIR/temporaries.rs:25:25
+   |
+LL |     "hello".to_string().as_ptr();
+   |     ------------------- ^^^^^^ this pointer will immediately be invalid
+   |     |
+   |     this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+   |
+   = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: a dangling pointer will be produced because the temporary `String` will be dropped
+  --> $DIR/temporaries.rs:32:26
+   |
+LL |     (string() + "hello").as_ptr();
+   |     -------------------- ^^^^^^ this pointer will immediately be invalid
+   |     |
+   |     this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+   |
+   = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: a dangling pointer will be produced because the temporary `String` will be dropped
+  --> $DIR/temporaries.rs:68:61
+   |
+LL |         (if true { String::new() } else { "hello".into() }).as_ptr();
+   |         --------------------------------------------------- ^^^^^^ this pointer will immediately be invalid
+   |         |
+   |         this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+   |
+   = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: a dangling pointer will be produced because the temporary `String` will be dropped
+  --> $DIR/temporaries.rs:77:10
+   |
+LL | /         (loop {
+LL | |             break String::new();
+LL | |         })
+   | |__________- this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+LL |           .as_ptr();
+   |            ^^^^^^ this pointer will immediately be invalid
+   |
+   = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: a dangling pointer will be produced because the temporary `String` will be dropped
+  --> $DIR/temporaries.rs:86:10
+   |
+LL | /         match string() {
+LL | |             s => s,
+LL | |         }
+   | |_________- this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+LL |           .as_ptr();
+   |            ^^^^^^ this pointer will immediately be invalid
+   |
+   = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: a dangling pointer will be produced because the temporary `String` will be dropped
+  --> $DIR/temporaries.rs:94:18
+   |
+LL |     { string() }.as_ptr();
+   |     ------------ ^^^^^^ this pointer will immediately be invalid
+   |     |
+   |     this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+   |
+   = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: a dangling pointer will be produced because the temporary `Vec<u8>` will be dropped
+  --> $DIR/temporaries.rs:134:15
+   |
+LL |     vec![0u8].as_ptr();
+   |     --------- ^^^^^^ this pointer will immediately be invalid
+   |     |
+   |     this `Vec<u8>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+   |
+   = note: pointers do not have a lifetime; when calling `as_ptr` the `Vec<u8>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: aborting due to 8 previous errors
+
diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/types.rs b/tests/ui/lint/dangling-pointers-from-temporaries/types.rs
new file mode 100644
index 0000000..2b515d3
--- /dev/null
+++ b/tests/ui/lint/dangling-pointers-from-temporaries/types.rs
@@ -0,0 +1,52 @@
+#![deny(dangling_pointers_from_temporaries)]
+
+use std::cell::Cell;
+use std::ffi::{CStr, CString};
+use std::mem::MaybeUninit;
+
+struct AsPtrFake;
+
+impl AsPtrFake {
+    fn as_ptr(&self) -> *const () {
+        std::ptr::null()
+    }
+}
+
+fn declval<T>() -> T {
+    loop {}
+}
+
+fn main() {
+    declval::<CString>().as_ptr();
+    //~^ ERROR a dangling pointer will be produced because the temporary `CString` will be dropped
+    declval::<String>().as_ptr();
+    //~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped
+    declval::<Vec<u8>>().as_ptr();
+    //~^ ERROR a dangling pointer will be produced because the temporary `Vec<u8>` will be dropped
+    declval::<Box<CString>>().as_ptr();
+    //~^ ERROR a dangling pointer will be produced because the temporary `Box<CString>` will be dropped
+    declval::<Box<[u8]>>().as_ptr();
+    //~^ ERROR a dangling pointer will be produced because the temporary `Box<[u8]>` will be dropped
+    declval::<Box<str>>().as_ptr();
+    //~^ ERROR a dangling pointer will be produced because the temporary `Box<str>` will be dropped
+    declval::<Box<CStr>>().as_ptr();
+    //~^ ERROR a dangling pointer will be produced because the temporary `Box<CStr>` will be dropped
+    declval::<[u8; 10]>().as_ptr();
+    //~^ ERROR a dangling pointer will be produced because the temporary `[u8; 10]` will be dropped
+    declval::<Box<[u8; 10]>>().as_ptr();
+    //~^ ERROR a dangling pointer will be produced because the temporary `Box<[u8; 10]>` will be dropped
+    declval::<Box<Vec<u8>>>().as_ptr();
+    //~^ ERROR a dangling pointer will be produced because the temporary `Box<Vec<u8>>` will be dropped
+    declval::<Box<String>>().as_ptr();
+    //~^ ERROR a dangling pointer will be produced because the temporary `Box<String>` will be dropped
+    declval::<Box<Box<Box<Box<[u8]>>>>>().as_ptr();
+    //~^ ERROR a dangling pointer will be produced because the temporary `Box<Box<Box<Box<[u8]>>>>` will be dropped
+    declval::<Cell<u8>>().as_ptr();
+    //~^ ERROR a dangling pointer will be produced because the temporary `Cell<u8>` will be dropped
+    declval::<MaybeUninit<u8>>().as_ptr();
+    //~^ ERROR a dangling pointer will be produced because the temporary `MaybeUninit<u8>` will be dropped
+    declval::<Vec<AsPtrFake>>().as_ptr();
+    //~^ ERROR a dangling pointer will be produced because the temporary `Vec<AsPtrFake>` will be dropped
+    declval::<Box<AsPtrFake>>().as_ptr();
+    declval::<AsPtrFake>().as_ptr();
+}
diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/types.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/types.stderr
new file mode 100644
index 0000000..c582a4c
--- /dev/null
+++ b/tests/ui/lint/dangling-pointers-from-temporaries/types.stderr
@@ -0,0 +1,172 @@
+error: a dangling pointer will be produced because the temporary `CString` will be dropped
+  --> $DIR/types.rs:20:26
+   |
+LL |     declval::<CString>().as_ptr();
+   |     -------------------- ^^^^^^ this pointer will immediately be invalid
+   |     |
+   |     this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+   |
+   = note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+note: the lint level is defined here
+  --> $DIR/types.rs:1:9
+   |
+LL | #![deny(dangling_pointers_from_temporaries)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: a dangling pointer will be produced because the temporary `String` will be dropped
+  --> $DIR/types.rs:22:25
+   |
+LL |     declval::<String>().as_ptr();
+   |     ------------------- ^^^^^^ this pointer will immediately be invalid
+   |     |
+   |     this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+   |
+   = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: a dangling pointer will be produced because the temporary `Vec<u8>` will be dropped
+  --> $DIR/types.rs:24:26
+   |
+LL |     declval::<Vec<u8>>().as_ptr();
+   |     -------------------- ^^^^^^ this pointer will immediately be invalid
+   |     |
+   |     this `Vec<u8>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+   |
+   = note: pointers do not have a lifetime; when calling `as_ptr` the `Vec<u8>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: a dangling pointer will be produced because the temporary `Box<CString>` will be dropped
+  --> $DIR/types.rs:26:31
+   |
+LL |     declval::<Box<CString>>().as_ptr();
+   |     ------------------------- ^^^^^^ this pointer will immediately be invalid
+   |     |
+   |     this `Box<CString>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+   |
+   = note: pointers do not have a lifetime; when calling `as_ptr` the `Box<CString>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: a dangling pointer will be produced because the temporary `Box<[u8]>` will be dropped
+  --> $DIR/types.rs:28:28
+   |
+LL |     declval::<Box<[u8]>>().as_ptr();
+   |     ---------------------- ^^^^^^ this pointer will immediately be invalid
+   |     |
+   |     this `Box<[u8]>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+   |
+   = note: pointers do not have a lifetime; when calling `as_ptr` the `Box<[u8]>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: a dangling pointer will be produced because the temporary `Box<str>` will be dropped
+  --> $DIR/types.rs:30:27
+   |
+LL |     declval::<Box<str>>().as_ptr();
+   |     --------------------- ^^^^^^ this pointer will immediately be invalid
+   |     |
+   |     this `Box<str>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+   |
+   = note: pointers do not have a lifetime; when calling `as_ptr` the `Box<str>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: a dangling pointer will be produced because the temporary `Box<CStr>` will be dropped
+  --> $DIR/types.rs:32:28
+   |
+LL |     declval::<Box<CStr>>().as_ptr();
+   |     ---------------------- ^^^^^^ this pointer will immediately be invalid
+   |     |
+   |     this `Box<CStr>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+   |
+   = note: pointers do not have a lifetime; when calling `as_ptr` the `Box<CStr>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: a dangling pointer will be produced because the temporary `[u8; 10]` will be dropped
+  --> $DIR/types.rs:34:27
+   |
+LL |     declval::<[u8; 10]>().as_ptr();
+   |     --------------------- ^^^^^^ this pointer will immediately be invalid
+   |     |
+   |     this `[u8; 10]` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+   |
+   = note: pointers do not have a lifetime; when calling `as_ptr` the `[u8; 10]` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: a dangling pointer will be produced because the temporary `Box<[u8; 10]>` will be dropped
+  --> $DIR/types.rs:36:32
+   |
+LL |     declval::<Box<[u8; 10]>>().as_ptr();
+   |     -------------------------- ^^^^^^ this pointer will immediately be invalid
+   |     |
+   |     this `Box<[u8; 10]>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+   |
+   = note: pointers do not have a lifetime; when calling `as_ptr` the `Box<[u8; 10]>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: a dangling pointer will be produced because the temporary `Box<Vec<u8>>` will be dropped
+  --> $DIR/types.rs:38:31
+   |
+LL |     declval::<Box<Vec<u8>>>().as_ptr();
+   |     ------------------------- ^^^^^^ this pointer will immediately be invalid
+   |     |
+   |     this `Box<Vec<u8>>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+   |
+   = note: pointers do not have a lifetime; when calling `as_ptr` the `Box<Vec<u8>>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: a dangling pointer will be produced because the temporary `Box<String>` will be dropped
+  --> $DIR/types.rs:40:30
+   |
+LL |     declval::<Box<String>>().as_ptr();
+   |     ------------------------ ^^^^^^ this pointer will immediately be invalid
+   |     |
+   |     this `Box<String>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+   |
+   = note: pointers do not have a lifetime; when calling `as_ptr` the `Box<String>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: a dangling pointer will be produced because the temporary `Box<Box<Box<Box<[u8]>>>>` will be dropped
+  --> $DIR/types.rs:42:43
+   |
+LL |     declval::<Box<Box<Box<Box<[u8]>>>>>().as_ptr();
+   |     ------------------------------------- ^^^^^^ this pointer will immediately be invalid
+   |     |
+   |     this `Box<Box<Box<Box<[u8]>>>>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+   |
+   = note: pointers do not have a lifetime; when calling `as_ptr` the `Box<Box<Box<Box<[u8]>>>>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: a dangling pointer will be produced because the temporary `Cell<u8>` will be dropped
+  --> $DIR/types.rs:44:27
+   |
+LL |     declval::<Cell<u8>>().as_ptr();
+   |     --------------------- ^^^^^^ this pointer will immediately be invalid
+   |     |
+   |     this `Cell<u8>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+   |
+   = note: pointers do not have a lifetime; when calling `as_ptr` the `Cell<u8>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: a dangling pointer will be produced because the temporary `MaybeUninit<u8>` will be dropped
+  --> $DIR/types.rs:46:34
+   |
+LL |     declval::<MaybeUninit<u8>>().as_ptr();
+   |     ---------------------------- ^^^^^^ this pointer will immediately be invalid
+   |     |
+   |     this `MaybeUninit<u8>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+   |
+   = note: pointers do not have a lifetime; when calling `as_ptr` the `MaybeUninit<u8>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: a dangling pointer will be produced because the temporary `Vec<AsPtrFake>` will be dropped
+  --> $DIR/types.rs:48:33
+   |
+LL |     declval::<Vec<AsPtrFake>>().as_ptr();
+   |     --------------------------- ^^^^^^ this pointer will immediately be invalid
+   |     |
+   |     this `Vec<AsPtrFake>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+   |
+   = note: pointers do not have a lifetime; when calling `as_ptr` the `Vec<AsPtrFake>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: aborting due to 15 previous errors
+
diff --git a/tests/ui/lint/keyword-idents/auxiliary/multi_file_submod.rs b/tests/ui/lint/keyword-idents/auxiliary/multi_file_submod.rs
new file mode 100644
index 0000000..08d6733
--- /dev/null
+++ b/tests/ui/lint/keyword-idents/auxiliary/multi_file_submod.rs
@@ -0,0 +1,10 @@
+// Submodule file used by test `../multi-file.rs`.
+
+// Keywords reserved from Rust 2018:
+fn async() {}
+fn await() {}
+fn try() {}
+fn dyn() {}
+
+// Keywords reserved from Rust 2024:
+fn gen() {}
diff --git a/tests/ui/lint/keyword-idents/multi-file.rs b/tests/ui/lint/keyword-idents/multi-file.rs
new file mode 100644
index 0000000..703e13f
--- /dev/null
+++ b/tests/ui/lint/keyword-idents/multi-file.rs
@@ -0,0 +1,14 @@
+#![deny(keyword_idents)] // Should affect the submodule, but doesn't.
+//@ edition: 2015
+//@ known-bug: #132218
+//@ check-pass (known bug; should be check-fail)
+
+// Because `keyword_idents_2018` and `keyword_idents_2024` are pre-expansion
+// lints, configuring them via lint attributes doesn't propagate to submodules
+// in other files.
+// <https://github.com/rust-lang/rust/issues/132218>
+
+#[path = "./auxiliary/multi_file_submod.rs"]
+mod multi_file_submod;
+
+fn main() {}
diff --git a/tests/ui/lint/lint-deref-nullptr.rs b/tests/ui/lint/lint-deref-nullptr.rs
index d052dbd..f83d883 100644
--- a/tests/ui/lint/lint-deref-nullptr.rs
+++ b/tests/ui/lint/lint-deref-nullptr.rs
@@ -27,9 +27,9 @@
         let ub = &*ptr::null_mut::<i32>();
         //~^ ERROR dereferencing a null pointer
         ptr::addr_of!(*ptr::null::<i32>());
-        //~^ ERROR dereferencing a null pointer
+        // ^^ OKAY
         ptr::addr_of_mut!(*ptr::null_mut::<i32>());
-        //~^ ERROR dereferencing a null pointer
+        // ^^ OKAY
         let offset = ptr::addr_of!((*ptr::null::<Struct>()).field);
         //~^ ERROR dereferencing a null pointer
     }
diff --git a/tests/ui/lint/lint-deref-nullptr.stderr b/tests/ui/lint/lint-deref-nullptr.stderr
index c6f432e..175431b 100644
--- a/tests/ui/lint/lint-deref-nullptr.stderr
+++ b/tests/ui/lint/lint-deref-nullptr.stderr
@@ -47,22 +47,10 @@
    |                   ^^^^^^^^^^^^^^^^^^^^^^^ this code causes undefined behavior when executed
 
 error: dereferencing a null pointer
-  --> $DIR/lint-deref-nullptr.rs:29:23
-   |
-LL |         ptr::addr_of!(*ptr::null::<i32>());
-   |                       ^^^^^^^^^^^^^^^^^^^ this code causes undefined behavior when executed
-
-error: dereferencing a null pointer
-  --> $DIR/lint-deref-nullptr.rs:31:27
-   |
-LL |         ptr::addr_of_mut!(*ptr::null_mut::<i32>());
-   |                           ^^^^^^^^^^^^^^^^^^^^^^^ this code causes undefined behavior when executed
-
-error: dereferencing a null pointer
   --> $DIR/lint-deref-nullptr.rs:33:36
    |
 LL |         let offset = ptr::addr_of!((*ptr::null::<Struct>()).field);
    |                                    ^^^^^^^^^^^^^^^^^^^^^^^^ this code causes undefined behavior when executed
 
-error: aborting due to 10 previous errors
+error: aborting due to 8 previous errors
 
diff --git a/tests/ui/lint/lint-missing-doc-expect.rs b/tests/ui/lint/lint-missing-doc-expect.rs
index 991f650..b1abf8b 100644
--- a/tests/ui/lint/lint-missing-doc-expect.rs
+++ b/tests/ui/lint/lint-missing-doc-expect.rs
@@ -1,10 +1,10 @@
 // Make sure that `#[expect(missing_docs)]` is always correctly fulfilled.
 
 //@ check-pass
-//@ revisions: lib bin test
+//@ revisions: lib bin test_
 //@ [lib]compile-flags: --crate-type lib
 //@ [bin]compile-flags: --crate-type bin
-//@ [test]compile-flags: --test
+//@ [test_]compile-flags: --test
 
 #[expect(missing_docs)]
 pub fn foo() {}
diff --git a/tests/ui/lint/lint-temporary-cstring-as-param.stderr b/tests/ui/lint/lint-temporary-cstring-as-param.stderr
deleted file mode 100644
index 7aa21f2..0000000
--- a/tests/ui/lint/lint-temporary-cstring-as-param.stderr
+++ /dev/null
@@ -1,18 +0,0 @@
-error: getting the inner pointer of a temporary `CString`
-  --> $DIR/lint-temporary-cstring-as-param.rs:9:45
-   |
-LL |     some_function(CString::new("").unwrap().as_ptr());
-   |                   ------------------------- ^^^^^^ this pointer will be invalid
-   |                   |
-   |                   this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
-   |
-   = note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
-   = help: for more information, see https://doc.rust-lang.org/reference/destructors.html
-note: the lint level is defined here
-  --> $DIR/lint-temporary-cstring-as-param.rs:1:9
-   |
-LL | #![deny(temporary_cstring_as_ptr)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 1 previous error
-
diff --git a/tests/ui/lint/lint-temporary-cstring-as-ptr.rs b/tests/ui/lint/lint-temporary-cstring-as-ptr.rs
deleted file mode 100644
index fab792f..0000000
--- a/tests/ui/lint/lint-temporary-cstring-as-ptr.rs
+++ /dev/null
@@ -1,17 +0,0 @@
-// this program is not technically incorrect, but is an obscure enough style to be worth linting
-#![deny(temporary_cstring_as_ptr)]
-
-use std::ffi::CString;
-
-macro_rules! mymacro {
-    () => {
-        let s = CString::new("some text").unwrap().as_ptr();
-        //~^ ERROR getting the inner pointer of a temporary `CString`
-    }
-}
-
-fn main() {
-    let s = CString::new("some text").unwrap().as_ptr();
-    //~^ ERROR getting the inner pointer of a temporary `CString`
-    mymacro!();
-}
diff --git a/tests/ui/lint/lint-temporary-cstring-as-ptr.stderr b/tests/ui/lint/lint-temporary-cstring-as-ptr.stderr
deleted file mode 100644
index 4e5c8aa..0000000
--- a/tests/ui/lint/lint-temporary-cstring-as-ptr.stderr
+++ /dev/null
@@ -1,33 +0,0 @@
-error: getting the inner pointer of a temporary `CString`
-  --> $DIR/lint-temporary-cstring-as-ptr.rs:14:48
-   |
-LL |     let s = CString::new("some text").unwrap().as_ptr();
-   |             ---------------------------------- ^^^^^^ this pointer will be invalid
-   |             |
-   |             this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
-   |
-   = note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
-   = help: for more information, see https://doc.rust-lang.org/reference/destructors.html
-note: the lint level is defined here
-  --> $DIR/lint-temporary-cstring-as-ptr.rs:2:9
-   |
-LL | #![deny(temporary_cstring_as_ptr)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: getting the inner pointer of a temporary `CString`
-  --> $DIR/lint-temporary-cstring-as-ptr.rs:8:52
-   |
-LL |         let s = CString::new("some text").unwrap().as_ptr();
-   |                 ---------------------------------- ^^^^^^ this pointer will be invalid
-   |                 |
-   |                 this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
-...
-LL |     mymacro!();
-   |     ---------- in this macro invocation
-   |
-   = note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
-   = help: for more information, see https://doc.rust-lang.org/reference/destructors.html
-   = note: this error originates in the macro `mymacro` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: aborting due to 2 previous errors
-
diff --git a/tests/ui/macros/rfc-3086-metavar-expr/count-and-length-are-distinct.rs b/tests/ui/macros/rfc-3086-metavar-expr/count-and-length-are-distinct.rs
index 131d416..8ca4532 100644
--- a/tests/ui/macros/rfc-3086-metavar-expr/count-and-length-are-distinct.rs
+++ b/tests/ui/macros/rfc-3086-metavar-expr/count-and-length-are-distinct.rs
@@ -6,9 +6,9 @@
     macro_rules! one_nested_count_and_len {
         ( $( [ $( $l:literal ),* ] ),* ) => {
             [
-                // outer-most repetition
+                // outermost repetition
                 $(
-                    // inner-most repetition
+                    // innermost repetition
                     $(
                         ${ignore($l)} ${index()}, ${len()},
                     )*
@@ -23,34 +23,34 @@
         [
             // # ["foo"]
 
-            // ## inner-most repetition (first iteration)
+            // ## innermost repetition (first iteration)
             //
-            // `index` is 0 because this is the first inner-most iteration.
-            // `len` is 1 because there is only one inner-most repetition, "foo".
+            // `index` is 0 because this is the first innermost iteration.
+            // `len` is 1 because there is only one innermost repetition, "foo".
             0, 1,
-            // ## outer-most repetition (first iteration)
+            // ## outermost repetition (first iteration)
             //
             // `count` is 1 because of "foo", i,e, `$l` has only one repetition,
-            // `index` is 0 because this is the first outer-most iteration.
-            // `len` is 2 because there are 2 outer-most repetitions, ["foo"] and ["bar", "baz"]
+            // `index` is 0 because this is the first outermost iteration.
+            // `len` is 2 because there are 2 outermost repetitions, ["foo"] and ["bar", "baz"]
             1, 0, 2,
             // # ["bar", "baz"]
 
-            // ## inner-most repetition (first iteration)
+            // ## innermost repetition (first iteration)
             //
-            // `index` is 0 because this is the first inner-most iteration
+            // `index` is 0 because this is the first innermost iteration
             // `len` is 2 because there are repetitions, "bar" and "baz"
             0, 2,
-            // ## inner-most repetition (second iteration)
+            // ## innermost repetition (second iteration)
             //
-            // `index` is 1 because this is the second inner-most iteration
+            // `index` is 1 because this is the second innermost iteration
             // `len` is 2 because there are repetitions, "bar" and "baz"
             1, 2,
-            // ## outer-most repetition (second iteration)
+            // ## outermost repetition (second iteration)
             //
             // `count` is 2 because of "bar" and "baz", i,e, `$l` has two repetitions,
-            // `index` is 1 because this is the second outer-most iteration
-            // `len` is 2 because there are 2 outer-most repetitions, ["foo"] and ["bar", "baz"]
+            // `index` is 1 because this is the second outermost iteration
+            // `len` is 2 because there are 2 outermost repetitions, ["foo"] and ["bar", "baz"]
             2, 1, 2,
             // # last count
 
@@ -61,7 +61,7 @@
 
     // Based on the above explanation, the following macros should be straightforward
 
-    // Grouped from the outer-most to the inner-most
+    // Grouped from the outermost to the innermost
     macro_rules! three_nested_count {
         ( $( { $( [ $( ( $( $i:ident )* ) )* ] )* } )* ) => {
             &[
@@ -156,7 +156,7 @@
         ][..]
     );
 
-    // Grouped from the outer-most to the inner-most
+    // Grouped from the outermost to the innermost
     macro_rules! three_nested_len {
         ( $( { $( [ $( ( $( $i:ident )* ) )* ] )* } )* ) => {
             &[
diff --git a/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.rs b/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.rs
index 1eda5f5..78cede9 100644
--- a/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.rs
+++ b/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.rs
@@ -10,12 +10,12 @@
 
 macro_rules! curly__no_rhs_dollar__no_round {
     ( $i:ident ) => { ${ count($i) } };
-    //~^ ERROR `count` can not be placed inside the inner-most repetition
+    //~^ ERROR `count` can not be placed inside the innermost repetition
 }
 
 macro_rules! curly__rhs_dollar__no_round {
     ( $i:ident ) => { ${ count($i) } };
-    //~^ ERROR `count` can not be placed inside the inner-most repetition
+    //~^ ERROR `count` can not be placed inside the innermost repetition
 }
 
 #[rustfmt::skip] // autoformatters can break a few of the error traces
diff --git a/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.stderr b/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.stderr
index 2c44ad2..ce7694e 100644
--- a/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.stderr
+++ b/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.stderr
@@ -196,13 +196,13 @@
 LL |     ( $( $i:ident ),* ) => { ${ {} } };
    |                                 ^^
 
-error: `count` can not be placed inside the inner-most repetition
+error: `count` can not be placed inside the innermost repetition
   --> $DIR/syntax-errors.rs:12:24
    |
 LL |     ( $i:ident ) => { ${ count($i) } };
    |                        ^^^^^^^^^^^^^
 
-error: `count` can not be placed inside the inner-most repetition
+error: `count` can not be placed inside the innermost repetition
   --> $DIR/syntax-errors.rs:17:24
    |
 LL |     ( $i:ident ) => { ${ count($i) } };
diff --git a/tests/ui/never_type/issue-52443.stderr b/tests/ui/never_type/issue-52443.stderr
index adcff66..2207ceb 100644
--- a/tests/ui/never_type/issue-52443.stderr
+++ b/tests/ui/never_type/issue-52443.stderr
@@ -50,10 +50,6 @@
 note: impl defined here, but it is not `const`
   --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
    = note: calls in constants are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
 
 error[E0015]: cannot call non-const fn `<RangeFrom<usize> as Iterator>::next` in constants
   --> $DIR/issue-52443.rs:9:21
@@ -62,10 +58,6 @@
    |                     ^^^^^^^^
    |
    = note: calls in constants are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
 
 error: aborting due to 5 previous errors; 1 warning emitted
 
diff --git a/tests/ui/parser/issues/issue-35813-postfix-after-cast.stderr b/tests/ui/parser/issues/issue-35813-postfix-after-cast.stderr
index 66b57c7..e34371b 100644
--- a/tests/ui/parser/issues/issue-35813-postfix-after-cast.stderr
+++ b/tests/ui/parser/issues/issue-35813-postfix-after-cast.stderr
@@ -353,10 +353,6 @@
    |
    = note: calls in statics are limited to constant functions, tuple structs and tuple variants
    = note: consider wrapping this expression in `std::sync::LazyLock::new(|| ...)`
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
 
 error: aborting due to 40 previous errors
 
diff --git a/tests/ui/privacy/privacy1.rs b/tests/ui/privacy/privacy1.rs
index fcb2108..31f3960 100644
--- a/tests/ui/privacy/privacy1.rs
+++ b/tests/ui/privacy/privacy1.rs
@@ -12,14 +12,14 @@
     type Target;
 }
 
-#[lang="receiver"]
-pub trait Receiver: Deref {}
+#[lang="legacy_receiver"]
+pub trait LegacyReceiver: Deref {}
 
 impl<'a, T> Deref for &'a T {
     type Target = T;
 }
 
-impl<'a, T> Receiver for &'a T {}
+impl<'a, T> LegacyReceiver for &'a T {}
 
 mod bar {
     // shouldn't bring in too much
diff --git a/tests/ui/repr/repr_align_greater_usize.msp430.stderr b/tests/ui/repr/repr_align_greater_usize.msp430.stderr
new file mode 100644
index 0000000..7c85249
--- /dev/null
+++ b/tests/ui/repr/repr_align_greater_usize.msp430.stderr
@@ -0,0 +1,19 @@
+error[E0589]: alignment must not be greater than `isize::MAX` bytes
+  --> $DIR/repr_align_greater_usize.rs:21:8
+   |
+LL | #[repr(align(32768))]
+   |        ^^^^^^^^^^^^
+   |
+   = note: `isize::MAX` is 32767 for the current target
+
+error[E0589]: alignment must not be greater than `isize::MAX` bytes
+  --> $DIR/repr_align_greater_usize.rs:24:8
+   |
+LL | #[repr(align(65536))]
+   |        ^^^^^^^^^^^^
+   |
+   = note: `isize::MAX` is 32767 for the current target
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0589`.
diff --git a/tests/ui/repr/repr_align_greater_usize.rs b/tests/ui/repr/repr_align_greater_usize.rs
new file mode 100644
index 0000000..b47320b
--- /dev/null
+++ b/tests/ui/repr/repr_align_greater_usize.rs
@@ -0,0 +1,25 @@
+//@ revisions: msp430 aarch32
+//@[msp430] needs-llvm-components: msp430
+//@[msp430] compile-flags: --target=msp430-none-elf
+//@[aarch32] build-pass
+//@[aarch32] needs-llvm-components: arm
+//@[aarch32] compile-flags: --target=thumbv7m-none-eabi
+
+// We should fail to compute alignment for types aligned higher than usize::MAX.
+// We can't handle alignments that require all 32 bits, so this only affects 16-bit.
+
+#![feature(lang_items, no_core)]
+#![no_core]
+#![crate_type = "lib"]
+
+#[lang = "sized"]
+trait Sized {}
+
+#[repr(align(16384))]
+struct Kitten;
+
+#[repr(align(32768))] //[msp430]~ ERROR alignment must not be greater than `isize::MAX`
+struct Cat;
+
+#[repr(align(65536))] //[msp430]~ ERROR alignment must not be greater than `isize::MAX`
+struct BigCat;
diff --git a/tests/ui/resolve/issue-39559-2.stderr b/tests/ui/resolve/issue-39559-2.stderr
index 7f51357..ea27e7b 100644
--- a/tests/ui/resolve/issue-39559-2.stderr
+++ b/tests/ui/resolve/issue-39559-2.stderr
@@ -5,10 +5,6 @@
    |                        ^^^^^^^^^^^
    |
    = note: calls in constants are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
 
 error[E0015]: cannot call non-const fn `<Dim3 as Dim>::dim` in constants
   --> $DIR/issue-39559-2.rs:16:15
@@ -17,10 +13,6 @@
    |               ^^^^^^^^^^^
    |
    = note: calls in constants are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-0.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-0.stderr
deleted file mode 100644
index 8288c66..0000000
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-0.stderr
+++ /dev/null
@@ -1,46 +0,0 @@
-error: using `#![feature(effects)]` without enabling next trait solver globally
-   |
-   = note: the next trait solver must be enabled globally for the effects feature to work correctly
-   = help: use `-Znext-solver` to enable
-
-error[E0277]: the trait bound `<T as Trait>::Assoc: Trait` is not satisfied
-  --> $DIR/assoc-type-const-bound-usage-0.rs:13:5
-   |
-LL |     T::Assoc::func()
-   |     ^^^^^^^^ the trait `Trait` is not implemented for `<T as Trait>::Assoc`
-   |
-note: required by a bound in `Trait::func`
-  --> $DIR/assoc-type-const-bound-usage-0.rs:6:1
-   |
-LL | #[const_trait]
-   | ^^^^^^^^^^^^^^ required by this bound in `Trait::func`
-...
-LL |     fn func() -> i32;
-   |        ---- required by a bound in this associated function
-help: consider further restricting the associated type
-   |
-LL | const fn unqualified<T: ~const Trait>() -> i32 where <T as Trait>::Assoc: Trait {
-   |                                                ++++++++++++++++++++++++++++++++
-
-error[E0277]: the trait bound `<T as Trait>::Assoc: Trait` is not satisfied
-  --> $DIR/assoc-type-const-bound-usage-0.rs:17:5
-   |
-LL |     <T as Trait>::Assoc::func()
-   |     ^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `<T as Trait>::Assoc`
-   |
-note: required by a bound in `Trait::func`
-  --> $DIR/assoc-type-const-bound-usage-0.rs:6:1
-   |
-LL | #[const_trait]
-   | ^^^^^^^^^^^^^^ required by this bound in `Trait::func`
-...
-LL |     fn func() -> i32;
-   |        ---- required by a bound in this associated function
-help: consider further restricting the associated type
-   |
-LL | const fn qualified<T: ~const Trait>() -> i32 where <T as Trait>::Assoc: Trait {
-   |                                              ++++++++++++++++++++++++++++++++
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-1.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-1.stderr
deleted file mode 100644
index 0792d09..0000000
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-1.stderr
+++ /dev/null
@@ -1,46 +0,0 @@
-error: using `#![feature(effects)]` without enabling next trait solver globally
-   |
-   = note: the next trait solver must be enabled globally for the effects feature to work correctly
-   = help: use `-Znext-solver` to enable
-
-error[E0277]: the trait bound `<T as Trait>::Assoc: Trait` is not satisfied
-  --> $DIR/assoc-type-const-bound-usage-1.rs:15:44
-   |
-LL | fn unqualified<T: const Trait>() -> Type<{ T::Assoc::func() }> {
-   |                                            ^^^^^^^^ the trait `Trait` is not implemented for `<T as Trait>::Assoc`
-   |
-note: required by a bound in `Trait::func`
-  --> $DIR/assoc-type-const-bound-usage-1.rs:7:1
-   |
-LL | #[const_trait]
-   | ^^^^^^^^^^^^^^ required by this bound in `Trait::func`
-...
-LL |     fn func() -> i32;
-   |        ---- required by a bound in this associated function
-help: consider further restricting the associated type
-   |
-LL | fn unqualified<T: const Trait>() -> Type<{ T::Assoc::func() }> where <T as Trait>::Assoc: Trait {
-   |                                                                ++++++++++++++++++++++++++++++++
-
-error[E0277]: the trait bound `<T as Trait>::Assoc: Trait` is not satisfied
-  --> $DIR/assoc-type-const-bound-usage-1.rs:19:42
-   |
-LL | fn qualified<T: const Trait>() -> Type<{ <T as Trait>::Assoc::func() }> {
-   |                                          ^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `<T as Trait>::Assoc`
-   |
-note: required by a bound in `Trait::func`
-  --> $DIR/assoc-type-const-bound-usage-1.rs:7:1
-   |
-LL | #[const_trait]
-   | ^^^^^^^^^^^^^^ required by this bound in `Trait::func`
-...
-LL |     fn func() -> i32;
-   |        ---- required by a bound in this associated function
-help: consider further restricting the associated type
-   |
-LL | fn qualified<T: const Trait>() -> Type<{ <T as Trait>::Assoc::func() }> where <T as Trait>::Assoc: Trait {
-   |                                                                         ++++++++++++++++++++++++++++++++
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-const-trait-method-fail.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-const-trait-method-fail.stderr
deleted file mode 100644
index 5d2333d..0000000
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-const-trait-method-fail.stderr
+++ /dev/null
@@ -1,22 +0,0 @@
-error[E0277]: the trait bound `u32: ~const Plus` is not satisfied
-  --> $DIR/call-const-trait-method-fail.rs:27:5
-   |
-LL |     a.plus(b)
-   |     ^ the trait `Plus` is not implemented for `u32`
-   |
-note: required by a bound in `Plus::plus`
-  --> $DIR/call-const-trait-method-fail.rs:5:1
-   |
-LL | #[const_trait]
-   | ^^^^^^^^^^^^^^ required by this bound in `Plus::plus`
-LL | pub trait Plus {
-LL |     fn plus(self, rhs: Self) -> Self;
-   |        ---- required by a bound in this associated function
-help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
-   |
-LL | pub const fn add_u32(a: u32, b: u32) -> u32 where u32: Plus {
-   |                                             +++++++++++++++
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-in-impl.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-in-impl.stderr
deleted file mode 100644
index 5cd274c..0000000
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-in-impl.stderr
+++ /dev/null
@@ -1,31 +0,0 @@
-error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/call-generic-in-impl.rs:10:16
-   |
-LL | impl<T: ~const PartialEq> const MyPartialEq for T {
-   |                ^^^^^^^^^
-
-error[E0049]: method `eq` has 1 const parameter but its trait declaration has 0 const parameters
-  --> $DIR/call-generic-in-impl.rs:5:1
-   |
-LL | #[const_trait]
-   | ^^^^^^^^^^^^^^ found 1 const parameter
-LL | trait MyPartialEq {
-LL |     fn eq(&self, other: &Self) -> bool;
-   |          - expected 0 const parameters
-
-error[E0015]: cannot call non-const fn `<T as PartialEq>::eq` in constant functions
-  --> $DIR/call-generic-in-impl.rs:12:9
-   |
-LL |         PartialEq::eq(self, other)
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(effects)]` to the crate attributes to enable
-   |
-LL + #![feature(effects)]
-   |
-
-error: aborting due to 3 previous errors
-
-Some errors have detailed explanations: E0015, E0049.
-For more information about an error, try `rustc --explain E0015`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-chain.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-chain.stderr
deleted file mode 100644
index 57d57df..0000000
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-chain.stderr
+++ /dev/null
@@ -1,37 +0,0 @@
-warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/call-generic-method-chain.rs:6:30
-   |
-LL | #![feature(const_trait_impl, effects)]
-   |                              ^^^^^^^
-   |
-   = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
-   = note: `#[warn(incomplete_features)]` on by default
-
-error: using `#![feature(effects)]` without enabling next trait solver globally
-   |
-   = note: the next trait solver must be enabled globally for the effects feature to work correctly
-   = help: use `-Znext-solver` to enable
-
-error: const `impl` for trait `PartialEq` which is not marked with `#[const_trait]`
-  --> $DIR/call-generic-method-chain.rs:10:12
-   |
-LL | impl const PartialEq for S {
-   |            ^^^^^^^^^
-   |
-   = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const`
-   = note: adding a non-const method body in the future would be a breaking change
-
-error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/call-generic-method-chain.rs:19:32
-   |
-LL | const fn equals_self<T: ~const PartialEq>(t: &T) -> bool {
-   |                                ^^^^^^^^^
-
-error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/call-generic-method-chain.rs:23:40
-   |
-LL | const fn equals_self_wrapper<T: ~const PartialEq>(t: &T) -> bool {
-   |                                        ^^^^^^^^^
-
-error: aborting due to 4 previous errors; 1 warning emitted
-
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-dup-bound.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-dup-bound.stderr
deleted file mode 100644
index 0088ed2..0000000
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-dup-bound.stderr
+++ /dev/null
@@ -1,37 +0,0 @@
-warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/call-generic-method-dup-bound.rs:4:30
-   |
-LL | #![feature(const_trait_impl, effects)]
-   |                              ^^^^^^^
-   |
-   = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
-   = note: `#[warn(incomplete_features)]` on by default
-
-error: using `#![feature(effects)]` without enabling next trait solver globally
-   |
-   = note: the next trait solver must be enabled globally for the effects feature to work correctly
-   = help: use `-Znext-solver` to enable
-
-error: const `impl` for trait `PartialEq` which is not marked with `#[const_trait]`
-  --> $DIR/call-generic-method-dup-bound.rs:8:12
-   |
-LL | impl const PartialEq for S {
-   |            ^^^^^^^^^
-   |
-   = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const`
-   = note: adding a non-const method body in the future would be a breaking change
-
-error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/call-generic-method-dup-bound.rs:19:44
-   |
-LL | const fn equals_self<T: PartialEq + ~const PartialEq>(t: &T) -> bool {
-   |                                            ^^^^^^^^^
-
-error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/call-generic-method-dup-bound.rs:26:37
-   |
-LL | const fn equals_self2<T: A + ~const PartialEq>(t: &T) -> bool {
-   |                                     ^^^^^^^^^
-
-error: aborting due to 4 previous errors; 1 warning emitted
-
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-nonconst.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-nonconst.stderr
deleted file mode 100644
index 68c9fc4..0000000
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-nonconst.stderr
+++ /dev/null
@@ -1,21 +0,0 @@
-error[E0277]: the trait bound `S: const Foo` is not satisfied
-  --> $DIR/call-generic-method-nonconst.rs:25:34
-   |
-LL | pub const EQ: bool = equals_self(&S);
-   |                      ----------- ^^ the trait `Foo` is not implemented for `S`
-   |                      |
-   |                      required by a bound introduced by this call
-   |
-note: required by a bound in `equals_self`
-  --> $DIR/call-generic-method-nonconst.rs:18:25
-   |
-LL | const fn equals_self<T: ~const Foo>(t: &T) -> bool {
-   |                         ^^^^^^^^^^ required by this bound in `equals_self`
-help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
-   |
-LL | pub const EQ: bool where S: Foo = equals_self(&S);
-   |                    ++++++++++++
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-pass.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-pass.stderr
deleted file mode 100644
index 4a6100c..0000000
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-pass.stderr
+++ /dev/null
@@ -1,31 +0,0 @@
-warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/call-generic-method-pass.rs:6:30
-   |
-LL | #![feature(const_trait_impl, effects)]
-   |                              ^^^^^^^
-   |
-   = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
-   = note: `#[warn(incomplete_features)]` on by default
-
-error: using `#![feature(effects)]` without enabling next trait solver globally
-   |
-   = note: the next trait solver must be enabled globally for the effects feature to work correctly
-   = help: use `-Znext-solver` to enable
-
-error: const `impl` for trait `PartialEq` which is not marked with `#[const_trait]`
-  --> $DIR/call-generic-method-pass.rs:10:12
-   |
-LL | impl const PartialEq for S {
-   |            ^^^^^^^^^
-   |
-   = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const`
-   = note: adding a non-const method body in the future would be a breaking change
-
-error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/call-generic-method-pass.rs:19:32
-   |
-LL | const fn equals_self<T: ~const PartialEq>(t: &T) -> bool {
-   |                                ^^^^^^^^^
-
-error: aborting due to 3 previous errors; 1 warning emitted
-
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-bound-on-not-const-associated-fn.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-bound-on-not-const-associated-fn.stderr
deleted file mode 100644
index b5d9b1f..0000000
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-bound-on-not-const-associated-fn.stderr
+++ /dev/null
@@ -1,31 +0,0 @@
-error: `~const` is not allowed here
-  --> $DIR/const-bound-on-not-const-associated-fn.rs:10:40
-   |
-LL |     fn do_something_else() where Self: ~const MyTrait;
-   |                                        ^^^^^^
-   |
-note: this function is not `const`, so it cannot have `~const` trait bounds
-  --> $DIR/const-bound-on-not-const-associated-fn.rs:10:8
-   |
-LL |     fn do_something_else() where Self: ~const MyTrait;
-   |        ^^^^^^^^^^^^^^^^^
-
-error: `~const` is not allowed here
-  --> $DIR/const-bound-on-not-const-associated-fn.rs:21:32
-   |
-LL |     pub fn foo(&self) where T: ~const MyTrait {
-   |                                ^^^^^^
-   |
-note: this function is not `const`, so it cannot have `~const` trait bounds
-  --> $DIR/const-bound-on-not-const-associated-fn.rs:21:12
-   |
-LL |     pub fn foo(&self) where T: ~const MyTrait {
-   |            ^^^
-
-error: using `#![feature(effects)]` without enabling next trait solver globally
-   |
-   = note: the next trait solver must be enabled globally for the effects feature to work correctly
-   = help: use `-Znext-solver` to enable
-
-error: aborting due to 3 previous errors
-
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method-fail.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method-fail.stderr
deleted file mode 100644
index 507ceaa..0000000
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method-fail.stderr
+++ /dev/null
@@ -1,35 +0,0 @@
-error[E0049]: method `a` has 1 const parameter but its trait declaration has 0 const parameters
-  --> $DIR/const-closure-trait-method-fail.rs:5:1
-   |
-LL | #[const_trait]
-   | ^^^^^^^^^^^^^^ found 1 const parameter
-LL | trait Tr {
-LL |     fn a(self) -> i32;
-   |         - expected 0 const parameters
-
-error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-closure-trait-method-fail.rs:14:39
-   |
-LL | const fn need_const_closure<T: ~const FnOnce(()) -> i32>(x: T) -> i32 {
-   |                                       ^^^^^^^^^^^^^^^^^
-
-error[E0015]: cannot call non-const closure in constant functions
-  --> $DIR/const-closure-trait-method-fail.rs:15:5
-   |
-LL |     x(())
-   |     ^^^^^
-   |
-   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: consider further restricting this bound
-   |
-LL | const fn need_const_closure<T: ~const FnOnce(()) -> i32 + ~const FnOnce(())>(x: T) -> i32 {
-   |                                                         +++++++++++++++++++
-help: add `#![feature(effects)]` to the crate attributes to enable
-   |
-LL + #![feature(effects)]
-   |
-
-error: aborting due to 3 previous errors
-
-Some errors have detailed explanations: E0015, E0049.
-For more information about an error, try `rustc --explain E0015`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method.stderr
deleted file mode 100644
index 2a54cd5..0000000
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method.stderr
+++ /dev/null
@@ -1,35 +0,0 @@
-error[E0049]: method `a` has 1 const parameter but its trait declaration has 0 const parameters
-  --> $DIR/const-closure-trait-method.rs:5:1
-   |
-LL | #[const_trait]
-   | ^^^^^^^^^^^^^^ found 1 const parameter
-LL | trait Tr {
-LL |     fn a(self) -> i32;
-   |         - expected 0 const parameters
-
-error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-closure-trait-method.rs:14:39
-   |
-LL | const fn need_const_closure<T: ~const FnOnce(()) -> i32>(x: T) -> i32 {
-   |                                       ^^^^^^^^^^^^^^^^^
-
-error[E0015]: cannot call non-const closure in constant functions
-  --> $DIR/const-closure-trait-method.rs:15:5
-   |
-LL |     x(())
-   |     ^^^^^
-   |
-   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: consider further restricting this bound
-   |
-LL | const fn need_const_closure<T: ~const FnOnce(()) -> i32 + ~const FnOnce(())>(x: T) -> i32 {
-   |                                                         +++++++++++++++++++
-help: add `#![feature(effects)]` to the crate attributes to enable
-   |
-LL + #![feature(effects)]
-   |
-
-error: aborting due to 3 previous errors
-
-Some errors have detailed explanations: E0015, E0049.
-For more information about an error, try `rustc --explain E0015`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closures.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closures.stderr
deleted file mode 100644
index a0f0532..0000000
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closures.stderr
+++ /dev/null
@@ -1,75 +0,0 @@
-error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-closures.rs:8:19
-   |
-LL |         F: ~const FnOnce() -> u8,
-   |                   ^^^^^^^^^^^^^^
-
-error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-closures.rs:9:19
-   |
-LL |         F: ~const FnMut() -> u8,
-   |                   ^^^^^^^^^^^^^
-
-error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-closures.rs:10:19
-   |
-LL |         F: ~const Fn() -> u8,
-   |                   ^^^^^^^^^^
-
-error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-closures.rs:23:27
-   |
-LL | const fn answer<F: ~const Fn() -> u8>(f: &F) -> u8 {
-   |                           ^^^^^^^^^^
-
-error[E0015]: cannot call non-const closure in constant functions
-  --> $DIR/const-closures.rs:24:5
-   |
-LL |     f() + f()
-   |     ^^^
-   |
-   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: consider further restricting this bound
-   |
-LL | const fn answer<F: ~const Fn() -> u8 + ~const Fn()>(f: &F) -> u8 {
-   |                                      +++++++++++++
-help: add `#![feature(effects)]` to the crate attributes to enable
-   |
-LL + #![feature(effects)]
-   |
-
-error[E0015]: cannot call non-const closure in constant functions
-  --> $DIR/const-closures.rs:24:11
-   |
-LL |     f() + f()
-   |           ^^^
-   |
-   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: consider further restricting this bound
-   |
-LL | const fn answer<F: ~const Fn() -> u8 + ~const Fn()>(f: &F) -> u8 {
-   |                                      +++++++++++++
-help: add `#![feature(effects)]` to the crate attributes to enable
-   |
-LL + #![feature(effects)]
-   |
-
-error[E0015]: cannot call non-const closure in constant functions
-  --> $DIR/const-closures.rs:12:5
-   |
-LL |     f() * 7
-   |     ^^^
-   |
-   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: consider further restricting this bound
-   |
-LL |         F: ~const FnOnce() -> u8 + ~const Fn(),
-   |                                  +++++++++++++
-help: add `#![feature(effects)]` to the crate attributes to enable
-   |
-LL + #![feature(effects)]
-   |
-
-error: aborting due to 7 previous errors
-
-For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-default-method-bodies.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-default-method-bodies.stderr
deleted file mode 100644
index 0809d9c..0000000
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-default-method-bodies.stderr
+++ /dev/null
@@ -1,22 +0,0 @@
-error[E0277]: the trait bound `NonConstImpl: ~const ConstDefaultFn` is not satisfied
-  --> $DIR/const-default-method-bodies.rs:26:18
-   |
-LL |     NonConstImpl.a();
-   |                  ^ the trait `ConstDefaultFn` is not implemented for `NonConstImpl`
-   |
-note: required by a bound in `ConstDefaultFn::a`
-  --> $DIR/const-default-method-bodies.rs:5:1
-   |
-LL | #[const_trait]
-   | ^^^^^^^^^^^^^^ required by this bound in `ConstDefaultFn::a`
-...
-LL |     fn a(self) {
-   |        - required by a bound in this associated function
-help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
-   |
-LL | const fn test() where NonConstImpl: ConstDefaultFn {
-   |                 ++++++++++++++++++++++++++++++++++
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-bound.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-bound.stderr
deleted file mode 100644
index be19700..0000000
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-bound.stderr
+++ /dev/null
@@ -1,27 +0,0 @@
-error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-drop-bound.rs:9:68
-   |
-LL | const fn foo<T, E>(res: Result<T, E>) -> Option<T> where E: ~const Destruct {
-   |                                                                    ^^^^^^^^
-
-error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-drop-bound.rs:20:15
-   |
-LL |     T: ~const Destruct,
-   |               ^^^^^^^^
-
-error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-drop-bound.rs:21:15
-   |
-LL |     E: ~const Destruct,
-   |               ^^^^^^^^
-
-error[E0493]: destructor of `E` cannot be evaluated at compile-time
-  --> $DIR/const-drop-bound.rs:12:13
-   |
-LL |         Err(_e) => None,
-   |             ^^ the destructor for this type cannot be evaluated in constant functions
-
-error: aborting due to 4 previous errors
-
-For more information about this error, try `rustc --explain E0493`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-fns-are-early-bound.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-fns-are-early-bound.rs
deleted file mode 100644
index b308734..0000000
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-fns-are-early-bound.rs
+++ /dev/null
@@ -1,136 +0,0 @@
-//@ known-bug: #110395
-// FIXME(effects) check-pass
-//@ compile-flags: -Znext-solver
-
-#![crate_type = "lib"]
-#![allow(internal_features, incomplete_features)]
-#![no_std]
-#![no_core]
-#![feature(
-    auto_traits,
-    const_trait_impl,
-    effects,
-    lang_items,
-    no_core,
-    staged_api,
-    unboxed_closures,
-    rustc_attrs,
-    marker_trait_attr,
-)]
-#![stable(feature = "minicore", since = "1.0.0")]
-
-fn test() {
-    fn is_const_fn<F>(_: F)
-    where
-        F: const FnOnce<()>,
-    {
-    }
-
-    const fn foo() {}
-
-    is_const_fn(foo);
-}
-
-/// ---------------------------------------------------------------------- ///
-/// Const fn trait definitions
-
-#[const_trait]
-#[lang = "fn"]
-#[rustc_paren_sugar]
-trait Fn<Args: Tuple>: ~const FnMut<Args> {
-    extern "rust-call" fn call(&self, args: Args) -> Self::Output;
-}
-
-#[const_trait]
-#[lang = "fn_mut"]
-#[rustc_paren_sugar]
-trait FnMut<Args: Tuple>: ~const FnOnce<Args> {
-    extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
-}
-
-#[const_trait]
-#[lang = "fn_once"]
-#[rustc_paren_sugar]
-trait FnOnce<Args: Tuple> {
-    #[lang = "fn_once_output"]
-    type Output;
-
-    extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
-}
-
-/// ---------------------------------------------------------------------- ///
-/// All this other stuff needed for core. Unrelated to test.
-
-#[lang = "destruct"]
-#[const_trait]
-trait Destruct {}
-
-#[lang = "freeze"]
-unsafe auto trait Freeze {}
-
-#[lang = "drop"]
-#[const_trait]
-trait Drop {
-    fn drop(&mut self);
-}
-
-#[lang = "sized"]
-trait Sized {}
-#[lang = "copy"]
-trait Copy {}
-
-#[lang = "tuple_trait"]
-trait Tuple {}
-
-#[lang = "receiver"]
-trait Receiver {}
-
-impl<T: ?Sized> Receiver for &T {}
-
-impl<T: ?Sized> Receiver for &mut T {}
-
-#[stable(feature = "minicore", since = "1.0.0")]
-pub mod effects {
-    use super::Sized;
-
-    #[lang = "EffectsNoRuntime"]
-    #[stable(feature = "minicore", since = "1.0.0")]
-    pub struct NoRuntime;
-    #[lang = "EffectsMaybe"]
-    #[stable(feature = "minicore", since = "1.0.0")]
-    pub struct Maybe;
-    #[lang = "EffectsRuntime"]
-    #[stable(feature = "minicore", since = "1.0.0")]
-    pub struct Runtime;
-
-    #[lang = "EffectsCompat"]
-    #[stable(feature = "minicore", since = "1.0.0")]
-    pub trait Compat<#[rustc_runtime] const RUNTIME: bool> {}
-
-    #[stable(feature = "minicore", since = "1.0.0")]
-    impl Compat<false> for NoRuntime {}
-    #[stable(feature = "minicore", since = "1.0.0")]
-    impl Compat<true> for Runtime {}
-    #[stable(feature = "minicore", since = "1.0.0")]
-    impl<#[rustc_runtime] const RUNTIME: bool> Compat<RUNTIME> for Maybe {}
-
-    #[lang = "EffectsTyCompat"]
-    #[marker]
-    #[stable(feature = "minicore", since = "1.0.0")]
-    pub trait TyCompat<T: ?Sized> {}
-
-    #[stable(feature = "minicore", since = "1.0.0")]
-    impl<T: ?Sized> TyCompat<T> for T {}
-    #[stable(feature = "minicore", since = "1.0.0")]
-    impl<T: ?Sized> TyCompat<T> for Maybe {}
-    #[stable(feature = "minicore", since = "1.0.0")]
-    impl<T: ?Sized> TyCompat<Maybe> for T {}
-
-    #[lang = "EffectsIntersection"]
-    #[stable(feature = "minicore", since = "1.0.0")]
-    pub trait Intersection {
-        #[lang = "EffectsIntersectionOutput"]
-        #[stable(feature = "minicore", since = "1.0.0")]
-        type Output: ?Sized;
-    }
-}
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-fns-are-early-bound.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-fns-are-early-bound.stderr
deleted file mode 100644
index 9eda9d9..0000000
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-fns-are-early-bound.stderr
+++ /dev/null
@@ -1,20 +0,0 @@
-error[E0277]: the trait bound `fn() {foo}: const FnOnce()` is not satisfied
-  --> $DIR/const-fns-are-early-bound.rs:31:17
-   |
-LL |     is_const_fn(foo);
-   |     ----------- ^^^ the trait `FnOnce()` is not implemented for fn item `fn() {foo}`
-   |     |
-   |     required by a bound introduced by this call
-   |
-note: required by a bound in `is_const_fn`
-  --> $DIR/const-fns-are-early-bound.rs:25:12
-   |
-LL |     fn is_const_fn<F>(_: F)
-   |        ----------- required by a bound in this function
-LL |     where
-LL |         F: const FnOnce<()>,
-   |            ^^^^^^^^^^^^^^^^ required by this bound in `is_const_fn`
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-requires-const-trait.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-requires-const-trait.rs
deleted file mode 100644
index bd6f476..0000000
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-requires-const-trait.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-//@ known-bug: #110395
-
-#![feature(const_trait_impl, effects)]
-
-pub trait A {}
-// FIXME ~^ HELP: mark `A` as const
-
-impl const A for () {}
-// FIXME ~^ ERROR: const `impl` for trait `A` which is not marked with `#[const_trait]`
-
-fn main() {}
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-requires-const-trait.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-requires-const-trait.stderr
deleted file mode 100644
index 2a03036..0000000
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-requires-const-trait.stderr
+++ /dev/null
@@ -1,28 +0,0 @@
-warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/const-impl-requires-const-trait.rs:3:30
-   |
-LL | #![feature(const_trait_impl, effects)]
-   |                              ^^^^^^^
-   |
-   = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
-   = note: `#[warn(incomplete_features)]` on by default
-
-error: using `#![feature(effects)]` without enabling next trait solver globally
-   |
-   = note: the next trait solver must be enabled globally for the effects feature to work correctly
-   = help: use `-Znext-solver` to enable
-
-error: const `impl` for trait `A` which is not marked with `#[const_trait]`
-  --> $DIR/const-impl-requires-const-trait.rs:8:12
-   |
-LL | pub trait A {}
-   | - help: mark `A` as const: `#[const_trait]`
-...
-LL | impl const A for () {}
-   |            ^
-   |
-   = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const`
-   = note: adding a non-const method body in the future would be a breaking change
-
-error: aborting due to 2 previous errors; 1 warning emitted
-
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-trait.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-trait.stderr
deleted file mode 100644
index 1040af7..0000000
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-trait.stderr
+++ /dev/null
@@ -1,249 +0,0 @@
-error[E0635]: unknown feature `const_cmp`
-  --> $DIR/const-impl-trait.rs:8:5
-   |
-LL |     const_cmp,
-   |     ^^^^^^^^^
-
-error: using `#![feature(effects)]` without enabling next trait solver globally
-   |
-   = note: the next trait solver must be enabled globally for the effects feature to work correctly
-   = help: use `-Znext-solver` to enable
-
-error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-impl-trait.rs:13:30
-   |
-LL | const fn cmp(a: &impl ~const PartialEq) -> bool {
-   |                              ^^^^^^^^^
-
-error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-impl-trait.rs:17:30
-   |
-LL | const fn wrap(x: impl ~const PartialEq + ~const Destruct)
-   |                              ^^^^^^^^^
-
-error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-impl-trait.rs:17:49
-   |
-LL | const fn wrap(x: impl ~const PartialEq + ~const Destruct)
-   |                                                 ^^^^^^^^
-
-error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-impl-trait.rs:18:20
-   |
-LL |     -> impl ~const PartialEq + ~const Destruct
-   |                    ^^^^^^^^^
-
-error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-impl-trait.rs:18:39
-   |
-LL |     -> impl ~const PartialEq + ~const Destruct
-   |                                       ^^^^^^^^
-
-error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-impl-trait.rs:18:20
-   |
-LL |     -> impl ~const PartialEq + ~const Destruct
-   |                    ^^^^^^^^^
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-impl-trait.rs:18:39
-   |
-LL |     -> impl ~const PartialEq + ~const Destruct
-   |                                       ^^^^^^^^
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-impl-trait.rs:25:29
-   |
-LL |     fn huh() -> impl ~const PartialEq + ~const Destruct + Copy;
-   |                             ^^^^^^^^^
-
-error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-impl-trait.rs:25:48
-   |
-LL |     fn huh() -> impl ~const PartialEq + ~const Destruct + Copy;
-   |                                                ^^^^^^^^
-
-error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-impl-trait.rs:29:29
-   |
-LL |     fn huh() -> impl ~const PartialEq + ~const Destruct + Copy {
-   |                             ^^^^^^^^^
-
-error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-impl-trait.rs:29:48
-   |
-LL |     fn huh() -> impl ~const PartialEq + ~const Destruct + Copy {
-   |                                                ^^^^^^^^
-
-error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-impl-trait.rs:29:29
-   |
-LL |     fn huh() -> impl ~const PartialEq + ~const Destruct + Copy {
-   |                             ^^^^^^^^^
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-impl-trait.rs:29:48
-   |
-LL |     fn huh() -> impl ~const PartialEq + ~const Destruct + Copy {
-   |                                                ^^^^^^^^
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-impl-trait.rs:50:41
-   |
-LL | const fn apit(_: impl ~const T + ~const Destruct) {}
-   |                                         ^^^^^^^^
-
-error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-impl-trait.rs:54:73
-   |
-LL | const fn apit_assoc_bound(_: impl IntoIterator<Item: ~const T> + ~const Destruct) {}
-   |                                                                         ^^^^^^^^
-
-error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-impl-trait.rs:25:29
-   |
-LL |     fn huh() -> impl ~const PartialEq + ~const Destruct + Copy;
-   |                             ^^^^^^^^^
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-impl-trait.rs:25:48
-   |
-LL |     fn huh() -> impl ~const PartialEq + ~const Destruct + Copy;
-   |                                                ^^^^^^^^
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-impl-trait.rs:25:29
-   |
-LL |     fn huh() -> impl ~const PartialEq + ~const Destruct + Copy;
-   |                             ^^^^^^^^^
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-impl-trait.rs:25:48
-   |
-LL |     fn huh() -> impl ~const PartialEq + ~const Destruct + Copy;
-   |                                                ^^^^^^^^
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-impl-trait.rs:25:29
-   |
-LL |     fn huh() -> impl ~const PartialEq + ~const Destruct + Copy;
-   |                             ^^^^^^^^^
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-impl-trait.rs:25:48
-   |
-LL |     fn huh() -> impl ~const PartialEq + ~const Destruct + Copy;
-   |                                                ^^^^^^^^
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error[E0493]: destructor of `impl PartialEq + Destruct` cannot be evaluated at compile-time
-  --> $DIR/const-impl-trait.rs:37:26
-   |
-LL |     assert!(wrap(123) == wrap(123));
-   |                          ^^^^^^^^^- value is dropped here
-   |                          |
-   |                          the destructor for this type cannot be evaluated in constants
-
-error[E0493]: destructor of `impl PartialEq + Destruct` cannot be evaluated at compile-time
-  --> $DIR/const-impl-trait.rs:37:26
-   |
-LL |     assert!(wrap(123) == wrap(123));
-   |                          ^^^^^^^^^- value is dropped here
-   |                          |
-   |                          the destructor for this type cannot be evaluated in constants
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error[E0493]: destructor of `impl PartialEq + Destruct` cannot be evaluated at compile-time
-  --> $DIR/const-impl-trait.rs:37:13
-   |
-LL |     assert!(wrap(123) == wrap(123));
-   |             ^^^^^^^^^             - value is dropped here
-   |             |
-   |             the destructor for this type cannot be evaluated in constants
-
-error[E0493]: destructor of `impl PartialEq + Destruct` cannot be evaluated at compile-time
-  --> $DIR/const-impl-trait.rs:37:13
-   |
-LL |     assert!(wrap(123) == wrap(123));
-   |             ^^^^^^^^^             - value is dropped here
-   |             |
-   |             the destructor for this type cannot be evaluated in constants
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error[E0493]: destructor of `impl PartialEq + Destruct` cannot be evaluated at compile-time
-  --> $DIR/const-impl-trait.rs:38:26
-   |
-LL |     assert!(wrap(123) != wrap(456));
-   |                          ^^^^^^^^^- value is dropped here
-   |                          |
-   |                          the destructor for this type cannot be evaluated in constants
-
-error[E0493]: destructor of `impl PartialEq + Destruct` cannot be evaluated at compile-time
-  --> $DIR/const-impl-trait.rs:38:26
-   |
-LL |     assert!(wrap(123) != wrap(456));
-   |                          ^^^^^^^^^- value is dropped here
-   |                          |
-   |                          the destructor for this type cannot be evaluated in constants
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error[E0493]: destructor of `impl PartialEq + Destruct` cannot be evaluated at compile-time
-  --> $DIR/const-impl-trait.rs:38:13
-   |
-LL |     assert!(wrap(123) != wrap(456));
-   |             ^^^^^^^^^             - value is dropped here
-   |             |
-   |             the destructor for this type cannot be evaluated in constants
-
-error[E0493]: destructor of `impl PartialEq + Destruct` cannot be evaluated at compile-time
-  --> $DIR/const-impl-trait.rs:38:13
-   |
-LL |     assert!(wrap(123) != wrap(456));
-   |             ^^^^^^^^^             - value is dropped here
-   |             |
-   |             the destructor for this type cannot be evaluated in constants
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error[E0493]: destructor of `impl ~const T + ~const Destruct` cannot be evaluated at compile-time
-  --> $DIR/const-impl-trait.rs:50:15
-   |
-LL | const fn apit(_: impl ~const T + ~const Destruct) {}
-   |               ^                                    - value is dropped here
-   |               |
-   |               the destructor for this type cannot be evaluated in constant functions
-
-error[E0493]: destructor of `impl IntoIterator<Item : ~const T> + ~const Destruct` cannot be evaluated at compile-time
-  --> $DIR/const-impl-trait.rs:54:27
-   |
-LL | const fn apit_assoc_bound(_: impl IntoIterator<Item: ~const T> + ~const Destruct) {}
-   |                           ^                                                        - value is dropped here
-   |                           |
-   |                           the destructor for this type cannot be evaluated in constant functions
-
-error: aborting due to 33 previous errors
-
-Some errors have detailed explanations: E0493, E0635.
-For more information about an error, try `rustc --explain E0493`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate.gatednc.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate.gatednc.stderr
deleted file mode 100644
index a34bae8..0000000
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate.gatednc.stderr
+++ /dev/null
@@ -1,22 +0,0 @@
-error[E0277]: the trait bound `cross_crate::NonConst: ~const cross_crate::MyTrait` is not satisfied
-  --> $DIR/cross-crate.rs:19:14
-   |
-LL |     NonConst.func();
-   |              ^^^^ the trait `cross_crate::MyTrait` is not implemented for `cross_crate::NonConst`
-   |
-note: required by a bound in `func`
-  --> $DIR/auxiliary/cross-crate.rs:5:1
-   |
-LL | #[const_trait]
-   | ^^^^^^^^^^^^^^ required by this bound in `MyTrait::func`
-...
-LL |     fn func(self);
-   |        ---- required by a bound in this associated function
-help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
-   |
-LL | const fn const_context() where cross_crate::NonConst: cross_crate::MyTrait {
-   |                          +++++++++++++++++++++++++++++++++++++++++++++++++
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr
deleted file mode 100644
index d0f22c0..0000000
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr
+++ /dev/null
@@ -1,22 +0,0 @@
-error[E0277]: the trait bound `(): ~const Tr` is not satisfied
-  --> $DIR/default-method-body-is-const-same-trait-ck.rs:10:12
-   |
-LL |         ().a()
-   |            ^ the trait `Tr` is not implemented for `()`
-   |
-note: required by a bound in `Tr::a`
-  --> $DIR/default-method-body-is-const-same-trait-ck.rs:5:1
-   |
-LL | #[const_trait]
-   | ^^^^^^^^^^^^^^ required by this bound in `Tr::a`
-LL | pub trait Tr {
-LL |     fn a(&self) {}
-   |        - required by a bound in this associated function
-help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
-   |
-LL | pub trait Tr where (): Tr {
-   |              ++++++++++++
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.stderr
deleted file mode 100644
index 823ab69..0000000
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.stderr
+++ /dev/null
@@ -1,13 +0,0 @@
-error: the compiler unexpectedly panicked. this is a bug.
-
-query stack during panic:
-#0 [check_well_formed] checking that `<impl at $DIR/minicore.rs:459:1: 459:36>` is well-formed
-#1 [check_mod_type_wf] checking that types are well-formed in top-level module
-end of query stack
-
-error: the compiler unexpectedly panicked. this is a bug.
-
-query stack during panic:
-#0 [check_well_formed] checking that `drop` is well-formed
-#1 [check_mod_type_wf] checking that types are well-formed in top-level module
-end of query stack
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/hir-const-check.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/hir-const-check.stderr
deleted file mode 100644
index 598129d..0000000
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/hir-const-check.stderr
+++ /dev/null
@@ -1,27 +0,0 @@
-warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/hir-const-check.rs:3:30
-   |
-LL | #![feature(const_trait_impl, effects)]
-   |                              ^^^^^^^
-   |
-   = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
-   = note: `#[warn(incomplete_features)]` on by default
-
-error[E0658]: `?` is not allowed in a `const fn`
-  --> $DIR/hir-const-check.rs:12:9
-   |
-LL |         Some(())?;
-   |         ^^^^^^^^^
-   |
-   = note: see issue #74935 <https://github.com/rust-lang/rust/issues/74935> for more information
-   = help: add `#![feature(const_try)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error: using `#![feature(effects)]` without enabling next trait solver globally
-   |
-   = note: the next trait solver must be enabled globally for the effects feature to work correctly
-   = help: use `-Znext-solver` to enable
-
-error: aborting due to 2 previous errors; 1 warning emitted
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-123664-unexpected-bound-var.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-123664-unexpected-bound-var.stderr
deleted file mode 100644
index c937430..0000000
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-123664-unexpected-bound-var.stderr
+++ /dev/null
@@ -1,13 +0,0 @@
-error: using `#![feature(effects)]` without enabling next trait solver globally
-   |
-   = note: the next trait solver must be enabled globally for the effects feature to work correctly
-   = help: use `-Znext-solver` to enable
-
-error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/ice-123664-unexpected-bound-var.rs:4:34
-   |
-LL | const fn with_positive<F: ~const Fn()>() {}
-   |                                  ^^^^
-
-error: aborting due to 2 previous errors
-
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/match-non-const-eq.stock.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/match-non-const-eq.stock.stderr
deleted file mode 100644
index 0f5ecac..0000000
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/match-non-const-eq.stock.stderr
+++ /dev/null
@@ -1,16 +0,0 @@
-error[E0015]: cannot match on `str` in constant functions
-  --> $DIR/match-non-const-eq.rs:7:9
-   |
-LL |         "a" => (), //FIXME [gated]~ ERROR can't compare `str` with `str` in const contexts
-   |         ^^^
-   |
-   = note: `str` cannot be compared in compile-time, and therefore cannot be used in `match`es
-   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/non-const-op-in-closure-in-const.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/non-const-op-in-closure-in-const.stderr
deleted file mode 100644
index de4783b..0000000
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/non-const-op-in-closure-in-const.stderr
+++ /dev/null
@@ -1,31 +0,0 @@
-error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/non-const-op-in-closure-in-const.rs:10:51
-   |
-LL | impl<A, B> const Convert<B> for A where B: ~const From<A> {
-   |                                                   ^^^^^^^
-
-error[E0049]: method `to` has 1 const parameter but its trait declaration has 0 const parameters
-  --> $DIR/non-const-op-in-closure-in-const.rs:5:1
-   |
-LL | #[const_trait]
-   | ^^^^^^^^^^^^^^ found 1 const parameter
-LL | trait Convert<T> {
-LL |     fn to(self) -> T;
-   |          - expected 0 const parameters
-
-error[E0015]: cannot call non-const fn `<B as From<A>>::from` in constant functions
-  --> $DIR/non-const-op-in-closure-in-const.rs:12:9
-   |
-LL |         B::from(self)
-   |         ^^^^^^^^^^^^^
-   |
-   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(effects)]` to the crate attributes to enable
-   |
-LL + #![feature(effects)]
-   |
-
-error: aborting due to 3 previous errors
-
-Some errors have detailed explanations: E0015, E0049.
-For more information about an error, try `rustc --explain E0015`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.stderr
deleted file mode 100644
index 7643697..0000000
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.stderr
+++ /dev/null
@@ -1,41 +0,0 @@
-error[E0049]: associated function `bar` has 1 const parameter but its trait declaration has 0 const parameters
-  --> $DIR/const-default-bound-non-const-specialized-bound.rs:16:1
-   |
-LL | #[const_trait]
-   | ^^^^^^^^^^^^^^ found 1 const parameter
-LL | trait Bar {
-LL |     fn bar();
-   |           - expected 0 const parameters
-
-error: cannot specialize on const impl with non-const impl
-  --> $DIR/const-default-bound-non-const-specialized-bound.rs:28:1
-   |
-LL | / impl<T> Bar for T
-LL | | where
-LL | |     T: Foo, //FIXME ~ ERROR missing `~const` qualifier
-LL | |     T: Specialize,
-   | |__________________^
-
-error[E0049]: associated function `baz` has 1 const parameter but its trait declaration has 0 const parameters
-  --> $DIR/const-default-bound-non-const-specialized-bound.rs:36:1
-   |
-LL | #[const_trait]
-   | ^^^^^^^^^^^^^^ found 1 const parameter
-LL | trait Baz {
-LL |     fn baz();
-   |           - expected 0 const parameters
-
-error[E0049]: associated function `baz` has 1 const parameter but its trait declaration has 0 const parameters
-  --> $DIR/const-default-bound-non-const-specialized-bound.rs:36:1
-   |
-LL | #[const_trait]
-   | ^^^^^^^^^^^^^^ found 1 const parameter
-LL | trait Baz {
-LL |     fn baz();
-   |           - expected 0 const parameters
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: aborting due to 4 previous errors
-
-For more information about this error, try `rustc --explain E0049`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-const-specialized.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-const-specialized.stderr
deleted file mode 100644
index 9b2ae8d..0000000
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-const-specialized.stderr
+++ /dev/null
@@ -1,36 +0,0 @@
-error[E0049]: associated function `value` has 1 const parameter but its trait declaration has 0 const parameters
-  --> $DIR/const-default-const-specialized.rs:10:1
-   |
-LL | #[const_trait]
-   | ^^^^^^^^^^^^^^ found 1 const parameter
-LL | trait Value {
-LL |     fn value() -> u32;
-   |             - expected 0 const parameters
-
-error[E0049]: associated function `value` has 1 const parameter but its trait declaration has 0 const parameters
-  --> $DIR/const-default-const-specialized.rs:10:1
-   |
-LL | #[const_trait]
-   | ^^^^^^^^^^^^^^ found 1 const parameter
-LL | trait Value {
-LL |     fn value() -> u32;
-   |             - expected 0 const parameters
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error[E0015]: cannot call non-const fn `<T as Value>::value` in constant functions
-  --> $DIR/const-default-const-specialized.rs:16:5
-   |
-LL |     T::value()
-   |     ^^^^^^^^^^
-   |
-   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(effects)]` to the crate attributes to enable
-   |
-LL + #![feature(effects)]
-   |
-
-error: aborting due to 3 previous errors
-
-Some errors have detailed explanations: E0015, E0049.
-For more information about an error, try `rustc --explain E0015`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/default-keyword.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/default-keyword.stderr
deleted file mode 100644
index 18a2504..0000000
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/default-keyword.stderr
+++ /dev/null
@@ -1,12 +0,0 @@
-error[E0049]: associated function `foo` has 1 const parameter but its trait declaration has 0 const parameters
-  --> $DIR/default-keyword.rs:7:1
-   |
-LL | #[const_trait]
-   | ^^^^^^^^^^^^^^ found 1 const parameter
-LL | trait Foo {
-LL |     fn foo();
-   |           - expected 0 const parameters
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0049`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95186-specialize-on-tilde-const.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95186-specialize-on-tilde-const.stderr
deleted file mode 100644
index ecdc7b9..0000000
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95186-specialize-on-tilde-const.stderr
+++ /dev/null
@@ -1,43 +0,0 @@
-error[E0049]: associated function `foo` has 1 const parameter but its trait declaration has 0 const parameters
-  --> $DIR/issue-95186-specialize-on-tilde-const.rs:14:1
-   |
-LL | #[const_trait]
-   | ^^^^^^^^^^^^^^ found 1 const parameter
-LL | trait Foo {
-LL |     fn foo();
-   |           - expected 0 const parameters
-
-error[E0049]: associated function `foo` has 1 const parameter but its trait declaration has 0 const parameters
-  --> $DIR/issue-95186-specialize-on-tilde-const.rs:14:1
-   |
-LL | #[const_trait]
-   | ^^^^^^^^^^^^^^ found 1 const parameter
-LL | trait Foo {
-LL |     fn foo();
-   |           - expected 0 const parameters
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error[E0049]: associated function `bar` has 1 const parameter but its trait declaration has 0 const parameters
-  --> $DIR/issue-95186-specialize-on-tilde-const.rs:30:1
-   |
-LL | #[const_trait]
-   | ^^^^^^^^^^^^^^ found 1 const parameter
-LL | trait Bar {
-LL |     fn bar() {}
-   |           - expected 0 const parameters
-
-error[E0049]: associated function `bar` has 1 const parameter but its trait declaration has 0 const parameters
-  --> $DIR/issue-95186-specialize-on-tilde-const.rs:30:1
-   |
-LL | #[const_trait]
-   | ^^^^^^^^^^^^^^ found 1 const parameter
-LL | trait Bar {
-LL |     fn bar() {}
-   |           - expected 0 const parameters
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: aborting due to 4 previous errors
-
-For more information about this error, try `rustc --explain E0049`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95187-same-trait-bound-different-constness.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95187-same-trait-bound-different-constness.stderr
deleted file mode 100644
index 6679bb4..0000000
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95187-same-trait-bound-different-constness.stderr
+++ /dev/null
@@ -1,43 +0,0 @@
-error[E0049]: associated function `bar` has 1 const parameter but its trait declaration has 0 const parameters
-  --> $DIR/issue-95187-same-trait-bound-different-constness.rs:18:1
-   |
-LL | #[const_trait]
-   | ^^^^^^^^^^^^^^ found 1 const parameter
-LL | trait Bar {
-LL |     fn bar();
-   |           - expected 0 const parameters
-
-error[E0049]: associated function `bar` has 1 const parameter but its trait declaration has 0 const parameters
-  --> $DIR/issue-95187-same-trait-bound-different-constness.rs:18:1
-   |
-LL | #[const_trait]
-   | ^^^^^^^^^^^^^^ found 1 const parameter
-LL | trait Bar {
-LL |     fn bar();
-   |           - expected 0 const parameters
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error[E0049]: associated function `baz` has 1 const parameter but its trait declaration has 0 const parameters
-  --> $DIR/issue-95187-same-trait-bound-different-constness.rs:38:1
-   |
-LL | #[const_trait]
-   | ^^^^^^^^^^^^^^ found 1 const parameter
-LL | trait Baz {
-LL |     fn baz();
-   |           - expected 0 const parameters
-
-error[E0049]: associated function `baz` has 1 const parameter but its trait declaration has 0 const parameters
-  --> $DIR/issue-95187-same-trait-bound-different-constness.rs:38:1
-   |
-LL | #[const_trait]
-   | ^^^^^^^^^^^^^^ found 1 const parameter
-LL | trait Baz {
-LL |     fn baz();
-   |           - expected 0 const parameters
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: aborting due to 4 previous errors
-
-For more information about this error, try `rustc --explain E0049`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/non-const-default-const-specialized.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/non-const-default-const-specialized.stderr
deleted file mode 100644
index 7f36392..0000000
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/non-const-default-const-specialized.stderr
+++ /dev/null
@@ -1,36 +0,0 @@
-error[E0049]: associated function `value` has 1 const parameter but its trait declaration has 0 const parameters
-  --> $DIR/non-const-default-const-specialized.rs:9:1
-   |
-LL | #[const_trait]
-   | ^^^^^^^^^^^^^^ found 1 const parameter
-LL | trait Value {
-LL |     fn value() -> u32;
-   |             - expected 0 const parameters
-
-error[E0049]: associated function `value` has 1 const parameter but its trait declaration has 0 const parameters
-  --> $DIR/non-const-default-const-specialized.rs:9:1
-   |
-LL | #[const_trait]
-   | ^^^^^^^^^^^^^^ found 1 const parameter
-LL | trait Value {
-LL |     fn value() -> u32;
-   |             - expected 0 const parameters
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error[E0015]: cannot call non-const fn `<T as Value>::value` in constant functions
-  --> $DIR/non-const-default-const-specialized.rs:15:5
-   |
-LL |     T::value()
-   |     ^^^^^^^^^^
-   |
-   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(effects)]` to the crate attributes to enable
-   |
-LL + #![feature(effects)]
-   |
-
-error: aborting due to 3 previous errors
-
-Some errors have detailed explanations: E0015, E0049.
-For more information about an error, try `rustc --explain E0015`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness-2.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness-2.stderr
deleted file mode 100644
index bf273f3..0000000
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness-2.stderr
+++ /dev/null
@@ -1,36 +0,0 @@
-error[E0049]: associated function `a` has 1 const parameter but its trait declaration has 0 const parameters
-  --> $DIR/specializing-constness-2.rs:9:1
-   |
-LL | #[const_trait]
-   | ^^^^^^^^^^^^^^ found 1 const parameter
-LL | pub trait A {
-LL |     fn a() -> u32;
-   |         - expected 0 const parameters
-
-error[E0049]: associated function `a` has 1 const parameter but its trait declaration has 0 const parameters
-  --> $DIR/specializing-constness-2.rs:9:1
-   |
-LL | #[const_trait]
-   | ^^^^^^^^^^^^^^ found 1 const parameter
-LL | pub trait A {
-LL |     fn a() -> u32;
-   |         - expected 0 const parameters
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error[E0015]: cannot call non-const fn `<T as A>::a` in constant functions
-  --> $DIR/specializing-constness-2.rs:27:5
-   |
-LL |     <T as A>::a();
-   |     ^^^^^^^^^^^^^
-   |
-   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(effects)]` to the crate attributes to enable
-   |
-LL + #![feature(effects)]
-   |
-
-error: aborting due to 3 previous errors
-
-Some errors have detailed explanations: E0015, E0049.
-For more information about an error, try `rustc --explain E0015`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/staged-api.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/staged-api.rs
deleted file mode 100644
index f87e723..0000000
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/staged-api.rs
+++ /dev/null
@@ -1,63 +0,0 @@
-//@ revisions: stable unstable
-//@ compile-flags: -Znext-solver
-
-#![cfg_attr(unstable, feature(unstable))] // The feature from the ./auxiliary/staged-api.rs file.
-#![feature(const_trait_impl, effects)]
-#![allow(incomplete_features)]
-#![feature(staged_api)]
-#![stable(feature = "rust1", since = "1.0.0")]
-
-//@ aux-build: staged-api.rs
-extern crate staged_api;
-
-use staged_api::*;
-
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct Foo;
-
-#[stable(feature = "rust1", since = "1.0.0")]
-#[cfg_attr(unstable, rustc_const_unstable(feature = "foo", issue = "none"))]
-#[cfg_attr(stable, rustc_const_stable(feature = "foo", since = "1.0.0"))]
-impl const MyTrait for Foo {
-    //[stable]~^ ERROR trait implementations cannot be const stable yet
-    fn func() {}
-}
-
-// Const stability has no impact on usage in non-const contexts.
-fn non_const_context() {
-    Unstable::func();
-    Foo::func();
-}
-
-#[unstable(feature = "none", issue = "none")]
-const fn const_context() {
-    Unstable::func();
-    //[stable]~^ ERROR not yet stable as a const fn
-    Foo::func();
-    //[unstable]~^ ERROR not yet stable as a const fn
-    // ^ fails, because the `foo` feature is not active
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-#[cfg_attr(unstable, rustc_const_unstable(feature = "foo", issue = "none"))]
-pub const fn const_context_not_const_stable() {
-    //[stable]~^ ERROR function has missing const stability attribute
-    Unstable::func();
-    //[stable]~^ ERROR not yet stable as a const fn
-    Foo::func();
-    //[unstable]~^ ERROR not yet stable as a const fn
-    // ^ fails, because the `foo` feature is not active
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_stable(feature = "cheese", since = "1.0.0")]
-const fn stable_const_context() {
-    Unstable::func();
-    //~^ ERROR not yet stable as a const fn
-    Foo::func();
-    //[unstable]~^ ERROR not yet stable as a const fn
-    const_context_not_const_stable()
-    //[unstable]~^ ERROR not yet stable as a const fn
-}
-
-fn main() {}
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/staged-api.stable.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/staged-api.stable.stderr
deleted file mode 100644
index 6c07a25..0000000
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/staged-api.stable.stderr
+++ /dev/null
@@ -1,49 +0,0 @@
-error: trait implementations cannot be const stable yet
-  --> $DIR/staged-api.rs:21:1
-   |
-LL | / impl const MyTrait for Foo {
-LL | |
-LL | |     fn func() {}
-LL | | }
-   | |_^
-   |
-   = note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information
-
-error: function has missing const stability attribute
-  --> $DIR/staged-api.rs:43:1
-   |
-LL | / pub const fn const_context_not_const_stable() {
-LL | |
-LL | |     Unstable::func();
-LL | |
-...  |
-LL | |     // ^ fails, because the `foo` feature is not active
-LL | | }
-   | |_^
-
-error: `<staged_api::Unstable as staged_api::MyTrait>::func` is not yet stable as a const fn
-  --> $DIR/staged-api.rs:34:5
-   |
-LL |     Unstable::func();
-   |     ^^^^^^^^^^^^^^^^
-   |
-   = help: add `#![feature(unstable)]` to the crate attributes to enable
-
-error: `<staged_api::Unstable as staged_api::MyTrait>::func` is not yet stable as a const fn
-  --> $DIR/staged-api.rs:45:5
-   |
-LL |     Unstable::func();
-   |     ^^^^^^^^^^^^^^^^
-   |
-   = help: add `#![feature(unstable)]` to the crate attributes to enable
-
-error: `<staged_api::Unstable as staged_api::MyTrait>::func` is not yet stable as a const fn
-  --> $DIR/staged-api.rs:55:5
-   |
-LL |     Unstable::func();
-   |     ^^^^^^^^^^^^^^^^
-   |
-   = help: const-stable functions can only call other const-stable functions
-
-error: aborting due to 5 previous errors
-
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/staged-api.unstable.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/staged-api.unstable.stderr
deleted file mode 100644
index 1c772f1..0000000
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/staged-api.unstable.stderr
+++ /dev/null
@@ -1,42 +0,0 @@
-error: `<Foo as staged_api::MyTrait>::func` is not yet stable as a const fn
-  --> $DIR/staged-api.rs:36:5
-   |
-LL |     Foo::func();
-   |     ^^^^^^^^^^^
-   |
-   = help: add `#![feature(foo)]` to the crate attributes to enable
-
-error: `<Foo as staged_api::MyTrait>::func` is not yet stable as a const fn
-  --> $DIR/staged-api.rs:47:5
-   |
-LL |     Foo::func();
-   |     ^^^^^^^^^^^
-   |
-   = help: add `#![feature(foo)]` to the crate attributes to enable
-
-error: `<staged_api::Unstable as staged_api::MyTrait>::func` is not yet stable as a const fn
-  --> $DIR/staged-api.rs:55:5
-   |
-LL |     Unstable::func();
-   |     ^^^^^^^^^^^^^^^^
-   |
-   = help: const-stable functions can only call other const-stable functions
-
-error: `<Foo as staged_api::MyTrait>::func` is not yet stable as a const fn
-  --> $DIR/staged-api.rs:57:5
-   |
-LL |     Foo::func();
-   |     ^^^^^^^^^^^
-   |
-   = help: const-stable functions can only call other const-stable functions
-
-error: `const_context_not_const_stable` is not yet stable as a const fn
-  --> $DIR/staged-api.rs:59:5
-   |
-LL |     const_context_not_const_stable()
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: const-stable functions can only call other const-stable functions
-
-error: aborting due to 5 previous errors
-
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.nn.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.nn.stderr
deleted file mode 100644
index 48bb190..0000000
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.nn.stderr
+++ /dev/null
@@ -1,36 +0,0 @@
-error: `~const` is not allowed here
-  --> $DIR/super-traits-fail-2.rs:12:12
-   |
-LL | trait Bar: ~const Foo {}
-   |            ^^^^^^
-   |
-note: this trait is not a `#[const_trait]`, so it cannot have `~const` trait bounds
-  --> $DIR/super-traits-fail-2.rs:12:1
-   |
-LL | trait Bar: ~const Foo {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/super-traits-fail-2.rs:12:19
-   |
-LL | trait Bar: ~const Foo {}
-   |                   ^^^
-
-error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/super-traits-fail-2.rs:12:19
-   |
-LL | trait Bar: ~const Foo {}
-   |                   ^^^
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/super-traits-fail-2.rs:12:19
-   |
-LL | trait Bar: ~const Foo {}
-   |                   ^^^
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: aborting due to 4 previous errors
-
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.ny.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.ny.stderr
deleted file mode 100644
index 029c3b4..0000000
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.ny.stderr
+++ /dev/null
@@ -1,24 +0,0 @@
-error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/super-traits-fail-2.rs:12:19
-   |
-LL | trait Bar: ~const Foo {}
-   |                   ^^^
-
-error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/super-traits-fail-2.rs:12:19
-   |
-LL | trait Bar: ~const Foo {}
-   |                   ^^^
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/super-traits-fail-2.rs:12:19
-   |
-LL | trait Bar: ~const Foo {}
-   |                   ^^^
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: aborting due to 3 previous errors
-
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.yn.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.yn.stderr
deleted file mode 100644
index 873c57e..0000000
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.yn.stderr
+++ /dev/null
@@ -1,34 +0,0 @@
-error: `~const` is not allowed here
-  --> $DIR/super-traits-fail-2.rs:12:12
-   |
-LL | trait Bar: ~const Foo {}
-   |            ^^^^^^
-   |
-note: this trait is not a `#[const_trait]`, so it cannot have `~const` trait bounds
-  --> $DIR/super-traits-fail-2.rs:12:1
-   |
-LL | trait Bar: ~const Foo {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0277]: the trait bound `T: ~const Foo` is not satisfied
-  --> $DIR/super-traits-fail-2.rs:19:7
-   |
-LL |     x.a();
-   |       ^ the trait `Foo` is not implemented for `T`
-   |
-note: required by a bound in `Foo::a`
-  --> $DIR/super-traits-fail-2.rs:6:25
-   |
-LL | #[cfg_attr(any(yy, yn), const_trait)]
-   |                         ^^^^^^^^^^^ required by this bound in `Foo::a`
-LL | trait Foo {
-LL |     fn a(&self);
-   |        - required by a bound in this associated function
-help: consider further restricting this bound
-   |
-LL | const fn foo<T: Bar + Foo>(x: &T) {
-   |                     +++++
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.yy.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.yy.stderr
deleted file mode 100644
index bea3aea..0000000
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.yy.stderr
+++ /dev/null
@@ -1,22 +0,0 @@
-error[E0277]: the trait bound `T: ~const Foo` is not satisfied
-  --> $DIR/super-traits-fail-2.rs:19:7
-   |
-LL |     x.a();
-   |       ^ the trait `Foo` is not implemented for `T`
-   |
-note: required by a bound in `Foo::a`
-  --> $DIR/super-traits-fail-2.rs:6:25
-   |
-LL | #[cfg_attr(any(yy, yn), const_trait)]
-   |                         ^^^^^^^^^^^ required by this bound in `Foo::a`
-LL | trait Foo {
-LL |     fn a(&self);
-   |        - required by a bound in this associated function
-help: consider further restricting this bound
-   |
-LL | const fn foo<T: Bar + Foo>(x: &T) {
-   |                     +++++
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.nn.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.nn.stderr
deleted file mode 100644
index f40583f..0000000
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.nn.stderr
+++ /dev/null
@@ -1,42 +0,0 @@
-error: `~const` is not allowed here
-  --> $DIR/super-traits-fail-3.rs:14:12
-   |
-LL | trait Bar: ~const Foo {}
-   |            ^^^^^^
-   |
-note: this trait is not a `#[const_trait]`, so it cannot have `~const` trait bounds
-  --> $DIR/super-traits-fail-3.rs:14:1
-   |
-LL | trait Bar: ~const Foo {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/super-traits-fail-3.rs:14:19
-   |
-LL | trait Bar: ~const Foo {}
-   |                   ^^^
-
-error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/super-traits-fail-3.rs:14:19
-   |
-LL | trait Bar: ~const Foo {}
-   |                   ^^^
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/super-traits-fail-3.rs:14:19
-   |
-LL | trait Bar: ~const Foo {}
-   |                   ^^^
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/super-traits-fail-3.rs:20:24
-   |
-LL | const fn foo<T: ~const Bar>(x: &T) {
-   |                        ^^^
-
-error: aborting due to 5 previous errors
-
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.ny.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.ny.stderr
deleted file mode 100644
index 3f6dfa7..0000000
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.ny.stderr
+++ /dev/null
@@ -1,24 +0,0 @@
-error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/super-traits-fail-3.rs:14:19
-   |
-LL | trait Bar: ~const Foo {}
-   |                   ^^^
-
-error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/super-traits-fail-3.rs:14:19
-   |
-LL | trait Bar: ~const Foo {}
-   |                   ^^^
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/super-traits-fail-3.rs:14:19
-   |
-LL | trait Bar: ~const Foo {}
-   |                   ^^^
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: aborting due to 3 previous errors
-
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.yn.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.yn.stderr
deleted file mode 100644
index bbc9594..0000000
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.yn.stderr
+++ /dev/null
@@ -1,40 +0,0 @@
-error: `~const` is not allowed here
-  --> $DIR/super-traits-fail-3.rs:14:12
-   |
-LL | trait Bar: ~const Foo {}
-   |            ^^^^^^
-   |
-note: this trait is not a `#[const_trait]`, so it cannot have `~const` trait bounds
-  --> $DIR/super-traits-fail-3.rs:14:1
-   |
-LL | trait Bar: ~const Foo {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/super-traits-fail-3.rs:20:24
-   |
-LL | const fn foo<T: ~const Bar>(x: &T) {
-   |                        ^^^
-
-error[E0277]: the trait bound `T: ~const Foo` is not satisfied
-  --> $DIR/super-traits-fail-3.rs:22:7
-   |
-LL |     x.a();
-   |       ^ the trait `Foo` is not implemented for `T`
-   |
-note: required by a bound in `Foo::a`
-  --> $DIR/super-traits-fail-3.rs:8:25
-   |
-LL | #[cfg_attr(any(yy, yn), const_trait)]
-   |                         ^^^^^^^^^^^ required by this bound in `Foo::a`
-LL | trait Foo {
-LL |     fn a(&self);
-   |        - required by a bound in this associated function
-help: consider further restricting this bound
-   |
-LL | const fn foo<T: ~const Bar + Foo>(x: &T) {
-   |                            +++++
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail.stderr
deleted file mode 100644
index 3870f0f..0000000
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail.stderr
+++ /dev/null
@@ -1,24 +0,0 @@
-error[E0277]: the trait bound `Bar::{synthetic#0}: TyCompat<Foo::{synthetic#0}>` is not satisfied
-  --> $DIR/super-traits-fail.rs:19:12
-   |
-LL | impl const Bar for S {}
-   |            ^^^ the trait `TyCompat<Foo::{synthetic#0}>` is not implemented for `Bar::{synthetic#0}`, which is required by `S: Bar`
-   |
-   = help: the trait `Bar` is implemented for `S`
-note: required for `S` to implement `Bar`
-  --> $DIR/super-traits-fail.rs:12:7
-   |
-LL | trait Bar: ~const Foo {}
-   |       ^^^
-
-error[E0277]: the trait bound `Maybe: TyCompat<Foo::{synthetic#0}>` is not satisfied
-   |
-note: required by a bound in `Bar::{synthetic#0}`
-  --> $DIR/super-traits-fail.rs:12:12
-   |
-LL | trait Bar: ~const Foo {}
-   |            ^^^^^^^^^^ required by this bound in `Bar::{synthetic#0}`
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-and-const-params.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-and-const-params.stderr
deleted file mode 100644
index 73526a2..0000000
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-and-const-params.stderr
+++ /dev/null
@@ -1,50 +0,0 @@
-error: `~const` is not allowed here
-  --> $DIR/tilde-const-and-const-params.rs:9:15
-   |
-LL |     fn add<A: ~const Add42>(self) -> Foo<{ A::add(N) }> {
-   |               ^^^^^^
-   |
-note: this function is not `const`, so it cannot have `~const` trait bounds
-  --> $DIR/tilde-const-and-const-params.rs:9:8
-   |
-LL |     fn add<A: ~const Add42>(self) -> Foo<{ A::add(N) }> {
-   |        ^^^
-
-error: `~const` is not allowed here
-  --> $DIR/tilde-const-and-const-params.rs:27:11
-   |
-LL | fn bar<A: ~const Add42, const N: usize>(_: Foo<N>) -> Foo<{ A::add(N) }> {
-   |           ^^^^^^
-   |
-note: this function is not `const`, so it cannot have `~const` trait bounds
-  --> $DIR/tilde-const-and-const-params.rs:27:4
-   |
-LL | fn bar<A: ~const Add42, const N: usize>(_: Foo<N>) -> Foo<{ A::add(N) }> {
-   |    ^^^
-
-error: using `#![feature(effects)]` without enabling next trait solver globally
-   |
-   = note: the next trait solver must be enabled globally for the effects feature to work correctly
-   = help: use `-Znext-solver` to enable
-
-error[E0308]: mismatched types
-  --> $DIR/tilde-const-and-const-params.rs:27:61
-   |
-LL | fn bar<A: ~const Add42, const N: usize>(_: Foo<N>) -> Foo<{ A::add(N) }> {
-   |                                                             ^^^^^^^^^ expected `false`, found `true`
-   |
-   = note: expected constant `false`
-              found constant `true`
-
-error[E0308]: mismatched types
-  --> $DIR/tilde-const-and-const-params.rs:9:44
-   |
-LL |     fn add<A: ~const Add42>(self) -> Foo<{ A::add(N) }> {
-   |                                            ^^^^^^^^^ expected `false`, found `true`
-   |
-   = note: expected constant `false`
-              found constant `true`
-
-error: aborting due to 5 previous errors
-
-For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-default-body-stability.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-default-body-stability.stderr
deleted file mode 100644
index 49fbef9..0000000
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-default-body-stability.stderr
+++ /dev/null
@@ -1,20 +0,0 @@
-error: const `impl` for trait `Try` which is not marked with `#[const_trait]`
-  --> $DIR/trait-default-body-stability.rs:19:12
-   |
-LL | impl const Try for T {
-   |            ^^^
-   |
-   = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const`
-   = note: adding a non-const method body in the future would be a breaking change
-
-error: const `impl` for trait `FromResidual` which is not marked with `#[const_trait]`
-  --> $DIR/trait-default-body-stability.rs:34:12
-   |
-LL | impl const FromResidual for T {
-   |            ^^^^^^^^^^^^
-   |
-   = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const`
-   = note: adding a non-const method body in the future would be a breaking change
-
-error: aborting due to 2 previous errors
-
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-const.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-const.stderr
deleted file mode 100644
index eaa981e..0000000
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-const.stderr
+++ /dev/null
@@ -1,52 +0,0 @@
-error[E0277]: the trait bound `T: Foo` is not satisfied
-  --> $DIR/trait-where-clause-const.rs:22:5
-   |
-LL |     T::b();
-   |     ^ the trait `Foo` is not implemented for `T`
-   |
-note: required by a bound in `Foo::b`
-  --> $DIR/trait-where-clause-const.rs:13:1
-   |
-LL | #[const_trait]
-   | ^^^^^^^^^^^^^^ required by this bound in `Foo::b`
-...
-LL |     fn b() where Self: ~const Bar;
-   |        - required by a bound in this associated function
-
-error[E0308]: mismatched types
-  --> $DIR/trait-where-clause-const.rs:22:5
-   |
-LL |     T::b();
-   |     ^^^^^^ expected `host`, found `true`
-   |
-   = note: expected constant `host`
-              found constant `true`
-
-error[E0277]: the trait bound `T: Foo` is not satisfied
-  --> $DIR/trait-where-clause-const.rs:25:5
-   |
-LL |     T::c::<T>();
-   |     ^ the trait `Foo` is not implemented for `T`
-   |
-note: required by a bound in `Foo::c`
-  --> $DIR/trait-where-clause-const.rs:13:1
-   |
-LL | #[const_trait]
-   | ^^^^^^^^^^^^^^ required by this bound in `Foo::c`
-...
-LL |     fn c<T: ~const Bar>();
-   |        - required by a bound in this associated function
-
-error[E0308]: mismatched types
-  --> $DIR/trait-where-clause-const.rs:25:5
-   |
-LL |     T::c::<T>();
-   |     ^^^^^^^^^^^ expected `host`, found `true`
-   |
-   = note: expected constant `host`
-              found constant `true`
-
-error: aborting due to 4 previous errors
-
-Some errors have detailed explanations: E0277, E0308.
-For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/unsatisfied-const-trait-bound.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/unsatisfied-const-trait-bound.stderr
deleted file mode 100644
index 848aa68..0000000
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/unsatisfied-const-trait-bound.stderr
+++ /dev/null
@@ -1,46 +0,0 @@
-error: `-Znext-solver=globally` and `generic_const_exprs` are incompatible, using them at the same time is not allowed
-  --> $DIR/unsatisfied-const-trait-bound.rs:5:39
-   |
-LL | #![feature(const_trait_impl, effects, generic_const_exprs)]
-   |                                       ^^^^^^^^^^^^^^^^^^^
-   |
-   = help: remove one of these features
-
-error[E0308]: mismatched types
-  --> $DIR/unsatisfied-const-trait-bound.rs:29:37
-   |
-LL | fn accept0<T: Trait>(_: Container<{ T::make() }>) {}
-   |                                     ^^^^^^^^^ expected `false`, found `true`
-   |
-   = note: expected constant `false`
-              found constant `true`
-
-error[E0308]: mismatched types
-  --> $DIR/unsatisfied-const-trait-bound.rs:33:50
-   |
-LL | const fn accept1<T: ~const Trait>(_: Container<{ T::make() }>) {}
-   |                                                  ^^^^^^^^^ expected `false`, found `host`
-   |
-   = note: expected constant `false`
-              found constant `host`
-
-error[E0277]: the trait bound `Ty: const Trait` is not satisfied
-  --> $DIR/unsatisfied-const-trait-bound.rs:22:15
-   |
-LL |     require::<Ty>();
-   |               ^^ the trait `Trait` is not implemented for `Ty`
-   |
-note: required by a bound in `require`
-  --> $DIR/unsatisfied-const-trait-bound.rs:8:15
-   |
-LL | fn require<T: const Trait>() {}
-   |               ^^^^^^^^^^^ required by this bound in `require`
-help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
-   |
-LL | fn main() where Ty: Trait {
-   |           +++++++++++++++
-
-error: aborting due to 4 previous errors
-
-Some errors have detailed explanations: E0277, E0308.
-For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr b/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr
index 505b0a1..6ae60e7 100644
--- a/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr
+++ b/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr
@@ -5,10 +5,6 @@
    |         ^^^^^^
    |
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
 
 error[E0493]: destructor of `R` cannot be evaluated at compile-time
   --> $DIR/arbitrary-self-from-method-substs-ice.rs:10:43
diff --git a/tests/ui/specialization/const_trait_impl.stderr b/tests/ui/specialization/const_trait_impl.stderr
index 643f1de..40ac350 100644
--- a/tests/ui/specialization/const_trait_impl.stderr
+++ b/tests/ui/specialization/const_trait_impl.stderr
@@ -1,69 +1,42 @@
-error[E0049]: associated function `foo` has 1 const parameter but its trait declaration has 0 const parameters
-  --> $DIR/const_trait_impl.rs:6:1
-   |
-LL | #[const_trait]
-   | ^^^^^^^^^^^^^^ found 1 const parameter
-LL | pub unsafe trait Sup {
-LL |     fn foo() -> u32;
-   |           - expected 0 const parameters
-
-error[E0049]: associated function `foo` has 1 const parameter but its trait declaration has 0 const parameters
-  --> $DIR/const_trait_impl.rs:6:1
-   |
-LL | #[const_trait]
-   | ^^^^^^^^^^^^^^ found 1 const parameter
-LL | pub unsafe trait Sup {
-LL |     fn foo() -> u32;
-   |           - expected 0 const parameters
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const_trait_impl.rs:34:16
+  --> $DIR/const_trait_impl.rs:34:9
    |
 LL | impl<T: ~const Default> const A for T {
-   |                ^^^^^^^
+   |         ^^^^^^
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const_trait_impl.rs:40:16
+  --> $DIR/const_trait_impl.rs:40:9
    |
 LL | impl<T: ~const Default + ~const Sup> const A for T {
-   |                ^^^^^^^
+   |         ^^^^^^
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const_trait_impl.rs:46:16
+  --> $DIR/const_trait_impl.rs:46:9
    |
 LL | impl<T: ~const Default + ~const Sub> const A for T {
-   |                ^^^^^^^
+   |         ^^^^^^
 
-error[E0049]: associated function `a` has 1 const parameter but its trait declaration has 0 const parameters
-  --> $DIR/const_trait_impl.rs:29:1
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/const_trait_impl.rs:40:9
    |
-LL | #[const_trait]
-   | ^^^^^^^^^^^^^^ found 1 const parameter
-LL | pub trait A {
-LL |     fn a() -> u32;
-   |         - expected 0 const parameters
-
-error[E0049]: associated function `a` has 1 const parameter but its trait declaration has 0 const parameters
-  --> $DIR/const_trait_impl.rs:29:1
-   |
-LL | #[const_trait]
-   | ^^^^^^^^^^^^^^ found 1 const parameter
-LL | pub trait A {
-LL |     fn a() -> u32;
-   |         - expected 0 const parameters
+LL | impl<T: ~const Default + ~const Sup> const A for T {
+   |         ^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
-error[E0049]: associated function `a` has 1 const parameter but its trait declaration has 0 const parameters
-  --> $DIR/const_trait_impl.rs:29:1
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/const_trait_impl.rs:34:9
    |
-LL | #[const_trait]
-   | ^^^^^^^^^^^^^^ found 1 const parameter
-LL | pub trait A {
-LL |     fn a() -> u32;
-   |         - expected 0 const parameters
+LL | impl<T: ~const Default> const A for T {
+   |         ^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/const_trait_impl.rs:46:9
+   |
+LL | impl<T: ~const Default + ~const Sub> const A for T {
+   |         ^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
@@ -115,7 +88,6 @@
 LL + #![feature(effects)]
    |
 
-error: aborting due to 12 previous errors
+error: aborting due to 10 previous errors
 
-Some errors have detailed explanations: E0015, E0049.
-For more information about an error, try `rustc --explain E0015`.
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/stability-attribute/const-stability-attribute-implies-missing.rs b/tests/ui/stability-attribute/const-stability-attribute-implies-missing.rs
index 4089ec7..6d6d793 100644
--- a/tests/ui/stability-attribute/const-stability-attribute-implies-missing.rs
+++ b/tests/ui/stability-attribute/const-stability-attribute-implies-missing.rs
@@ -14,4 +14,3 @@
 }
 
 const VAR: u32 = foobar();
-//~^ ERROR: `foobar` is not yet stable as a const fn
diff --git a/tests/ui/stability-attribute/const-stability-attribute-implies-missing.stderr b/tests/ui/stability-attribute/const-stability-attribute-implies-missing.stderr
index 918d6eb..232de41 100644
--- a/tests/ui/stability-attribute/const-stability-attribute-implies-missing.stderr
+++ b/tests/ui/stability-attribute/const-stability-attribute-implies-missing.stderr
@@ -4,13 +4,5 @@
 LL | #[rustc_const_unstable(feature = "const_foobar", issue = "1", implied_by = "const_bar")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: `foobar` is not yet stable as a const fn
-  --> $DIR/const-stability-attribute-implies-missing.rs:16:18
-   |
-LL | const VAR: u32 = foobar();
-   |                  ^^^^^^^^
-   |
-   = help: add `#![feature(const_foobar)]` to the crate attributes to enable
-
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
 
diff --git a/tests/ui/stability-attribute/missing-const-stability.rs b/tests/ui/stability-attribute/missing-const-stability.rs
index 82da18c..f113965 100644
--- a/tests/ui/stability-attribute/missing-const-stability.rs
+++ b/tests/ui/stability-attribute/missing-const-stability.rs
@@ -1,6 +1,6 @@
 //@ compile-flags: -Znext-solver
 #![feature(staged_api)]
-#![feature(const_trait_impl, effects)] //~ WARN the feature `effects` is incomplete
+#![feature(const_trait_impl, effects, rustc_attrs, intrinsics)] //~ WARN the feature `effects` is incomplete
 #![stable(feature = "stable", since = "1.0.0")]
 
 #[stable(feature = "stable", since = "1.0.0")]
@@ -31,4 +31,15 @@
     fn fun() {}
 }
 
+#[stable(feature = "stable", since = "1.0.0")]
+#[rustc_intrinsic]
+pub const unsafe fn size_of_val<T>(x: *const T) -> usize { 42 }
+//~^ ERROR function has missing const stability attribute
+
+extern "rust-intrinsic" {
+    #[stable(feature = "stable", since = "1.0.0")]
+    #[rustc_const_stable_indirect]
+    pub fn min_align_of_val<T>(x: *const T) -> usize;
+}
+
 fn main() {}
diff --git a/tests/ui/stability-attribute/missing-const-stability.stderr b/tests/ui/stability-attribute/missing-const-stability.stderr
index adf60c3..e62a8b8 100644
--- a/tests/ui/stability-attribute/missing-const-stability.stderr
+++ b/tests/ui/stability-attribute/missing-const-stability.stderr
@@ -1,7 +1,7 @@
 warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/missing-const-stability.rs:3:30
    |
-LL | #![feature(const_trait_impl, effects)]
+LL | #![feature(const_trait_impl, effects, rustc_attrs, intrinsics)]
    |                              ^^^^^^^
    |
    = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
@@ -22,11 +22,17 @@
 LL | | }
    | |_^
 
+error: function has missing const stability attribute
+  --> $DIR/missing-const-stability.rs:36:1
+   |
+LL | pub const unsafe fn size_of_val<T>(x: *const T) -> usize { 42 }
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
 error: associated function has missing const stability attribute
   --> $DIR/missing-const-stability.rs:16:5
    |
 LL |     pub const fn foo() {}
    |     ^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 3 previous errors; 1 warning emitted
+error: aborting due to 4 previous errors; 1 warning emitted
 
diff --git a/tests/ui/static/raw-ref-deref-with-unsafe.rs b/tests/ui/static/raw-ref-deref-with-unsafe.rs
index 0974948..5beed69 100644
--- a/tests/ui/static/raw-ref-deref-with-unsafe.rs
+++ b/tests/ui/static/raw-ref-deref-with-unsafe.rs
@@ -1,13 +1,14 @@
 //@ check-pass
 use std::ptr;
 
-// This code should remain unsafe because of the two unsafe operations here,
-// even if in a hypothetical future we deem all &raw (const|mut) *ptr exprs safe.
-
 static mut BYTE: u8 = 0;
 static mut BYTE_PTR: *mut u8 = ptr::addr_of_mut!(BYTE);
+
+// This code should remain unsafe because reading from a static mut is *always* unsafe.
+
 // An unsafe static's ident is a place expression in its own right, so despite the above being safe
-// (it's fine to create raw refs to places!) the following derefs the ptr before creating its ref
+// (it's fine to create raw refs to places!) the following *reads* from the static mut place before
+// derefing it explicitly with the `*` below.
 static mut DEREF_BYTE_PTR: *mut u8 = unsafe { ptr::addr_of_mut!(*BYTE_PTR) };
 
 fn main() {
diff --git a/tests/ui/static/raw-ref-deref-without-unsafe.rs b/tests/ui/static/raw-ref-deref-without-unsafe.rs
index 289e55b..97d08c8 100644
--- a/tests/ui/static/raw-ref-deref-without-unsafe.rs
+++ b/tests/ui/static/raw-ref-deref-without-unsafe.rs
@@ -1,15 +1,14 @@
 use std::ptr;
 
-// This code should remain unsafe because of the two unsafe operations here,
-// even if in a hypothetical future we deem all &raw (const|mut) *ptr exprs safe.
-
 static mut BYTE: u8 = 0;
 static mut BYTE_PTR: *mut u8 = ptr::addr_of_mut!(BYTE);
+
+// This code should remain unsafe because reading from a static mut is *always* unsafe.
+
 // An unsafe static's ident is a place expression in its own right, so despite the above being safe
 // (it's fine to create raw refs to places!) the following derefs the ptr before creating its ref!
 static mut DEREF_BYTE_PTR: *mut u8 = ptr::addr_of_mut!(*BYTE_PTR);
 //~^ ERROR: use of mutable static
-//~| ERROR: dereference of raw pointer
 
 fn main() {
     let _ = unsafe { DEREF_BYTE_PTR };
diff --git a/tests/ui/static/raw-ref-deref-without-unsafe.stderr b/tests/ui/static/raw-ref-deref-without-unsafe.stderr
index f034499..b9c294e 100644
--- a/tests/ui/static/raw-ref-deref-without-unsafe.stderr
+++ b/tests/ui/static/raw-ref-deref-without-unsafe.stderr
@@ -1,11 +1,3 @@
-error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
-  --> $DIR/raw-ref-deref-without-unsafe.rs:10:56
-   |
-LL | static mut DEREF_BYTE_PTR: *mut u8 = ptr::addr_of_mut!(*BYTE_PTR);
-   |                                                        ^^^^^^^^^ dereference of raw pointer
-   |
-   = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
-
 error[E0133]: use of mutable static is unsafe and requires unsafe function or block
   --> $DIR/raw-ref-deref-without-unsafe.rs:10:57
    |
@@ -14,6 +6,6 @@
    |
    = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
 
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
 
 For more information about this error, try `rustc --explain E0133`.
diff --git a/tests/ui/statics/check-values-constraints.stderr b/tests/ui/statics/check-values-constraints.stderr
index 24763c1..b4ee345 100644
--- a/tests/ui/statics/check-values-constraints.stderr
+++ b/tests/ui/statics/check-values-constraints.stderr
@@ -37,10 +37,6 @@
    |
    = note: calls in statics are limited to constant functions, tuple structs and tuple variants
    = note: consider wrapping this expression in `std::sync::LazyLock::new(|| ...)`
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
 
 error[E0010]: allocations are not allowed in statics
   --> $DIR/check-values-constraints.rs:96:5
diff --git a/tests/ui/stats/hir-stats.stderr b/tests/ui/stats/hir-stats.stderr
index 3a2d4df..bd0c8cb 100644
--- a/tests/ui/stats/hir-stats.stderr
+++ b/tests/ui/stats/hir-stats.stderr
@@ -141,10 +141,10 @@
 hir-stats Attribute                128 ( 1.4%)             4            32
 hir-stats GenericArgs              144 ( 1.6%)             3            48
 hir-stats Variant                  144 ( 1.6%)             2            72
-hir-stats GenericBound             192 ( 2.1%)             4            48
-hir-stats - Trait                    192 ( 2.1%)             4
 hir-stats WherePredicate           192 ( 2.1%)             3            64
 hir-stats - BoundPredicate           192 ( 2.1%)             3
+hir-stats GenericBound             256 ( 2.8%)             4            64
+hir-stats - Trait                    256 ( 2.8%)             4
 hir-stats Block                    288 ( 3.2%)             6            48
 hir-stats GenericParam             360 ( 4.0%)             5            72
 hir-stats Pat                      360 ( 4.0%)             5            72
@@ -155,15 +155,15 @@
 hir-stats Ty                       720 ( 8.0%)            15            48
 hir-stats - Ref                       48 ( 0.5%)             1
 hir-stats - Ptr                       48 ( 0.5%)             1
-hir-stats - Path                     624 ( 7.0%)            13
-hir-stats Expr                     768 ( 8.6%)            12            64
+hir-stats - Path                     624 ( 6.9%)            13
+hir-stats Expr                     768 ( 8.5%)            12            64
 hir-stats - Path                      64 ( 0.7%)             1
 hir-stats - Match                     64 ( 0.7%)             1
 hir-stats - Struct                    64 ( 0.7%)             1
 hir-stats - InlineAsm                 64 ( 0.7%)             1
 hir-stats - Lit                      128 ( 1.4%)             2
 hir-stats - Block                    384 ( 4.3%)             6
-hir-stats Item                     968 (10.8%)            11            88
+hir-stats Item                     968 (10.7%)            11            88
 hir-stats - Enum                      88 ( 1.0%)             1
 hir-stats - Trait                     88 ( 1.0%)             1
 hir-stats - Impl                      88 ( 1.0%)             1
@@ -171,8 +171,8 @@
 hir-stats - ForeignMod                88 ( 1.0%)             1
 hir-stats - Fn                       176 ( 2.0%)             2
 hir-stats - Use                      352 ( 3.9%)             4
-hir-stats Path                   1_240 (13.8%)            31            40
-hir-stats PathSegment            1_920 (21.4%)            40            48
+hir-stats Path                   1_240 (13.7%)            31            40
+hir-stats PathSegment            1_920 (21.3%)            40            48
 hir-stats ----------------------------------------------------------------
-hir-stats Total                  8_960
+hir-stats Total                  9_024
 hir-stats
diff --git a/tests/ui/target-feature/feature-hierarchy.rs b/tests/ui/target-feature/feature-hierarchy.rs
index 4cf9112..7f14d70 100644
--- a/tests/ui/target-feature/feature-hierarchy.rs
+++ b/tests/ui/target-feature/feature-hierarchy.rs
@@ -19,6 +19,7 @@
 impl Copy for bool {}
 
 extern "rust-intrinsic" {
+    #[stable(feature = "test", since = "1.0.0")]
     #[rustc_const_stable(feature = "test", since = "1.0.0")]
     fn unreachable() -> !;
 }
diff --git a/tests/ui/target-feature/no-llvm-leaks.rs b/tests/ui/target-feature/no-llvm-leaks.rs
index 9f5dec4..f0c887b 100644
--- a/tests/ui/target-feature/no-llvm-leaks.rs
+++ b/tests/ui/target-feature/no-llvm-leaks.rs
@@ -17,6 +17,7 @@
 impl Copy for bool {}
 
 extern "rust-intrinsic" {
+    #[stable(feature = "test", since = "1.0.0")]
     #[rustc_const_stable(feature = "test", since = "1.0.0")]
     fn unreachable() -> !;
 }
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-0.rs b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-0.rs
similarity index 86%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-0.rs
rename to tests/ui/traits/const-traits/assoc-type-const-bound-usage-0.rs
index 4399ae2..bbf8891 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-0.rs
+++ b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-0.rs
@@ -1,4 +1,5 @@
-//@ known-bug: unknown
+//@ compile-flags: -Znext-solver
+//@ check-pass
 
 #![allow(incomplete_features)]
 #![feature(const_trait_impl, effects)]
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-1.rs b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-1.rs
similarity index 92%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-1.rs
rename to tests/ui/traits/const-traits/assoc-type-const-bound-usage-1.rs
index 8a1bf75..04ad945 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-1.rs
+++ b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-1.rs
@@ -1,5 +1,5 @@
+//@ compile-flags: -Znext-solver
 //@ known-bug: unknown
-// FIXME(effects)
 
 #![feature(const_trait_impl, effects, generic_const_exprs)]
 #![allow(incomplete_features)]
diff --git a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-1.stderr b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-1.stderr
new file mode 100644
index 0000000..b8768bd
--- /dev/null
+++ b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-1.stderr
@@ -0,0 +1,35 @@
+error: `-Znext-solver=globally` and `generic_const_exprs` are incompatible, using them at the same time is not allowed
+  --> $DIR/assoc-type-const-bound-usage-1.rs:4:39
+   |
+LL | #![feature(const_trait_impl, effects, generic_const_exprs)]
+   |                                       ^^^^^^^^^^^^^^^^^^^
+   |
+   = help: remove one of these features
+
+error[E0284]: type annotations needed: cannot normalize `unqualified<T>::{constant#0}`
+  --> $DIR/assoc-type-const-bound-usage-1.rs:15:37
+   |
+LL | fn unqualified<T: const Trait>() -> Type<{ T::Assoc::func() }> {
+   |                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot normalize `unqualified<T>::{constant#0}`
+
+error[E0284]: type annotations needed: cannot normalize `qualified<T>::{constant#0}`
+  --> $DIR/assoc-type-const-bound-usage-1.rs:19:35
+   |
+LL | fn qualified<T: const Trait>() -> Type<{ <T as Trait>::Assoc::func() }> {
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot normalize `qualified<T>::{constant#0}`
+
+error[E0284]: type annotations needed: cannot normalize `unqualified<T>::{constant#0}`
+  --> $DIR/assoc-type-const-bound-usage-1.rs:16:5
+   |
+LL |     Type
+   |     ^^^^ cannot normalize `unqualified<T>::{constant#0}`
+
+error[E0284]: type annotations needed: cannot normalize `qualified<T>::{constant#0}`
+  --> $DIR/assoc-type-const-bound-usage-1.rs:20:5
+   |
+LL |     Type
+   |     ^^^^ cannot normalize `qualified<T>::{constant#0}`
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0284`.
diff --git a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail-2.rs b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail-2.rs
new file mode 100644
index 0000000..5e87308
--- /dev/null
+++ b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail-2.rs
@@ -0,0 +1,35 @@
+//@ compile-flags: -Znext-solver
+
+// Check that `~const` item bounds only hold if the where clauses on the
+// associated type are also const.
+// i.e. check that we validate the const conditions for the associated type
+// when considering one of implied const bounds.
+
+#![allow(incomplete_features)]
+#![feature(const_trait_impl, effects)]
+
+#[const_trait]
+trait Trait {
+    type Assoc<U>: ~const Trait
+    where
+        U: ~const Other;
+
+    fn func();
+}
+
+#[const_trait]
+trait Other {}
+
+const fn fails<T: ~const Trait, U: Other>() {
+    T::Assoc::<U>::func();
+    //~^ ERROR the trait bound `<T as Trait>::Assoc<U>: ~const Trait` is not satisfied
+    <T as Trait>::Assoc::<U>::func();
+    //~^ ERROR the trait bound `<T as Trait>::Assoc<U>: ~const Trait` is not satisfied
+}
+
+const fn works<T: ~const Trait, U: ~const Other>() {
+    T::Assoc::<U>::func();
+    <T as Trait>::Assoc::<U>::func();
+}
+
+fn main() {}
diff --git a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail-2.stderr b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail-2.stderr
new file mode 100644
index 0000000..1f6532c
--- /dev/null
+++ b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail-2.stderr
@@ -0,0 +1,15 @@
+error[E0277]: the trait bound `<T as Trait>::Assoc<U>: ~const Trait` is not satisfied
+  --> $DIR/assoc-type-const-bound-usage-fail-2.rs:24:5
+   |
+LL |     T::Assoc::<U>::func();
+   |     ^^^^^^^^^^^^^^^^^^^^^
+
+error[E0277]: the trait bound `<T as Trait>::Assoc<U>: ~const Trait` is not satisfied
+  --> $DIR/assoc-type-const-bound-usage-fail-2.rs:26:5
+   |
+LL |     <T as Trait>::Assoc::<U>::func();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.rs b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.rs
new file mode 100644
index 0000000..73b3d14
--- /dev/null
+++ b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.rs
@@ -0,0 +1,28 @@
+//@ compile-flags: -Znext-solver
+
+// Check that `~const` item bounds only hold if the parent trait is `~const`.
+// i.e. check that we validate the const conditions for the associated type
+// when considering one of implied const bounds.
+
+#![allow(incomplete_features)]
+#![feature(const_trait_impl, effects)]
+
+#[const_trait]
+trait Trait {
+    type Assoc: ~const Trait;
+    fn func();
+}
+
+const fn unqualified<T: Trait>() {
+    T::Assoc::func();
+    //~^ ERROR the trait bound `T: ~const Trait` is not satisfied
+    <T as Trait>::Assoc::func();
+    //~^ ERROR the trait bound `T: ~const Trait` is not satisfied
+}
+
+const fn works<T: ~const Trait>() {
+    T::Assoc::func();
+    <T as Trait>::Assoc::func();
+}
+
+fn main() {}
diff --git a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.stderr b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.stderr
new file mode 100644
index 0000000..fb08e74
--- /dev/null
+++ b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.stderr
@@ -0,0 +1,15 @@
+error[E0277]: the trait bound `T: ~const Trait` is not satisfied
+  --> $DIR/assoc-type-const-bound-usage-fail.rs:17:5
+   |
+LL |     T::Assoc::func();
+   |     ^^^^^^^^^^^^^^^^
+
+error[E0277]: the trait bound `T: ~const Trait` is not satisfied
+  --> $DIR/assoc-type-const-bound-usage-fail.rs:19:5
+   |
+LL |     <T as Trait>::Assoc::func();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type.rs b/tests/ui/traits/const-traits/assoc-type.rs
similarity index 79%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type.rs
rename to tests/ui/traits/const-traits/assoc-type.rs
index ea3cbab..a9394d9 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type.rs
+++ b/tests/ui/traits/const-traits/assoc-type.rs
@@ -1,4 +1,5 @@
-// FIXME(effects): Replace `Add` with `std::ops::Add` once the latter a `#[const_trait]` again.
+//@ compile-flags: -Znext-solver
+
 #![feature(const_trait_impl, effects)] //~ WARN the feature `effects` is incomplete
 
 #[const_trait]
@@ -33,7 +34,7 @@
 
 impl const Foo for NonConstAdd {
     type Bar = NonConstAdd;
-    // FIXME(effects) ERROR the trait bound `NonConstAdd: ~const Add` is not satisfied
+    //~^ ERROR the trait bound `NonConstAdd: ~const Add` is not satisfied
 }
 
 #[const_trait]
diff --git a/tests/ui/traits/const-traits/assoc-type.stderr b/tests/ui/traits/const-traits/assoc-type.stderr
new file mode 100644
index 0000000..672eaf2
--- /dev/null
+++ b/tests/ui/traits/const-traits/assoc-type.stderr
@@ -0,0 +1,24 @@
+warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/assoc-type.rs:3:30
+   |
+LL | #![feature(const_trait_impl, effects)]
+   |                              ^^^^^^^
+   |
+   = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+error[E0277]: the trait bound `NonConstAdd: ~const Add` is not satisfied
+  --> $DIR/assoc-type.rs:36:16
+   |
+LL |     type Bar = NonConstAdd;
+   |                ^^^^^^^^^^^
+   |
+note: required by a bound in `Foo::Bar`
+  --> $DIR/assoc-type.rs:32:15
+   |
+LL |     type Bar: ~const Add;
+   |               ^^^^^^ required by this bound in `Foo::Bar`
+
+error: aborting due to 1 previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/attr-misuse.rs b/tests/ui/traits/const-traits/attr-misuse.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/attr-misuse.rs
rename to tests/ui/traits/const-traits/attr-misuse.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/attr-misuse.stderr b/tests/ui/traits/const-traits/attr-misuse.stderr
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/attr-misuse.stderr
rename to tests/ui/traits/const-traits/attr-misuse.stderr
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/auxiliary/cross-crate.rs b/tests/ui/traits/const-traits/auxiliary/cross-crate.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/auxiliary/cross-crate.rs
rename to tests/ui/traits/const-traits/auxiliary/cross-crate.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/auxiliary/staged-api.rs b/tests/ui/traits/const-traits/auxiliary/staged-api.rs
similarity index 70%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/auxiliary/staged-api.rs
rename to tests/ui/traits/const-traits/auxiliary/staged-api.rs
index 986165e..bb59132 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/auxiliary/staged-api.rs
+++ b/tests/ui/traits/const-traits/auxiliary/staged-api.rs
@@ -19,3 +19,12 @@
 impl const MyTrait for Unstable {
     fn func() {}
 }
+
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Unstable2;
+
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_unstable(feature = "unstable2", issue = "none")]
+impl const MyTrait for Unstable2 {
+    fn func() {}
+}
diff --git a/tests/ui/traits/const-traits/call-const-closure.rs b/tests/ui/traits/const-traits/call-const-closure.rs
new file mode 100644
index 0000000..cbf3e6c
--- /dev/null
+++ b/tests/ui/traits/const-traits/call-const-closure.rs
@@ -0,0 +1,22 @@
+//@ compile-flags: -Znext-solver
+//@ edition:2021
+
+#![feature(const_trait_impl, effects, const_closures)]
+#![allow(incomplete_features)]
+
+#[const_trait]
+trait Bar {
+    fn foo(&self);
+}
+
+impl Bar for () {
+    fn foo(&self) {}
+}
+
+const FOO: () = {
+    (const || ().foo())();
+    //~^ ERROR the trait bound `(): ~const Bar` is not satisfied
+    // FIXME(effects): The constness environment for const closures is wrong.
+};
+
+fn main() {}
diff --git a/tests/ui/traits/const-traits/call-const-closure.stderr b/tests/ui/traits/const-traits/call-const-closure.stderr
new file mode 100644
index 0000000..3fed67f
--- /dev/null
+++ b/tests/ui/traits/const-traits/call-const-closure.stderr
@@ -0,0 +1,9 @@
+error[E0277]: the trait bound `(): ~const Bar` is not satisfied
+  --> $DIR/call-const-closure.rs:17:15
+   |
+LL |     (const || ().foo())();
+   |               ^^^^^^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/const-traits/call-const-in-tilde-const.rs b/tests/ui/traits/const-traits/call-const-in-tilde-const.rs
new file mode 100644
index 0000000..970ee93
--- /dev/null
+++ b/tests/ui/traits/const-traits/call-const-in-tilde-const.rs
@@ -0,0 +1,14 @@
+//@ compile-flags: -Znext-solver
+#![feature(const_trait_impl, effects)]
+//~^ WARN the feature `effects` is incomplete
+
+#[const_trait] trait Foo {
+    fn foo();
+}
+
+const fn foo<T: ~const Foo>() {
+    const { T::foo() }
+    //~^ ERROR the trait bound `T: const Foo` is not satisfied
+}
+
+fn main() {}
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type.stderr b/tests/ui/traits/const-traits/call-const-in-tilde-const.stderr
similarity index 60%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type.stderr
rename to tests/ui/traits/const-traits/call-const-in-tilde-const.stderr
index c20b53c..49c310f 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type.stderr
+++ b/tests/ui/traits/const-traits/call-const-in-tilde-const.stderr
@@ -1,5 +1,5 @@
 warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/assoc-type.rs:2:30
+  --> $DIR/call-const-in-tilde-const.rs:2:30
    |
 LL | #![feature(const_trait_impl, effects)]
    |                              ^^^^^^^
@@ -7,10 +7,12 @@
    = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
    = note: `#[warn(incomplete_features)]` on by default
 
-error: using `#![feature(effects)]` without enabling next trait solver globally
+error[E0277]: the trait bound `T: const Foo` is not satisfied
+  --> $DIR/call-const-in-tilde-const.rs:10:13
    |
-   = note: the next trait solver must be enabled globally for the effects feature to work correctly
-   = help: use `-Znext-solver` to enable
+LL |     const { T::foo() }
+   |             ^^^^^^^^
 
 error: aborting due to 1 previous error; 1 warning emitted
 
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-const-trait-method-fail.rs b/tests/ui/traits/const-traits/call-const-trait-method-fail.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/call-const-trait-method-fail.rs
rename to tests/ui/traits/const-traits/call-const-trait-method-fail.rs
diff --git a/tests/ui/traits/const-traits/call-const-trait-method-fail.stderr b/tests/ui/traits/const-traits/call-const-trait-method-fail.stderr
new file mode 100644
index 0000000..40a06af
--- /dev/null
+++ b/tests/ui/traits/const-traits/call-const-trait-method-fail.stderr
@@ -0,0 +1,9 @@
+error[E0277]: the trait bound `u32: ~const Plus` is not satisfied
+  --> $DIR/call-const-trait-method-fail.rs:27:5
+   |
+LL |     a.plus(b)
+   |     ^^^^^^^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-const-trait-method-pass.rs b/tests/ui/traits/const-traits/call-const-trait-method-pass.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/call-const-trait-method-pass.rs
rename to tests/ui/traits/const-traits/call-const-trait-method-pass.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-const-trait-method-pass.stderr b/tests/ui/traits/const-traits/call-const-trait-method-pass.stderr
similarity index 75%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/call-const-trait-method-pass.stderr
rename to tests/ui/traits/const-traits/call-const-trait-method-pass.stderr
index bf455a7..32f5313 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-const-trait-method-pass.stderr
+++ b/tests/ui/traits/const-traits/call-const-trait-method-pass.stderr
@@ -16,15 +16,6 @@
    = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const`
    = note: adding a non-const method body in the future would be a breaking change
 
-error[E0049]: method `plus` has 1 const parameter but its trait declaration has 0 const parameters
-  --> $DIR/call-const-trait-method-pass.rs:24:1
-   |
-LL | #[const_trait]
-   | ^^^^^^^^^^^^^^ found 1 const parameter
-LL | pub trait Plus {
-LL |     fn plus(self, rhs: Self) -> Self;
-   |            - expected 0 const parameters
-
 error[E0015]: cannot call non-const operator in constants
   --> $DIR/call-const-trait-method-pass.rs:39:22
    |
@@ -32,10 +23,6 @@
    |                      ^^^^^^^^^^^^^^^^^^^^^
    |
    = note: calls in constants are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(effects)]` to the crate attributes to enable
-   |
-LL + #![feature(effects)]
-   |
 
 error[E0015]: cannot call non-const fn `<i32 as Plus>::plus` in constant functions
   --> $DIR/call-const-trait-method-pass.rs:11:20
@@ -56,10 +43,6 @@
    |               ^^^^^^^^^
    |
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(effects)]` to the crate attributes to enable
-   |
-LL + #![feature(effects)]
-   |
 
 error[E0015]: cannot call non-const fn `<i32 as Plus>::plus` in constant functions
   --> $DIR/call-const-trait-method-pass.rs:36:7
@@ -73,7 +56,6 @@
 LL + #![feature(effects)]
    |
 
-error: aborting due to 7 previous errors
+error: aborting due to 6 previous errors
 
-Some errors have detailed explanations: E0015, E0049.
-For more information about an error, try `rustc --explain E0015`.
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-in-impl.rs b/tests/ui/traits/const-traits/call-generic-in-impl.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-in-impl.rs
rename to tests/ui/traits/const-traits/call-generic-in-impl.rs
diff --git a/tests/ui/traits/const-traits/call-generic-in-impl.stderr b/tests/ui/traits/const-traits/call-generic-in-impl.stderr
new file mode 100644
index 0000000..52ee044
--- /dev/null
+++ b/tests/ui/traits/const-traits/call-generic-in-impl.stderr
@@ -0,0 +1,25 @@
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/call-generic-in-impl.rs:10:9
+   |
+LL | impl<T: ~const PartialEq> const MyPartialEq for T {
+   |         ^^^^^^
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/call-generic-in-impl.rs:10:9
+   |
+LL | impl<T: ~const PartialEq> const MyPartialEq for T {
+   |         ^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0015]: cannot call non-const fn `<T as PartialEq>::eq` in constant functions
+  --> $DIR/call-generic-in-impl.rs:12:9
+   |
+LL |         PartialEq::eq(self, other)
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-chain.rs b/tests/ui/traits/const-traits/call-generic-method-chain.rs
similarity index 94%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-chain.rs
rename to tests/ui/traits/const-traits/call-generic-method-chain.rs
index 9df694a..e5baeda 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-chain.rs
+++ b/tests/ui/traits/const-traits/call-generic-method-chain.rs
@@ -1,6 +1,7 @@
 //! Basic test for calling methods on generic type parameters in `const fn`.
 
 //@ known-bug: #110395
+//@ compile-flags: -Znext-solver
 // FIXME(effects) check-pass
 
 #![feature(const_trait_impl, effects)]
diff --git a/tests/ui/traits/const-traits/call-generic-method-chain.stderr b/tests/ui/traits/const-traits/call-generic-method-chain.stderr
new file mode 100644
index 0000000..6dbf3ad
--- /dev/null
+++ b/tests/ui/traits/const-traits/call-generic-method-chain.stderr
@@ -0,0 +1,69 @@
+warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/call-generic-method-chain.rs:7:30
+   |
+LL | #![feature(const_trait_impl, effects)]
+   |                              ^^^^^^^
+   |
+   = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+error: const `impl` for trait `PartialEq` which is not marked with `#[const_trait]`
+  --> $DIR/call-generic-method-chain.rs:11:12
+   |
+LL | impl const PartialEq for S {
+   |            ^^^^^^^^^
+   |
+   = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const`
+   = note: adding a non-const method body in the future would be a breaking change
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/call-generic-method-chain.rs:20:25
+   |
+LL | const fn equals_self<T: ~const PartialEq>(t: &T) -> bool {
+   |                         ^^^^^^
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/call-generic-method-chain.rs:20:25
+   |
+LL | const fn equals_self<T: ~const PartialEq>(t: &T) -> bool {
+   |                         ^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/call-generic-method-chain.rs:24:33
+   |
+LL | const fn equals_self_wrapper<T: ~const PartialEq>(t: &T) -> bool {
+   |                                 ^^^^^^
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/call-generic-method-chain.rs:24:33
+   |
+LL | const fn equals_self_wrapper<T: ~const PartialEq>(t: &T) -> bool {
+   |                                 ^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0015]: cannot call non-const operator in constant functions
+  --> $DIR/call-generic-method-chain.rs:21:5
+   |
+LL |     *t == *t
+   |     ^^^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+help: consider further restricting this bound
+   |
+LL | const fn equals_self<T: ~const PartialEq + ~const std::cmp::PartialEq>(t: &T) -> bool {
+   |                                          ++++++++++++++++++++++++++++
+
+error[E0015]: cannot call non-const fn `<S as PartialEq>::eq` in constant functions
+  --> $DIR/call-generic-method-chain.rs:16:15
+   |
+LL |         !self.eq(other)
+   |               ^^^^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error: aborting due to 7 previous errors; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-dup-bound.rs b/tests/ui/traits/const-traits/call-generic-method-dup-bound.rs
similarity index 94%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-dup-bound.rs
rename to tests/ui/traits/const-traits/call-generic-method-dup-bound.rs
index f46a349..83a4bb2 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-dup-bound.rs
+++ b/tests/ui/traits/const-traits/call-generic-method-dup-bound.rs
@@ -1,3 +1,4 @@
+//@ compile-flags: -Znext-solver
 //@ known-bug: #110395
 // FIXME(effects) check-pass
 
diff --git a/tests/ui/traits/const-traits/call-generic-method-dup-bound.stderr b/tests/ui/traits/const-traits/call-generic-method-dup-bound.stderr
new file mode 100644
index 0000000..08877da
--- /dev/null
+++ b/tests/ui/traits/const-traits/call-generic-method-dup-bound.stderr
@@ -0,0 +1,81 @@
+warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/call-generic-method-dup-bound.rs:5:30
+   |
+LL | #![feature(const_trait_impl, effects)]
+   |                              ^^^^^^^
+   |
+   = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+error: const `impl` for trait `PartialEq` which is not marked with `#[const_trait]`
+  --> $DIR/call-generic-method-dup-bound.rs:9:12
+   |
+LL | impl const PartialEq for S {
+   |            ^^^^^^^^^
+   |
+   = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const`
+   = note: adding a non-const method body in the future would be a breaking change
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/call-generic-method-dup-bound.rs:20:37
+   |
+LL | const fn equals_self<T: PartialEq + ~const PartialEq>(t: &T) -> bool {
+   |                                     ^^^^^^
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/call-generic-method-dup-bound.rs:20:37
+   |
+LL | const fn equals_self<T: PartialEq + ~const PartialEq>(t: &T) -> bool {
+   |                                     ^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/call-generic-method-dup-bound.rs:27:30
+   |
+LL | const fn equals_self2<T: A + ~const PartialEq>(t: &T) -> bool {
+   |                              ^^^^^^
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/call-generic-method-dup-bound.rs:27:30
+   |
+LL | const fn equals_self2<T: A + ~const PartialEq>(t: &T) -> bool {
+   |                              ^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0015]: cannot call non-const operator in constant functions
+  --> $DIR/call-generic-method-dup-bound.rs:21:5
+   |
+LL |     *t == *t
+   |     ^^^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+help: consider further restricting this bound
+   |
+LL | const fn equals_self<T: PartialEq + ~const PartialEq + ~const std::cmp::PartialEq>(t: &T) -> bool {
+   |                                                      ++++++++++++++++++++++++++++
+
+error[E0015]: cannot call non-const fn `<S as PartialEq>::eq` in constant functions
+  --> $DIR/call-generic-method-dup-bound.rs:14:15
+   |
+LL |         !self.eq(other)
+   |               ^^^^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error[E0015]: cannot call non-const operator in constant functions
+  --> $DIR/call-generic-method-dup-bound.rs:28:5
+   |
+LL |     *t == *t
+   |     ^^^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+help: consider further restricting this bound
+   |
+LL | const fn equals_self2<T: A + ~const PartialEq + ~const std::cmp::PartialEq>(t: &T) -> bool {
+   |                                               ++++++++++++++++++++++++++++
+
+error: aborting due to 8 previous errors; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-fail.rs b/tests/ui/traits/const-traits/call-generic-method-fail.rs
similarity index 65%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-fail.rs
rename to tests/ui/traits/const-traits/call-generic-method-fail.rs
index 86e0eae..6bfbbef 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-fail.rs
+++ b/tests/ui/traits/const-traits/call-generic-method-fail.rs
@@ -1,12 +1,10 @@
-//@ check-pass
 //@ compile-flags: -Znext-solver
 #![allow(incomplete_features)]
 #![feature(const_trait_impl, effects)]
 
 pub const fn equals_self<T: PartialEq>(t: &T) -> bool {
     *t == *t
-    // FIXME(effects) ~^ ERROR mismatched types
-    // FIXME(effects): diagnostic
+    //~^ ERROR cannot call non-const operator in constant functions
 }
 
 fn main() {}
diff --git a/tests/ui/traits/const-traits/call-generic-method-fail.stderr b/tests/ui/traits/const-traits/call-generic-method-fail.stderr
new file mode 100644
index 0000000..5cd4216
--- /dev/null
+++ b/tests/ui/traits/const-traits/call-generic-method-fail.stderr
@@ -0,0 +1,15 @@
+error[E0015]: cannot call non-const operator in constant functions
+  --> $DIR/call-generic-method-fail.rs:6:5
+   |
+LL |     *t == *t
+   |     ^^^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+help: consider further restricting this bound
+   |
+LL | pub const fn equals_self<T: PartialEq + ~const std::cmp::PartialEq>(t: &T) -> bool {
+   |                                       ++++++++++++++++++++++++++++
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-nonconst-bound.rs b/tests/ui/traits/const-traits/call-generic-method-nonconst-bound.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-nonconst-bound.rs
rename to tests/ui/traits/const-traits/call-generic-method-nonconst-bound.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-nonconst.rs b/tests/ui/traits/const-traits/call-generic-method-nonconst.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-nonconst.rs
rename to tests/ui/traits/const-traits/call-generic-method-nonconst.rs
diff --git a/tests/ui/traits/const-traits/call-generic-method-nonconst.stderr b/tests/ui/traits/const-traits/call-generic-method-nonconst.stderr
new file mode 100644
index 0000000..06b9937
--- /dev/null
+++ b/tests/ui/traits/const-traits/call-generic-method-nonconst.stderr
@@ -0,0 +1,9 @@
+error[E0277]: the trait bound `S: const Foo` is not satisfied
+  --> $DIR/call-generic-method-nonconst.rs:25:22
+   |
+LL | pub const EQ: bool = equals_self(&S);
+   |                      ^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-pass.rs b/tests/ui/traits/const-traits/call-generic-method-pass.rs
similarity index 92%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-pass.rs
rename to tests/ui/traits/const-traits/call-generic-method-pass.rs
index 413685d..cbeeb25 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-pass.rs
+++ b/tests/ui/traits/const-traits/call-generic-method-pass.rs
@@ -1,5 +1,6 @@
 //! Basic test for calling methods on generic type parameters in `const fn`.
 
+//@ compile-flags: -Znext-solver
 //@ known-bug: #110395
 // FIXME(effects) check-pass
 
diff --git a/tests/ui/traits/const-traits/call-generic-method-pass.stderr b/tests/ui/traits/const-traits/call-generic-method-pass.stderr
new file mode 100644
index 0000000..ac08c05
--- /dev/null
+++ b/tests/ui/traits/const-traits/call-generic-method-pass.stderr
@@ -0,0 +1,55 @@
+warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/call-generic-method-pass.rs:7:30
+   |
+LL | #![feature(const_trait_impl, effects)]
+   |                              ^^^^^^^
+   |
+   = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+error: const `impl` for trait `PartialEq` which is not marked with `#[const_trait]`
+  --> $DIR/call-generic-method-pass.rs:11:12
+   |
+LL | impl const PartialEq for S {
+   |            ^^^^^^^^^
+   |
+   = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const`
+   = note: adding a non-const method body in the future would be a breaking change
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/call-generic-method-pass.rs:20:25
+   |
+LL | const fn equals_self<T: ~const PartialEq>(t: &T) -> bool {
+   |                         ^^^^^^
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/call-generic-method-pass.rs:20:25
+   |
+LL | const fn equals_self<T: ~const PartialEq>(t: &T) -> bool {
+   |                         ^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0015]: cannot call non-const operator in constant functions
+  --> $DIR/call-generic-method-pass.rs:21:5
+   |
+LL |     *t == *t
+   |     ^^^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+help: consider further restricting this bound
+   |
+LL | const fn equals_self<T: ~const PartialEq + ~const std::cmp::PartialEq>(t: &T) -> bool {
+   |                                          ++++++++++++++++++++++++++++
+
+error[E0015]: cannot call non-const fn `<S as PartialEq>::eq` in constant functions
+  --> $DIR/call-generic-method-pass.rs:16:15
+   |
+LL |         !self.eq(other)
+   |               ^^^^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error: aborting due to 5 previous errors; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call.rs b/tests/ui/traits/const-traits/call.rs
similarity index 68%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/call.rs
rename to tests/ui/traits/const-traits/call.rs
index af2f7ca..f96fb61 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/call.rs
+++ b/tests/ui/traits/const-traits/call.rs
@@ -1,10 +1,11 @@
-//@ check-pass
+// FIXME(effects) check-pass
 //@ compile-flags: -Znext-solver
 #![feature(const_closures, const_trait_impl, effects)]
 #![allow(incomplete_features)]
 
 pub const _: () = {
     assert!((const || true)());
+    //~^ ERROR cannot call non-const closure in constants
 };
 
 fn main() {}
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-102985.stderr b/tests/ui/traits/const-traits/call.stderr
similarity index 65%
copy from tests/ui/rfcs/rfc-2632-const-trait-impl/issue-102985.stderr
copy to tests/ui/traits/const-traits/call.stderr
index 8401d1b..e9bf640 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-102985.stderr
+++ b/tests/ui/traits/const-traits/call.stderr
@@ -1,15 +1,11 @@
 error[E0015]: cannot call non-const closure in constants
-  --> $DIR/issue-102985.rs:6:14
+  --> $DIR/call.rs:7:13
    |
-LL |         n => n(),
-   |              ^^^
+LL |     assert!((const || true)());
+   |             ^^^^^^^^^^^^^^^^^
    |
    = note: closures need an RFC before allowed to be called in constants
    = note: calls in constants are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(effects)]` to the crate attributes to enable
-   |
-LL + #![feature(effects)]
-   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-and-non-const-impl.rs b/tests/ui/traits/const-traits/const-and-non-const-impl.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const-and-non-const-impl.rs
rename to tests/ui/traits/const-traits/const-and-non-const-impl.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-and-non-const-impl.stderr b/tests/ui/traits/const-traits/const-and-non-const-impl.stderr
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const-and-non-const-impl.stderr
rename to tests/ui/traits/const-traits/const-and-non-const-impl.stderr
diff --git a/tests/ui/traits/const-traits/const-bound-in-host.rs b/tests/ui/traits/const-traits/const-bound-in-host.rs
new file mode 100644
index 0000000..6fbc210
--- /dev/null
+++ b/tests/ui/traits/const-traits/const-bound-in-host.rs
@@ -0,0 +1,15 @@
+//@ compile-flags: -Znext-solver
+//@ check-pass
+
+#![feature(const_trait_impl, effects)]
+//~^ WARN the feature `effects` is incomplete
+
+#[const_trait] trait Foo {
+    fn foo();
+}
+
+fn foo<T: const Foo>() {
+    const { T::foo() }
+}
+
+fn main() {}
diff --git a/tests/ui/traits/const-traits/const-bound-in-host.stderr b/tests/ui/traits/const-traits/const-bound-in-host.stderr
new file mode 100644
index 0000000..b815f74
--- /dev/null
+++ b/tests/ui/traits/const-traits/const-bound-in-host.stderr
@@ -0,0 +1,11 @@
+warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/const-bound-in-host.rs:4:30
+   |
+LL | #![feature(const_trait_impl, effects)]
+   |                              ^^^^^^^
+   |
+   = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-bound-on-not-const-associated-fn.rs b/tests/ui/traits/const-traits/const-bound-on-not-const-associated-fn.rs
similarity index 93%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const-bound-on-not-const-associated-fn.rs
rename to tests/ui/traits/const-traits/const-bound-on-not-const-associated-fn.rs
index 099cf0b..7c3e2af 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-bound-on-not-const-associated-fn.rs
+++ b/tests/ui/traits/const-traits/const-bound-on-not-const-associated-fn.rs
@@ -1,3 +1,5 @@
+//@ compile-flags: -Znext-solver
+
 #![allow(incomplete_features)]
 #![feature(const_trait_impl, effects)]
 
diff --git a/tests/ui/traits/const-traits/const-bound-on-not-const-associated-fn.stderr b/tests/ui/traits/const-traits/const-bound-on-not-const-associated-fn.stderr
new file mode 100644
index 0000000..ae1260f
--- /dev/null
+++ b/tests/ui/traits/const-traits/const-bound-on-not-const-associated-fn.stderr
@@ -0,0 +1,26 @@
+error: `~const` is not allowed here
+  --> $DIR/const-bound-on-not-const-associated-fn.rs:12:40
+   |
+LL |     fn do_something_else() where Self: ~const MyTrait;
+   |                                        ^^^^^^
+   |
+note: this function is not `const`, so it cannot have `~const` trait bounds
+  --> $DIR/const-bound-on-not-const-associated-fn.rs:12:8
+   |
+LL |     fn do_something_else() where Self: ~const MyTrait;
+   |        ^^^^^^^^^^^^^^^^^
+
+error: `~const` is not allowed here
+  --> $DIR/const-bound-on-not-const-associated-fn.rs:23:32
+   |
+LL |     pub fn foo(&self) where T: ~const MyTrait {
+   |                                ^^^^^^
+   |
+note: this function is not `const`, so it cannot have `~const` trait bounds
+  --> $DIR/const-bound-on-not-const-associated-fn.rs:23:12
+   |
+LL |     pub fn foo(&self) where T: ~const MyTrait {
+   |            ^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-bounds-non-const-trait.rs b/tests/ui/traits/const-traits/const-bounds-non-const-trait.rs
similarity index 84%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const-bounds-non-const-trait.rs
rename to tests/ui/traits/const-traits/const-bounds-non-const-trait.rs
index db446f8..d51d231 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-bounds-non-const-trait.rs
+++ b/tests/ui/traits/const-traits/const-bounds-non-const-trait.rs
@@ -5,6 +5,7 @@
 
 const fn perform<T: ~const NonConst>() {}
 //~^ ERROR `~const` can only be applied to `#[const_trait]` traits
+//~| ERROR `~const` can only be applied to `#[const_trait]` traits
 
 fn operate<T: const NonConst>() {}
 //~^ ERROR `const` can only be applied to `#[const_trait]` traits
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-bounds-non-const-trait.stderr b/tests/ui/traits/const-traits/const-bounds-non-const-trait.stderr
similarity index 63%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const-bounds-non-const-trait.stderr
rename to tests/ui/traits/const-traits/const-bounds-non-const-trait.stderr
index e1a85fc..d27be2a 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-bounds-non-const-trait.stderr
+++ b/tests/ui/traits/const-traits/const-bounds-non-const-trait.stderr
@@ -13,16 +13,24 @@
    = help: use `-Znext-solver` to enable
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-bounds-non-const-trait.rs:6:28
+  --> $DIR/const-bounds-non-const-trait.rs:6:21
    |
 LL | const fn perform<T: ~const NonConst>() {}
-   |                            ^^^^^^^^
+   |                     ^^^^^^
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/const-bounds-non-const-trait.rs:6:21
+   |
+LL | const fn perform<T: ~const NonConst>() {}
+   |                     ^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: `const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-bounds-non-const-trait.rs:9:21
+  --> $DIR/const-bounds-non-const-trait.rs:10:15
    |
 LL | fn operate<T: const NonConst>() {}
-   |                     ^^^^^^^^
+   |               ^^^^^
 
-error: aborting due to 3 previous errors; 1 warning emitted
+error: aborting due to 4 previous errors; 1 warning emitted
 
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.rs b/tests/ui/traits/const-traits/const-check-fns-in-const-impl.rs
similarity index 88%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.rs
rename to tests/ui/traits/const-traits/const-check-fns-in-const-impl.rs
index a1710e6..7f9b38b 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.rs
+++ b/tests/ui/traits/const-traits/const-check-fns-in-const-impl.rs
@@ -1,3 +1,5 @@
+//@ compile-flags: -Znext-solver
+
 #![feature(const_trait_impl, effects)] //~ WARN the feature `effects` is incomplete
 
 struct S;
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.stderr b/tests/ui/traits/const-traits/const-check-fns-in-const-impl.stderr
similarity index 63%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.stderr
rename to tests/ui/traits/const-traits/const-check-fns-in-const-impl.stderr
index 49cd172..ba12854 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.stderr
+++ b/tests/ui/traits/const-traits/const-check-fns-in-const-impl.stderr
@@ -1,5 +1,5 @@
 warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/const-check-fns-in-const-impl.rs:1:30
+  --> $DIR/const-check-fns-in-const-impl.rs:3:30
    |
 LL | #![feature(const_trait_impl, effects)]
    |                              ^^^^^^^
@@ -7,19 +7,14 @@
    = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
    = note: `#[warn(incomplete_features)]` on by default
 
-error: using `#![feature(effects)]` without enabling next trait solver globally
-   |
-   = note: the next trait solver must be enabled globally for the effects feature to work correctly
-   = help: use `-Znext-solver` to enable
-
 error[E0015]: cannot call non-const fn `non_const` in constant functions
-  --> $DIR/const-check-fns-in-const-impl.rs:12:16
+  --> $DIR/const-check-fns-in-const-impl.rs:14:16
    |
 LL |     fn foo() { non_const() }
    |                ^^^^^^^^^^^
    |
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
 
-error: aborting due to 2 previous errors; 1 warning emitted
+error: aborting due to 1 previous error; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-parse-not-item.rs b/tests/ui/traits/const-traits/const-closure-parse-not-item.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-parse-not-item.rs
rename to tests/ui/traits/const-traits/const-closure-parse-not-item.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-parse-not-item.stderr b/tests/ui/traits/const-traits/const-closure-parse-not-item.stderr
similarity index 66%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-parse-not-item.stderr
rename to tests/ui/traits/const-traits/const-closure-parse-not-item.stderr
index 12cc79f..25c81ff 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-parse-not-item.stderr
+++ b/tests/ui/traits/const-traits/const-closure-parse-not-item.stderr
@@ -1,14 +1,14 @@
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-closure-parse-not-item.rs:7:32
+  --> $DIR/const-closure-parse-not-item.rs:7:25
    |
 LL | const fn test() -> impl ~const Fn() {
-   |                                ^^^^
+   |                         ^^^^^^
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-closure-parse-not-item.rs:7:32
+  --> $DIR/const-closure-parse-not-item.rs:7:25
    |
 LL | const fn test() -> impl ~const Fn() {
-   |                                ^^^^
+   |                         ^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method-fail.rs b/tests/ui/traits/const-traits/const-closure-trait-method-fail.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method-fail.rs
rename to tests/ui/traits/const-traits/const-closure-trait-method-fail.rs
diff --git a/tests/ui/traits/const-traits/const-closure-trait-method-fail.stderr b/tests/ui/traits/const-traits/const-closure-trait-method-fail.stderr
new file mode 100644
index 0000000..cb4c994
--- /dev/null
+++ b/tests/ui/traits/const-traits/const-closure-trait-method-fail.stderr
@@ -0,0 +1,29 @@
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/const-closure-trait-method-fail.rs:14:32
+   |
+LL | const fn need_const_closure<T: ~const FnOnce(()) -> i32>(x: T) -> i32 {
+   |                                ^^^^^^
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/const-closure-trait-method-fail.rs:14:32
+   |
+LL | const fn need_const_closure<T: ~const FnOnce(()) -> i32>(x: T) -> i32 {
+   |                                ^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0015]: cannot call non-const closure in constant functions
+  --> $DIR/const-closure-trait-method-fail.rs:15:5
+   |
+LL |     x(())
+   |     ^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+help: consider further restricting this bound
+   |
+LL | const fn need_const_closure<T: ~const FnOnce(()) -> i32 + ~const FnOnce(())>(x: T) -> i32 {
+   |                                                         +++++++++++++++++++
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method.rs b/tests/ui/traits/const-traits/const-closure-trait-method.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method.rs
rename to tests/ui/traits/const-traits/const-closure-trait-method.rs
diff --git a/tests/ui/traits/const-traits/const-closure-trait-method.stderr b/tests/ui/traits/const-traits/const-closure-trait-method.stderr
new file mode 100644
index 0000000..43af435
--- /dev/null
+++ b/tests/ui/traits/const-traits/const-closure-trait-method.stderr
@@ -0,0 +1,29 @@
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/const-closure-trait-method.rs:14:32
+   |
+LL | const fn need_const_closure<T: ~const FnOnce(()) -> i32>(x: T) -> i32 {
+   |                                ^^^^^^
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/const-closure-trait-method.rs:14:32
+   |
+LL | const fn need_const_closure<T: ~const FnOnce(()) -> i32>(x: T) -> i32 {
+   |                                ^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0015]: cannot call non-const closure in constant functions
+  --> $DIR/const-closure-trait-method.rs:15:5
+   |
+LL |     x(())
+   |     ^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+help: consider further restricting this bound
+   |
+LL | const fn need_const_closure<T: ~const FnOnce(()) -> i32 + ~const FnOnce(())>(x: T) -> i32 {
+   |                                                         +++++++++++++++++++
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closures.rs b/tests/ui/traits/const-traits/const-closures.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const-closures.rs
rename to tests/ui/traits/const-traits/const-closures.rs
diff --git a/tests/ui/traits/const-traits/const-closures.stderr b/tests/ui/traits/const-traits/const-closures.stderr
new file mode 100644
index 0000000..2e9e37b
--- /dev/null
+++ b/tests/ui/traits/const-traits/const-closures.stderr
@@ -0,0 +1,95 @@
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/const-closures.rs:8:12
+   |
+LL |         F: ~const FnOnce() -> u8,
+   |            ^^^^^^
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/const-closures.rs:9:12
+   |
+LL |         F: ~const FnMut() -> u8,
+   |            ^^^^^^
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/const-closures.rs:10:12
+   |
+LL |         F: ~const Fn() -> u8,
+   |            ^^^^^^
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/const-closures.rs:8:12
+   |
+LL |         F: ~const FnOnce() -> u8,
+   |            ^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/const-closures.rs:9:12
+   |
+LL |         F: ~const FnMut() -> u8,
+   |            ^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/const-closures.rs:10:12
+   |
+LL |         F: ~const Fn() -> u8,
+   |            ^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/const-closures.rs:23:20
+   |
+LL | const fn answer<F: ~const Fn() -> u8>(f: &F) -> u8 {
+   |                    ^^^^^^
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/const-closures.rs:23:20
+   |
+LL | const fn answer<F: ~const Fn() -> u8>(f: &F) -> u8 {
+   |                    ^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0015]: cannot call non-const closure in constant functions
+  --> $DIR/const-closures.rs:24:5
+   |
+LL |     f() + f()
+   |     ^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+help: consider further restricting this bound
+   |
+LL | const fn answer<F: ~const Fn() -> u8 + ~const Fn()>(f: &F) -> u8 {
+   |                                      +++++++++++++
+
+error[E0015]: cannot call non-const closure in constant functions
+  --> $DIR/const-closures.rs:24:11
+   |
+LL |     f() + f()
+   |           ^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+help: consider further restricting this bound
+   |
+LL | const fn answer<F: ~const Fn() -> u8 + ~const Fn()>(f: &F) -> u8 {
+   |                                      +++++++++++++
+
+error[E0015]: cannot call non-const closure in constant functions
+  --> $DIR/const-closures.rs:12:5
+   |
+LL |     f() * 7
+   |     ^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+help: consider further restricting this bound
+   |
+LL |         F: ~const FnOnce() -> u8 + ~const Fn(),
+   |                                  +++++++++++++
+
+error: aborting due to 11 previous errors
+
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-default-method-bodies.rs b/tests/ui/traits/const-traits/const-default-method-bodies.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const-default-method-bodies.rs
rename to tests/ui/traits/const-traits/const-default-method-bodies.rs
diff --git a/tests/ui/traits/const-traits/const-default-method-bodies.stderr b/tests/ui/traits/const-traits/const-default-method-bodies.stderr
new file mode 100644
index 0000000..071eaf4
--- /dev/null
+++ b/tests/ui/traits/const-traits/const-default-method-bodies.stderr
@@ -0,0 +1,9 @@
+error[E0277]: the trait bound `NonConstImpl: ~const ConstDefaultFn` is not satisfied
+  --> $DIR/const-default-method-bodies.rs:26:5
+   |
+LL |     NonConstImpl.a();
+   |     ^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-bound.rs b/tests/ui/traits/const-traits/const-drop-bound.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-bound.rs
rename to tests/ui/traits/const-traits/const-drop-bound.rs
diff --git a/tests/ui/traits/const-traits/const-drop-bound.stderr b/tests/ui/traits/const-traits/const-drop-bound.stderr
new file mode 100644
index 0000000..3f71864
--- /dev/null
+++ b/tests/ui/traits/const-traits/const-drop-bound.stderr
@@ -0,0 +1,51 @@
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/const-drop-bound.rs:9:61
+   |
+LL | const fn foo<T, E>(res: Result<T, E>) -> Option<T> where E: ~const Destruct {
+   |                                                             ^^^^^^
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/const-drop-bound.rs:9:61
+   |
+LL | const fn foo<T, E>(res: Result<T, E>) -> Option<T> where E: ~const Destruct {
+   |                                                             ^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/const-drop-bound.rs:20:8
+   |
+LL |     T: ~const Destruct,
+   |        ^^^^^^
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/const-drop-bound.rs:21:8
+   |
+LL |     E: ~const Destruct,
+   |        ^^^^^^
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/const-drop-bound.rs:20:8
+   |
+LL |     T: ~const Destruct,
+   |        ^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/const-drop-bound.rs:21:8
+   |
+LL |     E: ~const Destruct,
+   |        ^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0493]: destructor of `E` cannot be evaluated at compile-time
+  --> $DIR/const-drop-bound.rs:12:13
+   |
+LL |         Err(_e) => None,
+   |             ^^ the destructor for this type cannot be evaluated in constant functions
+
+error: aborting due to 7 previous errors
+
+For more information about this error, try `rustc --explain E0493`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.precise.stderr b/tests/ui/traits/const-traits/const-drop-fail-2.precise.stderr
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.precise.stderr
rename to tests/ui/traits/const-traits/const-drop-fail-2.precise.stderr
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.rs b/tests/ui/traits/const-traits/const-drop-fail-2.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.rs
rename to tests/ui/traits/const-traits/const-drop-fail-2.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.stderr b/tests/ui/traits/const-traits/const-drop-fail-2.stderr
similarity index 78%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.stderr
rename to tests/ui/traits/const-traits/const-drop-fail-2.stderr
index faf24c6d..82d6412 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.stderr
+++ b/tests/ui/traits/const-traits/const-drop-fail-2.stderr
@@ -8,10 +8,18 @@
    = note: adding a non-const method body in the future would be a breaking change
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-drop-fail-2.rs:20:26
+  --> $DIR/const-drop-fail-2.rs:20:19
    |
 LL | const fn check<T: ~const Destruct>(_: T) {}
-   |                          ^^^^^^^^
+   |                   ^^^^^^
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/const-drop-fail-2.rs:20:19
+   |
+LL | const fn check<T: ~const Destruct>(_: T) {}
+   |                   ^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0493]: destructor of `T` cannot be evaluated at compile-time
   --> $DIR/const-drop-fail-2.rs:20:36
@@ -33,7 +41,7 @@
 LL + #![feature(effects)]
    |
 
-error: aborting due to 4 previous errors
+error: aborting due to 5 previous errors
 
 Some errors have detailed explanations: E0015, E0493.
 For more information about an error, try `rustc --explain E0015`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.stock.stderr b/tests/ui/traits/const-traits/const-drop-fail-2.stock.stderr
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.stock.stderr
rename to tests/ui/traits/const-traits/const-drop-fail-2.stock.stderr
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail.precise.stderr b/tests/ui/traits/const-traits/const-drop-fail.precise.stderr
similarity index 87%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail.precise.stderr
rename to tests/ui/traits/const-traits/const-drop-fail.precise.stderr
index 3d400bf..859fdfa 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail.precise.stderr
+++ b/tests/ui/traits/const-traits/const-drop-fail.precise.stderr
@@ -8,10 +8,18 @@
    = note: adding a non-const method body in the future would be a breaking change
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-drop-fail.rs:23:26
+  --> $DIR/const-drop-fail.rs:23:19
    |
 LL | const fn check<T: ~const Destruct>(_: T) {}
-   |                          ^^^^^^^^
+   |                   ^^^^^^
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/const-drop-fail.rs:23:19
+   |
+LL | const fn check<T: ~const Destruct>(_: T) {}
+   |                   ^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0493]: destructor of `T` cannot be evaluated at compile-time
   --> $DIR/const-drop-fail.rs:23:36
@@ -71,7 +79,7 @@
    | |_- in this macro invocation
    = note: this error originates in the macro `check_all` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 5 previous errors
+error: aborting due to 6 previous errors
 
 Some errors have detailed explanations: E0080, E0493.
 For more information about an error, try `rustc --explain E0080`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail.rs b/tests/ui/traits/const-traits/const-drop-fail.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail.rs
rename to tests/ui/traits/const-traits/const-drop-fail.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail.stock.stderr b/tests/ui/traits/const-traits/const-drop-fail.stock.stderr
similarity index 71%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail.stock.stderr
rename to tests/ui/traits/const-traits/const-drop-fail.stock.stderr
index fd0f6d0..20dea28 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail.stock.stderr
+++ b/tests/ui/traits/const-traits/const-drop-fail.stock.stderr
@@ -8,10 +8,18 @@
    = note: adding a non-const method body in the future would be a breaking change
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-drop-fail.rs:23:26
+  --> $DIR/const-drop-fail.rs:23:19
    |
 LL | const fn check<T: ~const Destruct>(_: T) {}
-   |                          ^^^^^^^^
+   |                   ^^^^^^
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/const-drop-fail.rs:23:19
+   |
+LL | const fn check<T: ~const Destruct>(_: T) {}
+   |                   ^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0493]: destructor of `T` cannot be evaluated at compile-time
   --> $DIR/const-drop-fail.rs:23:36
@@ -21,6 +29,6 @@
    |                                    |
    |                                    the destructor for this type cannot be evaluated in constant functions
 
-error: aborting due to 3 previous errors
+error: aborting due to 4 previous errors
 
 For more information about this error, try `rustc --explain E0493`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.precise.stderr b/tests/ui/traits/const-traits/const-drop.precise.stderr
similarity index 75%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.precise.stderr
rename to tests/ui/traits/const-traits/const-drop.precise.stderr
index dd3ea5d..2b8066e 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.precise.stderr
+++ b/tests/ui/traits/const-traits/const-drop.precise.stderr
@@ -35,28 +35,16 @@
    = note: adding a non-const method body in the future would be a breaking change
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-drop.rs:18:22
+  --> $DIR/const-drop.rs:18:15
    |
 LL | const fn a<T: ~const Destruct>(_: T) {}
-   |                      ^^^^^^^^
+   |               ^^^^^^
 
-error[E0049]: associated function `foo` has 1 const parameter but its trait declaration has 0 const parameters
-  --> $DIR/const-drop.rs:53:5
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/const-drop.rs:18:15
    |
-LL |     #[const_trait]
-   |     ^^^^^^^^^^^^^^ found 1 const parameter
-LL |     pub trait SomeTrait {
-LL |         fn foo();
-   |               - expected 0 const parameters
-
-error[E0049]: associated function `foo` has 1 const parameter but its trait declaration has 0 const parameters
-  --> $DIR/const-drop.rs:53:5
-   |
-LL |     #[const_trait]
-   |     ^^^^^^^^^^^^^^ found 1 const parameter
-LL |     pub trait SomeTrait {
-LL |         fn foo();
-   |               - expected 0 const parameters
+LL | const fn a<T: ~const Destruct>(_: T) {}
+   |               ^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
@@ -78,7 +66,7 @@
 LL + #![feature(effects)]
    |
 
-error: aborting due to 9 previous errors
+error: aborting due to 8 previous errors
 
-Some errors have detailed explanations: E0015, E0049, E0493.
+Some errors have detailed explanations: E0015, E0493.
 For more information about an error, try `rustc --explain E0015`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.rs b/tests/ui/traits/const-traits/const-drop.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.rs
rename to tests/ui/traits/const-traits/const-drop.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.stock.stderr b/tests/ui/traits/const-traits/const-drop.stock.stderr
similarity index 75%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.stock.stderr
rename to tests/ui/traits/const-traits/const-drop.stock.stderr
index aa59e1c..54ed293 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.stock.stderr
+++ b/tests/ui/traits/const-traits/const-drop.stock.stderr
@@ -35,28 +35,16 @@
    = note: adding a non-const method body in the future would be a breaking change
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-drop.rs:18:22
+  --> $DIR/const-drop.rs:18:15
    |
 LL | const fn a<T: ~const Destruct>(_: T) {}
-   |                      ^^^^^^^^
+   |               ^^^^^^
 
-error[E0049]: associated function `foo` has 1 const parameter but its trait declaration has 0 const parameters
-  --> $DIR/const-drop.rs:53:5
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/const-drop.rs:18:15
    |
-LL |     #[const_trait]
-   |     ^^^^^^^^^^^^^^ found 1 const parameter
-LL |     pub trait SomeTrait {
-LL |         fn foo();
-   |               - expected 0 const parameters
-
-error[E0049]: associated function `foo` has 1 const parameter but its trait declaration has 0 const parameters
-  --> $DIR/const-drop.rs:53:5
-   |
-LL |     #[const_trait]
-   |     ^^^^^^^^^^^^^^ found 1 const parameter
-LL |     pub trait SomeTrait {
-LL |         fn foo();
-   |               - expected 0 const parameters
+LL | const fn a<T: ~const Destruct>(_: T) {}
+   |               ^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
@@ -80,7 +68,7 @@
 LL + #![feature(effects)]
    |
 
-error: aborting due to 9 previous errors
+error: aborting due to 8 previous errors
 
-Some errors have detailed explanations: E0015, E0049, E0493.
+Some errors have detailed explanations: E0015, E0493.
 For more information about an error, try `rustc --explain E0015`.
diff --git a/tests/ui/traits/const-traits/const-fns-are-early-bound.rs b/tests/ui/traits/const-traits/const-fns-are-early-bound.rs
new file mode 100644
index 0000000..6d08d8b
--- /dev/null
+++ b/tests/ui/traits/const-traits/const-fns-are-early-bound.rs
@@ -0,0 +1,90 @@
+//@ known-bug: #110395
+//@ failure-status: 101
+//@ dont-check-compiler-stderr
+// FIXME(effects) check-pass
+//@ compile-flags: -Znext-solver
+
+#![crate_type = "lib"]
+#![allow(internal_features, incomplete_features)]
+#![no_std]
+#![no_core]
+#![feature(
+    auto_traits,
+    const_trait_impl,
+    effects,
+    lang_items,
+    no_core,
+    staged_api,
+    unboxed_closures,
+    rustc_attrs,
+    marker_trait_attr,
+)]
+#![stable(feature = "minicore", since = "1.0.0")]
+
+fn test() {
+    fn is_const_fn<F>(_: F)
+    where
+        F: const FnOnce<()>,
+    {
+    }
+
+    const fn foo() {}
+
+    is_const_fn(foo);
+}
+
+/// ---------------------------------------------------------------------- ///
+/// Const fn trait definitions
+
+#[const_trait]
+#[lang = "fn"]
+#[rustc_paren_sugar]
+trait Fn<Args: Tuple>: ~const FnMut<Args> {
+    extern "rust-call" fn call(&self, args: Args) -> Self::Output;
+}
+
+#[const_trait]
+#[lang = "fn_mut"]
+#[rustc_paren_sugar]
+trait FnMut<Args: Tuple>: ~const FnOnce<Args> {
+    extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
+}
+
+#[const_trait]
+#[lang = "fn_once"]
+#[rustc_paren_sugar]
+trait FnOnce<Args: Tuple> {
+    #[lang = "fn_once_output"]
+    type Output;
+
+    extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
+}
+
+/// ---------------------------------------------------------------------- ///
+/// All this other stuff needed for core. Unrelated to test.
+
+#[lang = "destruct"]
+#[const_trait]
+trait Destruct {}
+
+#[lang = "freeze"]
+unsafe auto trait Freeze {}
+
+#[lang = "drop"]
+#[const_trait]
+trait Drop {
+    fn drop(&mut self);
+}
+
+#[lang = "sized"]
+trait Sized {}
+#[lang = "copy"]
+trait Copy {}
+
+#[lang = "tuple_trait"]
+trait Tuple {}
+
+#[lang = "legacy_receiver"]
+trait LegacyReceiver {}
+
+impl<T: ?Sized> LegacyReceiver for &T {}
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-norecover.rs b/tests/ui/traits/const-traits/const-impl-norecover.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-norecover.rs
rename to tests/ui/traits/const-traits/const-impl-norecover.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-norecover.stderr b/tests/ui/traits/const-traits/const-impl-norecover.stderr
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-norecover.stderr
rename to tests/ui/traits/const-traits/const-impl-norecover.stderr
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-recovery.rs b/tests/ui/traits/const-traits/const-impl-recovery.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-recovery.rs
rename to tests/ui/traits/const-traits/const-impl-recovery.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-recovery.stderr b/tests/ui/traits/const-traits/const-impl-recovery.stderr
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-recovery.stderr
rename to tests/ui/traits/const-traits/const-impl-recovery.stderr
diff --git a/tests/ui/traits/const-traits/const-impl-requires-const-trait.rs b/tests/ui/traits/const-traits/const-impl-requires-const-trait.rs
new file mode 100644
index 0000000..e49e909
--- /dev/null
+++ b/tests/ui/traits/const-traits/const-impl-requires-const-trait.rs
@@ -0,0 +1,10 @@
+//@ compile-flags: -Znext-solver
+#![feature(const_trait_impl, effects)]
+#![allow(incomplete_features)]
+
+pub trait A {}
+
+impl const A for () {}
+//~^ ERROR: const `impl` for trait `A` which is not marked with `#[const_trait]`
+
+fn main() {}
diff --git a/tests/ui/traits/const-traits/const-impl-requires-const-trait.stderr b/tests/ui/traits/const-traits/const-impl-requires-const-trait.stderr
new file mode 100644
index 0000000..828e217
--- /dev/null
+++ b/tests/ui/traits/const-traits/const-impl-requires-const-trait.stderr
@@ -0,0 +1,14 @@
+error: const `impl` for trait `A` which is not marked with `#[const_trait]`
+  --> $DIR/const-impl-requires-const-trait.rs:7:12
+   |
+LL | pub trait A {}
+   | - help: mark `A` as const: `#[const_trait]`
+LL |
+LL | impl const A for () {}
+   |            ^
+   |
+   = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const`
+   = note: adding a non-const method body in the future would be a breaking change
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-trait.rs b/tests/ui/traits/const-traits/const-impl-trait.rs
similarity index 92%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-trait.rs
rename to tests/ui/traits/const-traits/const-impl-trait.rs
index 51dfe29..61b8c9a 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-trait.rs
+++ b/tests/ui/traits/const-traits/const-impl-trait.rs
@@ -1,4 +1,7 @@
+//@ compile-flags: -Znext-solver
 //@ known-bug: #110395
+//@ failure-status: 101
+//@ dont-check-compiler-stderr
 // Broken until we have `&T: const Deref` impl in stdlib
 
 #![allow(incomplete_features)]
diff --git a/tests/ui/traits/const-traits/const-in-closure.rs b/tests/ui/traits/const-traits/const-in-closure.rs
new file mode 100644
index 0000000..51b22c5
--- /dev/null
+++ b/tests/ui/traits/const-traits/const-in-closure.rs
@@ -0,0 +1,25 @@
+//@ compile-flags: -Znext-solver
+//@ check-pass
+
+#![feature(const_trait_impl, effects)]
+//~^ WARN the feature `effects` is incomplete
+
+#[const_trait] trait Trait {
+    fn method();
+}
+
+const fn foo<T: Trait>() {
+    let _ = || {
+        // Make sure this doesn't enforce `T: ~const Trait`
+        T::method();
+    };
+}
+
+fn bar<T: const Trait>() {
+    let _ = || {
+        // Make sure unconditionally const bounds propagate from parent.
+        const { T::method(); };
+    };
+}
+
+fn main() {}
diff --git a/tests/ui/traits/const-traits/const-in-closure.stderr b/tests/ui/traits/const-traits/const-in-closure.stderr
new file mode 100644
index 0000000..f4b03b9
--- /dev/null
+++ b/tests/ui/traits/const-traits/const-in-closure.stderr
@@ -0,0 +1,11 @@
+warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/const-in-closure.rs:4:30
+   |
+LL | #![feature(const_trait_impl, effects)]
+   |                              ^^^^^^^
+   |
+   = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-trait-bounds-trait-objects.rs b/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const-trait-bounds-trait-objects.rs
rename to tests/ui/traits/const-traits/const-trait-bounds-trait-objects.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-trait-bounds-trait-objects.stderr b/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.stderr
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const-trait-bounds-trait-objects.stderr
rename to tests/ui/traits/const-traits/const-trait-bounds-trait-objects.stderr
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-trait-bounds.rs b/tests/ui/traits/const-traits/const-trait-bounds.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const-trait-bounds.rs
rename to tests/ui/traits/const-traits/const-trait-bounds.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-trait-bounds.stderr b/tests/ui/traits/const-traits/const-trait-bounds.stderr
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const-trait-bounds.stderr
rename to tests/ui/traits/const-traits/const-trait-bounds.stderr
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-gate.rs b/tests/ui/traits/const-traits/const_derives/derive-const-gate.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-gate.rs
rename to tests/ui/traits/const-traits/const_derives/derive-const-gate.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-gate.stderr b/tests/ui/traits/const-traits/const_derives/derive-const-gate.stderr
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-gate.stderr
rename to tests/ui/traits/const-traits/const_derives/derive-const-gate.stderr
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-non-const-type.rs b/tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-non-const-type.rs
rename to tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-non-const-type.stderr b/tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.stderr
similarity index 63%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-non-const-type.stderr
rename to tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.stderr
index 777b331..4bcc179 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-non-const-type.stderr
+++ b/tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.stderr
@@ -22,5 +22,17 @@
    = note: adding a non-const method body in the future would be a breaking change
    = note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 2 previous errors; 1 warning emitted
+error[E0015]: cannot call non-const fn `<A as Default>::default` in constant functions
+  --> $DIR/derive-const-non-const-type.rs:11:14
+   |
+LL | #[derive_const(Default)]
+   |                ------- in this derive macro expansion
+LL | pub struct S(A);
+   |              ^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+   = note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info)
 
+error: aborting due to 3 previous errors; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-use.rs b/tests/ui/traits/const-traits/const_derives/derive-const-use.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-use.rs
rename to tests/ui/traits/const-traits/const_derives/derive-const-use.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-use.stderr b/tests/ui/traits/const-traits/const_derives/derive-const-use.stderr
similarity index 61%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-use.stderr
rename to tests/ui/traits/const-traits/const_derives/derive-const-use.stderr
index ad727fc..d471a82 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-use.stderr
+++ b/tests/ui/traits/const-traits/const_derives/derive-const-use.stderr
@@ -62,29 +62,67 @@
    = note: adding a non-const method body in the future would be a breaking change
    = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error[E0080]: evaluation of constant value failed
-  --> $DIR/derive-const-use.rs:16:14
+error[E0015]: cannot call non-const fn `<S as Default>::default` in constants
+  --> $DIR/derive-const-use.rs:18:35
    |
-LL | #[derive_const(Default, PartialEq)]
-   |                ------- in this derive macro expansion
-LL | pub struct S((), A);
-   |              ^^ calling non-const function `<() as Default>::default`
+LL | const _: () = assert!(S((), A) == S::default());
+   |                                   ^^^^^^^^^^^^
    |
-note: inside `<S as Default>::default`
+   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
+
+error[E0015]: cannot call non-const operator in constants
+  --> $DIR/derive-const-use.rs:18:23
+   |
+LL | const _: () = assert!(S((), A) == S::default());
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
+
+error[E0015]: cannot call non-const fn `<() as Default>::default` in constant functions
   --> $DIR/derive-const-use.rs:16:14
    |
 LL | #[derive_const(Default, PartialEq)]
    |                ------- in this derive macro expansion
 LL | pub struct S((), A);
    |              ^^
-note: inside `_`
-  --> $DIR/derive-const-use.rs:18:35
    |
-LL | const _: () = assert!(S((), A) == S::default());
-   |                                   ^^^^^^^^^^^^
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
    = note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 8 previous errors; 1 warning emitted
+error[E0015]: cannot call non-const fn `<A as Default>::default` in constant functions
+  --> $DIR/derive-const-use.rs:16:18
+   |
+LL | #[derive_const(Default, PartialEq)]
+   |                ------- in this derive macro expansion
+LL | pub struct S((), A);
+   |                  ^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+   = note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-Some errors have detailed explanations: E0080, E0635.
-For more information about an error, try `rustc --explain E0080`.
+error[E0015]: cannot call non-const operator in constant functions
+  --> $DIR/derive-const-use.rs:16:14
+   |
+LL | #[derive_const(Default, PartialEq)]
+   |                         --------- in this derive macro expansion
+LL | pub struct S((), A);
+   |              ^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+   = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0015]: cannot call non-const operator in constant functions
+  --> $DIR/derive-const-use.rs:16:18
+   |
+LL | #[derive_const(Default, PartialEq)]
+   |                         --------- in this derive macro expansion
+LL | pub struct S((), A);
+   |                  ^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+   = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 13 previous errors; 1 warning emitted
+
+Some errors have detailed explanations: E0015, E0635.
+For more information about an error, try `rustc --explain E0015`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-with-params.rs b/tests/ui/traits/const-traits/const_derives/derive-const-with-params.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-with-params.rs
rename to tests/ui/traits/const-traits/const_derives/derive-const-with-params.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-with-params.stderr b/tests/ui/traits/const-traits/const_derives/derive-const-with-params.stderr
similarity index 65%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-with-params.stderr
rename to tests/ui/traits/const-traits/const_derives/derive-const-with-params.stderr
index addce8d..64285cf 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-with-params.stderr
+++ b/tests/ui/traits/const-traits/const_derives/derive-const-with-params.stderr
@@ -23,12 +23,26 @@
    = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/derive-const-with-params.rs:7:16
+
+error[E0015]: cannot call non-const operator in constant functions
+  --> $DIR/derive-const-with-params.rs:8:23
    |
 LL | #[derive_const(PartialEq)]
-   |                ^^^^^^^^^
+   |                --------- in this derive macro expansion
+LL | pub struct Reverse<T>(T);
+   |                       ^
    |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
    = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 3 previous errors; 1 warning emitted
+error[E0015]: cannot call non-const operator in constant functions
+  --> $DIR/derive-const-with-params.rs:11:5
+   |
+LL |     a == b
+   |     ^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
 
+error: aborting due to 5 previous errors; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate-default-method-body-is-const.rs b/tests/ui/traits/const-traits/cross-crate-default-method-body-is-const.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate-default-method-body-is-const.rs
rename to tests/ui/traits/const-traits/cross-crate-default-method-body-is-const.rs
diff --git a/tests/ui/traits/const-traits/cross-crate.gatednc.stderr b/tests/ui/traits/const-traits/cross-crate.gatednc.stderr
new file mode 100644
index 0000000..b6f2434
--- /dev/null
+++ b/tests/ui/traits/const-traits/cross-crate.gatednc.stderr
@@ -0,0 +1,9 @@
+error[E0277]: the trait bound `cross_crate::NonConst: ~const cross_crate::MyTrait` is not satisfied
+  --> $DIR/cross-crate.rs:19:5
+   |
+LL |     NonConst.func();
+   |     ^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate.rs b/tests/ui/traits/const-traits/cross-crate.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate.rs
rename to tests/ui/traits/const-traits/cross-crate.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate.stock.stderr b/tests/ui/traits/const-traits/cross-crate.stock.stderr
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate.stock.stderr
rename to tests/ui/traits/const-traits/cross-crate.stock.stderr
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate.stocknc.stderr b/tests/ui/traits/const-traits/cross-crate.stocknc.stderr
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate.stocknc.stderr
rename to tests/ui/traits/const-traits/cross-crate.stocknc.stderr
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.rs b/tests/ui/traits/const-traits/default-method-body-is-const-body-checking.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.rs
rename to tests/ui/traits/const-traits/default-method-body-is-const-body-checking.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.rs b/tests/ui/traits/const-traits/default-method-body-is-const-same-trait-ck.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.rs
rename to tests/ui/traits/const-traits/default-method-body-is-const-same-trait-ck.rs
diff --git a/tests/ui/traits/const-traits/default-method-body-is-const-same-trait-ck.stderr b/tests/ui/traits/const-traits/default-method-body-is-const-same-trait-ck.stderr
new file mode 100644
index 0000000..7b4d512
--- /dev/null
+++ b/tests/ui/traits/const-traits/default-method-body-is-const-same-trait-ck.stderr
@@ -0,0 +1,9 @@
+error[E0277]: the trait bound `(): ~const Tr` is not satisfied
+  --> $DIR/default-method-body-is-const-same-trait-ck.rs:10:9
+   |
+LL |         ().a()
+   |         ^^^^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-with-staged-api.rs b/tests/ui/traits/const-traits/default-method-body-is-const-with-staged-api.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-with-staged-api.rs
rename to tests/ui/traits/const-traits/default-method-body-is-const-with-staged-api.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/do-not-const-check-override.rs b/tests/ui/traits/const-traits/do-not-const-check-override.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/do-not-const-check-override.rs
rename to tests/ui/traits/const-traits/do-not-const-check-override.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/do-not-const-check.rs b/tests/ui/traits/const-traits/do-not-const-check.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/do-not-const-check.rs
rename to tests/ui/traits/const-traits/do-not-const-check.rs
diff --git a/tests/ui/traits/const-traits/dont-observe-host-opaque.rs b/tests/ui/traits/const-traits/dont-observe-host-opaque.rs
new file mode 100644
index 0000000..4a5ae34
--- /dev/null
+++ b/tests/ui/traits/const-traits/dont-observe-host-opaque.rs
@@ -0,0 +1,12 @@
+//@ compile-flags: -Znext-solver
+//@ check-pass
+
+#![feature(const_trait_impl, effects)]
+//~^ WARN the feature `effects` is incomplete
+
+const fn opaque() -> impl Sized {}
+
+fn main() {
+    let mut x = const { opaque() };
+    x = opaque();
+}
diff --git a/tests/ui/traits/const-traits/dont-observe-host-opaque.stderr b/tests/ui/traits/const-traits/dont-observe-host-opaque.stderr
new file mode 100644
index 0000000..1b457ab
--- /dev/null
+++ b/tests/ui/traits/const-traits/dont-observe-host-opaque.stderr
@@ -0,0 +1,11 @@
+warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/dont-observe-host-opaque.rs:4:30
+   |
+LL | #![feature(const_trait_impl, effects)]
+   |                              ^^^^^^^
+   |
+   = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/traits/const-traits/dont-observe-host.rs b/tests/ui/traits/const-traits/dont-observe-host.rs
new file mode 100644
index 0000000..d027d57
--- /dev/null
+++ b/tests/ui/traits/const-traits/dont-observe-host.rs
@@ -0,0 +1,23 @@
+//@ compile-flags: -Znext-solver
+//@ check-pass
+
+#![feature(const_trait_impl, effects)]
+//~^ WARN the feature `effects` is incomplete
+
+#[const_trait]
+trait Trait {
+    fn method() {}
+}
+
+impl const Trait for () {}
+
+fn main() {
+    let mut x = const {
+        let x = <()>::method;
+        x();
+        x
+    };
+    let y = <()>::method;
+    y();
+    x = y;
+}
diff --git a/tests/ui/traits/const-traits/dont-observe-host.stderr b/tests/ui/traits/const-traits/dont-observe-host.stderr
new file mode 100644
index 0000000..64ef611
--- /dev/null
+++ b/tests/ui/traits/const-traits/dont-observe-host.stderr
@@ -0,0 +1,11 @@
+warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/dont-observe-host.rs:4:30
+   |
+LL | #![feature(const_trait_impl, effects)]
+   |                              ^^^^^^^
+   |
+   = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/auxiliary/cross-crate.rs b/tests/ui/traits/const-traits/effects/auxiliary/cross-crate.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/effects/auxiliary/cross-crate.rs
rename to tests/ui/traits/const-traits/effects/auxiliary/cross-crate.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/const_closure-const_trait_impl-ice-113381.rs b/tests/ui/traits/const-traits/effects/const_closure-const_trait_impl-ice-113381.rs
similarity index 62%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/effects/const_closure-const_trait_impl-ice-113381.rs
rename to tests/ui/traits/const-traits/effects/const_closure-const_trait_impl-ice-113381.rs
index 3debc22..8f8e9f0 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/const_closure-const_trait_impl-ice-113381.rs
+++ b/tests/ui/traits/const-traits/effects/const_closure-const_trait_impl-ice-113381.rs
@@ -1,5 +1,3 @@
-//@ check-pass
-// FIXME(effects) this shouldn't pass
 //@ compile-flags: -Znext-solver
 #![feature(const_closures, const_trait_impl, effects)]
 #![allow(incomplete_features)]
@@ -14,5 +12,6 @@
 
 fn main() {
     (const || { (()).foo() })();
-    // FIXME(effects) ~^ ERROR: cannot call non-const fn
+    //~^ ERROR: cannot call non-const fn `<() as Foo>::foo` in constant functions
+    // FIXME(effects) this should probably say constant closures
 }
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/non-const-op-const-closure-non-const-outer.stderr b/tests/ui/traits/const-traits/effects/const_closure-const_trait_impl-ice-113381.stderr
similarity index 68%
copy from tests/ui/rfcs/rfc-2632-const-trait-impl/non-const-op-const-closure-non-const-outer.stderr
copy to tests/ui/traits/const-traits/effects/const_closure-const_trait_impl-ice-113381.stderr
index c362a10..243e940 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/non-const-op-const-closure-non-const-outer.stderr
+++ b/tests/ui/traits/const-traits/effects/const_closure-const_trait_impl-ice-113381.stderr
@@ -1,14 +1,10 @@
 error[E0015]: cannot call non-const fn `<() as Foo>::foo` in constant functions
-  --> $DIR/non-const-op-const-closure-non-const-outer.rs:13:22
+  --> $DIR/const_closure-const_trait_impl-ice-113381.rs:14:22
    |
 LL |     (const || { (()).foo() })();
    |                      ^^^^^
    |
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(effects)]` to the crate attributes to enable
-   |
-LL + #![feature(effects)]
-   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/effect-param-infer.rs b/tests/ui/traits/const-traits/effects/effect-param-infer.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/effects/effect-param-infer.rs
rename to tests/ui/traits/const-traits/effects/effect-param-infer.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/fallback.rs b/tests/ui/traits/const-traits/effects/fallback.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/effects/fallback.rs
rename to tests/ui/traits/const-traits/effects/fallback.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/group-traits.rs b/tests/ui/traits/const-traits/effects/group-traits.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/effects/group-traits.rs
rename to tests/ui/traits/const-traits/effects/group-traits.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/helloworld.rs b/tests/ui/traits/const-traits/effects/helloworld.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/effects/helloworld.rs
rename to tests/ui/traits/const-traits/effects/helloworld.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/ice-112822-expected-type-for-param.rs b/tests/ui/traits/const-traits/effects/ice-112822-expected-type-for-param.rs
similarity index 90%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/effects/ice-112822-expected-type-for-param.rs
rename to tests/ui/traits/const-traits/effects/ice-112822-expected-type-for-param.rs
index 9a9016d..ab530b1 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/ice-112822-expected-type-for-param.rs
+++ b/tests/ui/traits/const-traits/effects/ice-112822-expected-type-for-param.rs
@@ -10,6 +10,7 @@
             [first, remainder @ ..] => {
                 assert_eq!(first, &b'f');
                 //~^ ERROR cannot call non-const fn
+                //~| ERROR cannot call non-const operator
             }
             [] => panic!(),
         }
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/ice-112822-expected-type-for-param.stderr b/tests/ui/traits/const-traits/effects/ice-112822-expected-type-for-param.stderr
similarity index 73%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/effects/ice-112822-expected-type-for-param.stderr
rename to tests/ui/traits/const-traits/effects/ice-112822-expected-type-for-param.stderr
index 526746e..5b0d5a8 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/ice-112822-expected-type-for-param.stderr
+++ b/tests/ui/traits/const-traits/effects/ice-112822-expected-type-for-param.stderr
@@ -23,19 +23,28 @@
    = help: use `-Znext-solver` to enable
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/ice-112822-expected-type-for-param.rs:3:32
+  --> $DIR/ice-112822-expected-type-for-param.rs:3:25
    |
 LL | const fn test() -> impl ~const Fn() {
-   |                                ^^^^
+   |                         ^^^^^^
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/ice-112822-expected-type-for-param.rs:3:32
+  --> $DIR/ice-112822-expected-type-for-param.rs:3:25
    |
 LL | const fn test() -> impl ~const Fn() {
-   |                                ^^^^
+   |                         ^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
+error[E0015]: cannot call non-const operator in constant functions
+  --> $DIR/ice-112822-expected-type-for-param.rs:11:17
+   |
+LL |                 assert_eq!(first, &b'f');
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+   = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
 error[E0015]: cannot call non-const fn `core::panicking::assert_failed::<&u8, &u8>` in constant functions
   --> $DIR/ice-112822-expected-type-for-param.rs:11:17
    |
@@ -45,7 +54,7 @@
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
    = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 5 previous errors; 1 warning emitted
+error: aborting due to 6 previous errors; 1 warning emitted
 
 Some errors have detailed explanations: E0015, E0658.
 For more information about an error, try `rustc --explain E0015`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/ice-113375-index-out-of-bounds-generics.rs b/tests/ui/traits/const-traits/effects/ice-113375-index-out-of-bounds-generics.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/effects/ice-113375-index-out-of-bounds-generics.rs
rename to tests/ui/traits/const-traits/effects/ice-113375-index-out-of-bounds-generics.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/infer-fallback.rs b/tests/ui/traits/const-traits/effects/infer-fallback.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/effects/infer-fallback.rs
rename to tests/ui/traits/const-traits/effects/infer-fallback.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.rs b/tests/ui/traits/const-traits/effects/minicore.rs
similarity index 90%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.rs
rename to tests/ui/traits/const-traits/effects/minicore.rs
index 1c3c66b..1f0d22e 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.rs
+++ b/tests/ui/traits/const-traits/effects/minicore.rs
@@ -137,12 +137,12 @@
 //impl_fn_mut_tuple!(A B C D);
 //impl_fn_mut_tuple!(A B C D E);
 
-#[lang = "receiver"]
-trait Receiver {}
+#[lang = "legacy_receiver"]
+trait LegacyReceiver {}
 
-impl<T: ?Sized> Receiver for &T {}
+impl<T: ?Sized> LegacyReceiver for &T {}
 
-impl<T: ?Sized> Receiver for &mut T {}
+impl<T: ?Sized> LegacyReceiver for &mut T {}
 
 #[lang = "destruct"]
 #[const_trait]
@@ -454,7 +454,7 @@
     }
 }
 
-impl<P: Receiver> Receiver for Pin<P> {}
+impl<P: LegacyReceiver> LegacyReceiver for Pin<P> {}
 
 impl<T: Clone> Clone for RefCell<T> {
     fn clone(&self) -> RefCell<T> {
@@ -515,7 +515,7 @@
 
 const fn drop<T: ~const Destruct>(_: T) {}
 
-#[rustc_const_stable(feature = "const_eval_select", since = "1.0.0")]
+#[rustc_const_stable_indirect]
 #[rustc_intrinsic_must_be_overridden]
 #[rustc_intrinsic]
 const fn const_eval_select<ARG: Tuple, F, G, RET>(
@@ -536,35 +536,3 @@
 
     const_eval_select((), const_fn, rt_fn);
 }
-
-mod effects {
-    use super::Sized;
-
-    #[lang = "EffectsNoRuntime"]
-    pub struct NoRuntime;
-    #[lang = "EffectsMaybe"]
-    pub struct Maybe;
-    #[lang = "EffectsRuntime"]
-    pub struct Runtime;
-
-    #[lang = "EffectsCompat"]
-    pub trait Compat<#[rustc_runtime] const RUNTIME: bool> {}
-
-    impl Compat<false> for NoRuntime {}
-    impl Compat<true> for Runtime {}
-    impl<#[rustc_runtime] const RUNTIME: bool> Compat<RUNTIME> for Maybe {}
-
-    #[lang = "EffectsTyCompat"]
-    #[marker]
-    pub trait TyCompat<T: ?Sized> {}
-
-    impl<T: ?Sized> TyCompat<T> for T {}
-    impl<T: ?Sized> TyCompat<T> for Maybe {}
-    impl<T: ?Sized> TyCompat<Maybe> for T {}
-
-    #[lang = "EffectsIntersection"]
-    pub trait Intersection {
-        #[lang = "EffectsIntersectionOutput"]
-        type Output: ?Sized;
-    }
-}
diff --git a/tests/ui/traits/const-traits/effects/minicore.stderr b/tests/ui/traits/const-traits/effects/minicore.stderr
new file mode 100644
index 0000000..568d98c
--- /dev/null
+++ b/tests/ui/traits/const-traits/effects/minicore.stderr
@@ -0,0 +1,13 @@
+error: the compiler unexpectedly panicked. this is a bug.
+
+query stack during panic:
+#0 [typeck] type-checking `Clone::clone_from`
+#1 [analysis] running analysis passes on this crate
+end of query stack
+
+error: the compiler unexpectedly panicked. this is a bug.
+
+query stack during panic:
+#0 [typeck] type-checking `test_const_eval_select`
+#1 [analysis] running analysis passes on this crate
+end of query stack
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/mismatched_generic_args.rs b/tests/ui/traits/const-traits/effects/mismatched_generic_args.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/effects/mismatched_generic_args.rs
rename to tests/ui/traits/const-traits/effects/mismatched_generic_args.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/mismatched_generic_args.stderr b/tests/ui/traits/const-traits/effects/mismatched_generic_args.stderr
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/effects/mismatched_generic_args.stderr
rename to tests/ui/traits/const-traits/effects/mismatched_generic_args.stderr
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/no-explicit-const-params-cross-crate.rs b/tests/ui/traits/const-traits/effects/no-explicit-const-params-cross-crate.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/effects/no-explicit-const-params-cross-crate.rs
rename to tests/ui/traits/const-traits/effects/no-explicit-const-params-cross-crate.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/no-explicit-const-params-cross-crate.stderr b/tests/ui/traits/const-traits/effects/no-explicit-const-params-cross-crate.stderr
similarity index 82%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/effects/no-explicit-const-params-cross-crate.stderr
rename to tests/ui/traits/const-traits/effects/no-explicit-const-params-cross-crate.stderr
index 8c591ed..eea6a06 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/no-explicit-const-params-cross-crate.stderr
+++ b/tests/ui/traits/const-traits/effects/no-explicit-const-params-cross-crate.stderr
@@ -16,17 +16,15 @@
   --> $DIR/no-explicit-const-params-cross-crate.rs:16:12
    |
 LL |     <() as Bar<false>>::bar();
-   |            ^^^ expected 0 generic arguments
+   |            ^^^------- help: remove the unnecessary generics
+   |            |
+   |            expected 0 generic arguments
    |
 note: trait defined here, with 0 generic parameters
   --> $DIR/auxiliary/cross-crate.rs:8:11
    |
 LL | pub trait Bar {
    |           ^^^
-help: replace the generic bound with the associated type
-   |
-LL |     <() as Bar< = false>>::bar();
-   |                 +
 
 error[E0107]: function takes 0 generic arguments but 1 generic argument was supplied
   --> $DIR/no-explicit-const-params-cross-crate.rs:7:5
@@ -46,17 +44,15 @@
   --> $DIR/no-explicit-const-params-cross-crate.rs:9:12
    |
 LL |     <() as Bar<true>>::bar();
-   |            ^^^ expected 0 generic arguments
+   |            ^^^------ help: remove the unnecessary generics
+   |            |
+   |            expected 0 generic arguments
    |
 note: trait defined here, with 0 generic parameters
   --> $DIR/auxiliary/cross-crate.rs:8:11
    |
 LL | pub trait Bar {
    |           ^^^
-help: replace the generic bound with the associated type
-   |
-LL |     <() as Bar< = true>>::bar();
-   |                 +
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/no-explicit-const-params.rs b/tests/ui/traits/const-traits/effects/no-explicit-const-params.rs
similarity index 94%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/effects/no-explicit-const-params.rs
rename to tests/ui/traits/const-traits/effects/no-explicit-const-params.rs
index 84f5f28..b08aba9 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/no-explicit-const-params.rs
+++ b/tests/ui/traits/const-traits/effects/no-explicit-const-params.rs
@@ -23,5 +23,4 @@
     //~^ ERROR: function takes 0 generic arguments but 1 generic argument was supplied
     <() as Bar<false>>::bar();
     //~^ ERROR: trait takes 0 generic arguments but 1 generic argument was supplied
-    //~| ERROR: mismatched types
 };
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/no-explicit-const-params.stderr b/tests/ui/traits/const-traits/effects/no-explicit-const-params.stderr
similarity index 72%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/effects/no-explicit-const-params.stderr
rename to tests/ui/traits/const-traits/effects/no-explicit-const-params.stderr
index cc08114..a3aa970 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/no-explicit-const-params.stderr
+++ b/tests/ui/traits/const-traits/effects/no-explicit-const-params.stderr
@@ -30,26 +30,15 @@
   --> $DIR/no-explicit-const-params.rs:24:12
    |
 LL |     <() as Bar<false>>::bar();
-   |            ^^^ expected 0 generic arguments
+   |            ^^^------- help: remove the unnecessary generics
+   |            |
+   |            expected 0 generic arguments
    |
 note: trait defined here, with 0 generic parameters
   --> $DIR/no-explicit-const-params.rs:6:7
    |
 LL | trait Bar {
    |       ^^^
-help: replace the generic bound with the associated type
-   |
-LL |     <() as Bar< = false>>::bar();
-   |                 +
-
-error[E0308]: mismatched types
-  --> $DIR/no-explicit-const-params.rs:24:5
-   |
-LL |     <() as Bar<false>>::bar();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^ expected `false`, found `true`
-   |
-   = note: expected constant `false`
-              found constant `true`
 
 error[E0107]: function takes 0 generic arguments but 1 generic argument was supplied
   --> $DIR/no-explicit-const-params.rs:15:5
@@ -69,19 +58,16 @@
   --> $DIR/no-explicit-const-params.rs:17:12
    |
 LL |     <() as Bar<true>>::bar();
-   |            ^^^ expected 0 generic arguments
+   |            ^^^------ help: remove the unnecessary generics
+   |            |
+   |            expected 0 generic arguments
    |
 note: trait defined here, with 0 generic parameters
   --> $DIR/no-explicit-const-params.rs:6:7
    |
 LL | trait Bar {
    |       ^^^
-help: replace the generic bound with the associated type
-   |
-LL |     <() as Bar< = true>>::bar();
-   |                 +
 
-error: aborting due to 6 previous errors; 1 warning emitted
+error: aborting due to 5 previous errors; 1 warning emitted
 
-Some errors have detailed explanations: E0107, E0308.
-For more information about an error, try `rustc --explain E0107`.
+For more information about this error, try `rustc --explain E0107`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/project.rs b/tests/ui/traits/const-traits/effects/project.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/effects/project.rs
rename to tests/ui/traits/const-traits/effects/project.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/span-bug-issue-121418.rs b/tests/ui/traits/const-traits/effects/span-bug-issue-121418.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/effects/span-bug-issue-121418.rs
rename to tests/ui/traits/const-traits/effects/span-bug-issue-121418.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/span-bug-issue-121418.stderr b/tests/ui/traits/const-traits/effects/span-bug-issue-121418.stderr
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/effects/span-bug-issue-121418.stderr
rename to tests/ui/traits/const-traits/effects/span-bug-issue-121418.stderr
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/spec-effectvar-ice.rs b/tests/ui/traits/const-traits/effects/spec-effectvar-ice.rs
similarity index 97%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/effects/spec-effectvar-ice.rs
rename to tests/ui/traits/const-traits/effects/spec-effectvar-ice.rs
index 0508b1c..d29cd93 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/spec-effectvar-ice.rs
+++ b/tests/ui/traits/const-traits/effects/spec-effectvar-ice.rs
@@ -1,4 +1,3 @@
-//@ check-fail
 // Fixes #119830
 
 #![feature(effects)] //~ WARN the feature `effects` is incomplete
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/spec-effectvar-ice.stderr b/tests/ui/traits/const-traits/effects/spec-effectvar-ice.stderr
similarity index 85%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/effects/spec-effectvar-ice.stderr
rename to tests/ui/traits/const-traits/effects/spec-effectvar-ice.stderr
index e97a961..0cb172a 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/spec-effectvar-ice.stderr
+++ b/tests/ui/traits/const-traits/effects/spec-effectvar-ice.stderr
@@ -1,5 +1,5 @@
 warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/spec-effectvar-ice.rs:4:12
+  --> $DIR/spec-effectvar-ice.rs:3:12
    |
 LL | #![feature(effects)]
    |            ^^^^^^^
@@ -13,7 +13,7 @@
    = help: use `-Znext-solver` to enable
 
 error: const `impl` for trait `Foo` which is not marked with `#[const_trait]`
-  --> $DIR/spec-effectvar-ice.rs:12:15
+  --> $DIR/spec-effectvar-ice.rs:11:15
    |
 LL | trait Foo {}
    | - help: mark `Foo` as const: `#[const_trait]`
@@ -25,7 +25,7 @@
    = note: adding a non-const method body in the future would be a breaking change
 
 error: const `impl` for trait `Foo` which is not marked with `#[const_trait]`
-  --> $DIR/spec-effectvar-ice.rs:15:15
+  --> $DIR/spec-effectvar-ice.rs:14:15
    |
 LL | trait Foo {}
    | - help: mark `Foo` as const: `#[const_trait]`
@@ -37,25 +37,25 @@
    = note: adding a non-const method body in the future would be a breaking change
 
 error: `const` can only be applied to `#[const_trait]` traits
-  --> $DIR/spec-effectvar-ice.rs:15:40
+  --> $DIR/spec-effectvar-ice.rs:14:34
    |
 LL | impl<T> const Foo for T where T: const Specialize {}
-   |                                        ^^^^^^^^^^
+   |                                  ^^^^^
 
 error: specialization impl does not specialize any associated items
-  --> $DIR/spec-effectvar-ice.rs:15:1
+  --> $DIR/spec-effectvar-ice.rs:14:1
    |
 LL | impl<T> const Foo for T where T: const Specialize {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: impl is a specialization of this impl
-  --> $DIR/spec-effectvar-ice.rs:12:1
+  --> $DIR/spec-effectvar-ice.rs:11:1
    |
 LL | impl<T> const Foo for T {}
    | ^^^^^^^^^^^^^^^^^^^^^^^
 
 error: cannot specialize on trait `Specialize`
-  --> $DIR/spec-effectvar-ice.rs:15:34
+  --> $DIR/spec-effectvar-ice.rs:14:34
    |
 LL | impl<T> const Foo for T where T: const Specialize {}
    |                                  ^^^^^^^^^^^^^^^^
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/trait-fn-const.rs b/tests/ui/traits/const-traits/effects/trait-fn-const.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/effects/trait-fn-const.rs
rename to tests/ui/traits/const-traits/effects/trait-fn-const.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/trait-fn-const.stderr b/tests/ui/traits/const-traits/effects/trait-fn-const.stderr
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/effects/trait-fn-const.stderr
rename to tests/ui/traits/const-traits/effects/trait-fn-const.stderr
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/with-without-next-solver.coherence.stderr b/tests/ui/traits/const-traits/effects/with-without-next-solver.coherence.stderr
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/effects/with-without-next-solver.coherence.stderr
rename to tests/ui/traits/const-traits/effects/with-without-next-solver.coherence.stderr
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/with-without-next-solver.rs b/tests/ui/traits/const-traits/effects/with-without-next-solver.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/effects/with-without-next-solver.rs
rename to tests/ui/traits/const-traits/effects/with-without-next-solver.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/with-without-next-solver.stock.stderr b/tests/ui/traits/const-traits/effects/with-without-next-solver.stock.stderr
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/effects/with-without-next-solver.stock.stderr
rename to tests/ui/traits/const-traits/effects/with-without-next-solver.stock.stderr
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/feature-gate.gated.stderr b/tests/ui/traits/const-traits/feature-gate.gated.stderr
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/feature-gate.gated.stderr
rename to tests/ui/traits/const-traits/feature-gate.gated.stderr
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/feature-gate.rs b/tests/ui/traits/const-traits/feature-gate.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/feature-gate.rs
rename to tests/ui/traits/const-traits/feature-gate.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/feature-gate.stock.stderr b/tests/ui/traits/const-traits/feature-gate.stock.stderr
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/feature-gate.stock.stderr
rename to tests/ui/traits/const-traits/feature-gate.stock.stderr
diff --git a/tests/ui/traits/const-traits/fn-ptr-lub.rs b/tests/ui/traits/const-traits/fn-ptr-lub.rs
new file mode 100644
index 0000000..0fc3267
--- /dev/null
+++ b/tests/ui/traits/const-traits/fn-ptr-lub.rs
@@ -0,0 +1,20 @@
+//@ compile-flags: -Znext-solver
+//@ check-pass
+
+#![feature(const_trait_impl, effects)]
+//~^ WARN the feature `effects` is incomplete
+
+const fn foo() {}
+const fn bar() {}
+fn baz() {}
+
+const fn caller(branch: bool) {
+    let mut x = if branch {
+      foo
+    } else {
+      bar
+    };
+    x = baz;
+}
+
+fn main() {}
diff --git a/tests/ui/traits/const-traits/fn-ptr-lub.stderr b/tests/ui/traits/const-traits/fn-ptr-lub.stderr
new file mode 100644
index 0000000..b333311
--- /dev/null
+++ b/tests/ui/traits/const-traits/fn-ptr-lub.stderr
@@ -0,0 +1,11 @@
+warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/fn-ptr-lub.rs:4:30
+   |
+LL | #![feature(const_trait_impl, effects)]
+   |                              ^^^^^^^
+   |
+   = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/function-pointer-does-not-require-const.rs b/tests/ui/traits/const-traits/function-pointer-does-not-require-const.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/function-pointer-does-not-require-const.rs
rename to tests/ui/traits/const-traits/function-pointer-does-not-require-const.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/gate.rs b/tests/ui/traits/const-traits/gate.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/gate.rs
rename to tests/ui/traits/const-traits/gate.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/gate.stderr b/tests/ui/traits/const-traits/gate.stderr
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/gate.stderr
rename to tests/ui/traits/const-traits/gate.stderr
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/generic-bound.rs b/tests/ui/traits/const-traits/generic-bound.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/generic-bound.rs
rename to tests/ui/traits/const-traits/generic-bound.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/generic-bound.stderr b/tests/ui/traits/const-traits/generic-bound.stderr
similarity index 87%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/generic-bound.stderr
rename to tests/ui/traits/const-traits/generic-bound.stderr
index 2baac1d..0444c31 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/generic-bound.stderr
+++ b/tests/ui/traits/const-traits/generic-bound.stderr
@@ -14,10 +14,6 @@
    |     ^^^^^^^^^
    |
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(effects)]` to the crate attributes to enable
-   |
-LL + #![feature(effects)]
-   |
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/hir-const-check.rs b/tests/ui/traits/const-traits/hir-const-check.rs
similarity index 62%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/hir-const-check.rs
rename to tests/ui/traits/const-traits/hir-const-check.rs
index f5fb0fd..0ffd606 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/hir-const-check.rs
+++ b/tests/ui/traits/const-traits/hir-const-check.rs
@@ -1,3 +1,5 @@
+//@ compile-flags: -Znext-solver
+
 // Regression test for #69615.
 
 #![feature(const_trait_impl, effects)] //~ WARN the feature `effects` is incomplete
@@ -10,6 +12,8 @@
 impl const MyTrait for () {
     fn method(&self) -> Option<()> {
         Some(())?; //~ ERROR `?` is not allowed in a `const fn`
+        //~^ ERROR `?` cannot determine the branch of `Option<()>` in constant functions
+        //~| ERROR `?` cannot convert from residual of `Option<()>` in constant functions
         None
     }
 }
diff --git a/tests/ui/traits/const-traits/hir-const-check.stderr b/tests/ui/traits/const-traits/hir-const-check.stderr
new file mode 100644
index 0000000..a22ac2c
--- /dev/null
+++ b/tests/ui/traits/const-traits/hir-const-check.stderr
@@ -0,0 +1,43 @@
+warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/hir-const-check.rs:5:30
+   |
+LL | #![feature(const_trait_impl, effects)]
+   |                              ^^^^^^^
+   |
+   = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+error[E0658]: `?` is not allowed in a `const fn`
+  --> $DIR/hir-const-check.rs:14:9
+   |
+LL |         Some(())?;
+   |         ^^^^^^^^^
+   |
+   = note: see issue #74935 <https://github.com/rust-lang/rust/issues/74935> for more information
+   = help: add `#![feature(const_try)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0015]: `?` cannot determine the branch of `Option<()>` in constant functions
+  --> $DIR/hir-const-check.rs:14:9
+   |
+LL |         Some(())?;
+   |         ^^^^^^^^^
+   |
+note: impl defined here, but it is not `const`
+  --> $SRC_DIR/core/src/option.rs:LL:COL
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error[E0015]: `?` cannot convert from residual of `Option<()>` in constant functions
+  --> $DIR/hir-const-check.rs:14:9
+   |
+LL |         Some(())?;
+   |         ^^^^^^^^^
+   |
+note: impl defined here, but it is not `const`
+  --> $SRC_DIR/core/src/option.rs:LL:COL
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error: aborting due to 3 previous errors; 1 warning emitted
+
+Some errors have detailed explanations: E0015, E0658.
+For more information about an error, try `rustc --explain E0015`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-119717-constant-lifetime.rs b/tests/ui/traits/const-traits/ice-119717-constant-lifetime.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/ice-119717-constant-lifetime.rs
rename to tests/ui/traits/const-traits/ice-119717-constant-lifetime.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-119717-constant-lifetime.stderr b/tests/ui/traits/const-traits/ice-119717-constant-lifetime.stderr
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/ice-119717-constant-lifetime.stderr
rename to tests/ui/traits/const-traits/ice-119717-constant-lifetime.stderr
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-120503-async-const-method.rs b/tests/ui/traits/const-traits/ice-120503-async-const-method.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/ice-120503-async-const-method.rs
rename to tests/ui/traits/const-traits/ice-120503-async-const-method.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-120503-async-const-method.stderr b/tests/ui/traits/const-traits/ice-120503-async-const-method.stderr
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/ice-120503-async-const-method.stderr
rename to tests/ui/traits/const-traits/ice-120503-async-const-method.stderr
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-121536-const-method.rs b/tests/ui/traits/const-traits/ice-121536-const-method.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/ice-121536-const-method.rs
rename to tests/ui/traits/const-traits/ice-121536-const-method.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-121536-const-method.stderr b/tests/ui/traits/const-traits/ice-121536-const-method.stderr
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/ice-121536-const-method.stderr
rename to tests/ui/traits/const-traits/ice-121536-const-method.stderr
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-123664-unexpected-bound-var.rs b/tests/ui/traits/const-traits/ice-123664-unexpected-bound-var.rs
similarity index 76%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/ice-123664-unexpected-bound-var.rs
rename to tests/ui/traits/const-traits/ice-123664-unexpected-bound-var.rs
index 64634e7..29f4060 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-123664-unexpected-bound-var.rs
+++ b/tests/ui/traits/const-traits/ice-123664-unexpected-bound-var.rs
@@ -3,5 +3,6 @@
 
 const fn with_positive<F: ~const Fn()>() {}
 //~^ ERROR `~const` can only be applied to `#[const_trait]` traits
+//~| ERROR `~const` can only be applied to `#[const_trait]` traits
 
 pub fn main() {}
diff --git a/tests/ui/traits/const-traits/ice-123664-unexpected-bound-var.stderr b/tests/ui/traits/const-traits/ice-123664-unexpected-bound-var.stderr
new file mode 100644
index 0000000..dcb7dd7
--- /dev/null
+++ b/tests/ui/traits/const-traits/ice-123664-unexpected-bound-var.stderr
@@ -0,0 +1,21 @@
+error: using `#![feature(effects)]` without enabling next trait solver globally
+   |
+   = note: the next trait solver must be enabled globally for the effects feature to work correctly
+   = help: use `-Znext-solver` to enable
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/ice-123664-unexpected-bound-var.rs:4:27
+   |
+LL | const fn with_positive<F: ~const Fn()>() {}
+   |                           ^^^^^^
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/ice-123664-unexpected-bound-var.rs:4:27
+   |
+LL | const fn with_positive<F: ~const Fn()>() {}
+   |                           ^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-124857-combine-effect-const-infer-vars.rs b/tests/ui/traits/const-traits/ice-124857-combine-effect-const-infer-vars.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/ice-124857-combine-effect-const-infer-vars.rs
rename to tests/ui/traits/const-traits/ice-124857-combine-effect-const-infer-vars.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-124857-combine-effect-const-infer-vars.stderr b/tests/ui/traits/const-traits/ice-124857-combine-effect-const-infer-vars.stderr
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/ice-124857-combine-effect-const-infer-vars.stderr
rename to tests/ui/traits/const-traits/ice-124857-combine-effect-const-infer-vars.stderr
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-126148-failed-to-normalize.rs b/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.rs
similarity index 79%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/ice-126148-failed-to-normalize.rs
rename to tests/ui/traits/const-traits/ice-126148-failed-to-normalize.rs
index 717c0e7..da97a0e 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-126148-failed-to-normalize.rs
+++ b/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.rs
@@ -18,6 +18,8 @@
 
 const fn t() -> TryMe {
     TryMe?;
+    //~^ ERROR `?` cannot determine the branch of `TryMe` in constant functions
+    //~| ERROR `?` cannot convert from residual of `TryMe` in constant functions
     TryMe
 }
 
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-126148-failed-to-normalize.stderr b/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.stderr
similarity index 71%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/ice-126148-failed-to-normalize.stderr
rename to tests/ui/traits/const-traits/ice-126148-failed-to-normalize.stderr
index e49436c..0ca16a1 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-126148-failed-to-normalize.stderr
+++ b/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.stderr
@@ -38,6 +38,23 @@
    = help: implement the missing item: `fn from_output(_: <Self as Try>::Output) -> Self { todo!() }`
    = help: implement the missing item: `fn branch(self) -> ControlFlow<<Self as Try>::Residual, <Self as Try>::Output> { todo!() }`
 
-error: aborting due to 5 previous errors
+error[E0015]: `?` cannot determine the branch of `TryMe` in constant functions
+  --> $DIR/ice-126148-failed-to-normalize.rs:20:5
+   |
+LL |     TryMe?;
+   |     ^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
 
-For more information about this error, try `rustc --explain E0046`.
+error[E0015]: `?` cannot convert from residual of `TryMe` in constant functions
+  --> $DIR/ice-126148-failed-to-normalize.rs:20:5
+   |
+LL |     TryMe?;
+   |     ^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error: aborting due to 7 previous errors
+
+Some errors have detailed explanations: E0015, E0046.
+For more information about an error, try `rustc --explain E0015`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/impl-tilde-const-trait.rs b/tests/ui/traits/const-traits/impl-tilde-const-trait.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/impl-tilde-const-trait.rs
rename to tests/ui/traits/const-traits/impl-tilde-const-trait.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/impl-tilde-const-trait.stderr b/tests/ui/traits/const-traits/impl-tilde-const-trait.stderr
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/impl-tilde-const-trait.stderr
rename to tests/ui/traits/const-traits/impl-tilde-const-trait.stderr
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/impl-with-default-fn-fail.rs b/tests/ui/traits/const-traits/impl-with-default-fn-fail.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/impl-with-default-fn-fail.rs
rename to tests/ui/traits/const-traits/impl-with-default-fn-fail.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/impl-with-default-fn-fail.stderr b/tests/ui/traits/const-traits/impl-with-default-fn-fail.stderr
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/impl-with-default-fn-fail.stderr
rename to tests/ui/traits/const-traits/impl-with-default-fn-fail.stderr
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/impl-with-default-fn-pass.rs b/tests/ui/traits/const-traits/impl-with-default-fn-pass.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/impl-with-default-fn-pass.rs
rename to tests/ui/traits/const-traits/impl-with-default-fn-pass.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/inherent-impl-const-bounds.rs b/tests/ui/traits/const-traits/inherent-impl-const-bounds.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/inherent-impl-const-bounds.rs
rename to tests/ui/traits/const-traits/inherent-impl-const-bounds.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/inherent-impl.rs b/tests/ui/traits/const-traits/inherent-impl.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/inherent-impl.rs
rename to tests/ui/traits/const-traits/inherent-impl.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/inherent-impl.stderr b/tests/ui/traits/const-traits/inherent-impl.stderr
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/inherent-impl.stderr
rename to tests/ui/traits/const-traits/inherent-impl.stderr
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/inline-incorrect-early-bound-in-ctfe.rs b/tests/ui/traits/const-traits/inline-incorrect-early-bound-in-ctfe.rs
similarity index 90%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/inline-incorrect-early-bound-in-ctfe.rs
rename to tests/ui/traits/const-traits/inline-incorrect-early-bound-in-ctfe.rs
index e3adcce..8638c4b 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/inline-incorrect-early-bound-in-ctfe.rs
+++ b/tests/ui/traits/const-traits/inline-incorrect-early-bound-in-ctfe.rs
@@ -25,6 +25,7 @@
 
 const fn foo() {
     ().foo();
+    //~^ ERROR cannot call non-const fn `<() as Trait>::foo` in constant functions
 }
 
 const UWU: () = foo();
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/inline-incorrect-early-bound-in-ctfe.stderr b/tests/ui/traits/const-traits/inline-incorrect-early-bound-in-ctfe.stderr
similarity index 60%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/inline-incorrect-early-bound-in-ctfe.stderr
rename to tests/ui/traits/const-traits/inline-incorrect-early-bound-in-ctfe.stderr
index 2e7801c..096b00d 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/inline-incorrect-early-bound-in-ctfe.stderr
+++ b/tests/ui/traits/const-traits/inline-incorrect-early-bound-in-ctfe.stderr
@@ -16,6 +16,15 @@
 LL |     fn foo<T>(self) {
    |            ^ found 1 type parameter
 
-error: aborting due to 1 previous error; 1 warning emitted
+error[E0015]: cannot call non-const fn `<() as Trait>::foo` in constant functions
+  --> $DIR/inline-incorrect-early-bound-in-ctfe.rs:27:8
+   |
+LL |     ().foo();
+   |        ^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
 
-For more information about this error, try `rustc --explain E0049`.
+error: aborting due to 2 previous errors; 1 warning emitted
+
+Some errors have detailed explanations: E0015, E0049.
+For more information about an error, try `rustc --explain E0015`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.rs b/tests/ui/traits/const-traits/issue-100222.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.rs
rename to tests/ui/traits/const-traits/issue-100222.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-102156.rs b/tests/ui/traits/const-traits/issue-102156.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/issue-102156.rs
rename to tests/ui/traits/const-traits/issue-102156.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-102156.stderr b/tests/ui/traits/const-traits/issue-102156.stderr
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/issue-102156.stderr
rename to tests/ui/traits/const-traits/issue-102156.stderr
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-102985.rs b/tests/ui/traits/const-traits/issue-102985.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/issue-102985.rs
rename to tests/ui/traits/const-traits/issue-102985.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-102985.stderr b/tests/ui/traits/const-traits/issue-102985.stderr
similarity index 80%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/issue-102985.stderr
rename to tests/ui/traits/const-traits/issue-102985.stderr
index 8401d1b..7c5c5ac 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-102985.stderr
+++ b/tests/ui/traits/const-traits/issue-102985.stderr
@@ -6,10 +6,6 @@
    |
    = note: closures need an RFC before allowed to be called in constants
    = note: calls in constants are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(effects)]` to the crate attributes to enable
-   |
-LL + #![feature(effects)]
-   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-103677.rs b/tests/ui/traits/const-traits/issue-103677.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/issue-103677.rs
rename to tests/ui/traits/const-traits/issue-103677.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-79450.rs b/tests/ui/traits/const-traits/issue-79450.rs
similarity index 90%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/issue-79450.rs
rename to tests/ui/traits/const-traits/issue-79450.rs
index b8b9e07..cdefebc 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-79450.rs
+++ b/tests/ui/traits/const-traits/issue-79450.rs
@@ -1,6 +1,5 @@
 //@ compile-flags: -Znext-solver
 #![allow(incomplete_features)]
-#![feature(const_fmt_arguments_new)]
 #![feature(const_trait_impl, effects)]
 
 #[const_trait]
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-79450.stderr b/tests/ui/traits/const-traits/issue-79450.stderr
similarity index 93%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/issue-79450.stderr
rename to tests/ui/traits/const-traits/issue-79450.stderr
index 9e6348d..49f380c 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-79450.stderr
+++ b/tests/ui/traits/const-traits/issue-79450.stderr
@@ -1,5 +1,5 @@
 error[E0015]: cannot call non-const fn `_print` in constant functions
-  --> $DIR/issue-79450.rs:11:9
+  --> $DIR/issue-79450.rs:10:9
    |
 LL |         println!("lul");
    |         ^^^^^^^^^^^^^^^
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-88155.rs b/tests/ui/traits/const-traits/issue-88155.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/issue-88155.rs
rename to tests/ui/traits/const-traits/issue-88155.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-88155.stderr b/tests/ui/traits/const-traits/issue-88155.stderr
similarity index 78%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/issue-88155.stderr
rename to tests/ui/traits/const-traits/issue-88155.stderr
index afe1ea3..157b542 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-88155.stderr
+++ b/tests/ui/traits/const-traits/issue-88155.stderr
@@ -5,10 +5,6 @@
    |     ^^^^^^^^^^
    |
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(effects)]` to the crate attributes to enable
-   |
-LL + #![feature(effects)]
-   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-92111.rs b/tests/ui/traits/const-traits/issue-92111.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/issue-92111.rs
rename to tests/ui/traits/const-traits/issue-92111.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-92111.stderr b/tests/ui/traits/const-traits/issue-92111.stderr
similarity index 60%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/issue-92111.stderr
rename to tests/ui/traits/const-traits/issue-92111.stderr
index ecc994a..51c6a22 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-92111.stderr
+++ b/tests/ui/traits/const-traits/issue-92111.stderr
@@ -1,8 +1,16 @@
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/issue-92111.rs:20:22
+  --> $DIR/issue-92111.rs:20:15
    |
 LL | const fn a<T: ~const Destruct>(t: T) {}
-   |                      ^^^^^^^^
+   |               ^^^^^^
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/issue-92111.rs:20:15
+   |
+LL | const fn a<T: ~const Destruct>(t: T) {}
+   |               ^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0493]: destructor of `T` cannot be evaluated at compile-time
   --> $DIR/issue-92111.rs:20:32
@@ -12,6 +20,6 @@
    |                                |
    |                                the destructor for this type cannot be evaluated in constant functions
 
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0493`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-92230-wf-super-trait-env.rs b/tests/ui/traits/const-traits/issue-92230-wf-super-trait-env.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/issue-92230-wf-super-trait-env.rs
rename to tests/ui/traits/const-traits/issue-92230-wf-super-trait-env.rs
diff --git a/tests/ui/traits/const-traits/item-bound-entailment-fails.rs b/tests/ui/traits/const-traits/item-bound-entailment-fails.rs
new file mode 100644
index 0000000..42799e3
--- /dev/null
+++ b/tests/ui/traits/const-traits/item-bound-entailment-fails.rs
@@ -0,0 +1,31 @@
+//@ compile-flags: -Znext-solver
+#![feature(const_trait_impl, effects)]
+//~^ WARN the feature `effects` is incomplete
+
+#[const_trait] trait Foo {
+    type Assoc<T>: ~const Bar
+    where
+        T: ~const Bar;
+}
+
+#[const_trait] trait Bar {}
+struct N<T>(T);
+impl<T> Bar for N<T> where T: Bar {}
+struct C<T>(T);
+impl<T> const Bar for C<T> where T: ~const Bar {}
+
+impl const Foo for u32 {
+    type Assoc<T> = N<T>
+    //~^ ERROR the trait bound `N<T>: ~const Bar` is not satisfied
+    where
+        T: ~const Bar;
+}
+
+impl const Foo for i32 {
+    type Assoc<T> = C<T>
+    //~^ ERROR the trait bound `T: ~const Bar` is not satisfied
+    where
+        T: Bar;
+}
+
+fn main() {}
diff --git a/tests/ui/traits/const-traits/item-bound-entailment-fails.stderr b/tests/ui/traits/const-traits/item-bound-entailment-fails.stderr
new file mode 100644
index 0000000..054a8ac
--- /dev/null
+++ b/tests/ui/traits/const-traits/item-bound-entailment-fails.stderr
@@ -0,0 +1,36 @@
+warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/item-bound-entailment-fails.rs:2:30
+   |
+LL | #![feature(const_trait_impl, effects)]
+   |                              ^^^^^^^
+   |
+   = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+error[E0277]: the trait bound `N<T>: ~const Bar` is not satisfied
+  --> $DIR/item-bound-entailment-fails.rs:18:21
+   |
+LL |     type Assoc<T> = N<T>
+   |                     ^^^^
+   |
+note: required by a bound in `Foo::Assoc`
+  --> $DIR/item-bound-entailment-fails.rs:6:20
+   |
+LL |     type Assoc<T>: ~const Bar
+   |                    ^^^^^^ required by this bound in `Foo::Assoc`
+
+error[E0277]: the trait bound `T: ~const Bar` is not satisfied
+  --> $DIR/item-bound-entailment-fails.rs:25:21
+   |
+LL |     type Assoc<T> = C<T>
+   |                     ^^^^
+   |
+note: required by a bound in `Foo::Assoc`
+  --> $DIR/item-bound-entailment-fails.rs:6:20
+   |
+LL |     type Assoc<T>: ~const Bar
+   |                    ^^^^^^ required by this bound in `Foo::Assoc`
+
+error: aborting due to 2 previous errors; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/const-traits/item-bound-entailment.rs b/tests/ui/traits/const-traits/item-bound-entailment.rs
new file mode 100644
index 0000000..3670eab
--- /dev/null
+++ b/tests/ui/traits/const-traits/item-bound-entailment.rs
@@ -0,0 +1,31 @@
+//@ compile-flags: -Znext-solver
+//@ check-pass
+
+#![feature(const_trait_impl, effects)]
+//~^ WARN the feature `effects` is incomplete
+
+#[const_trait] trait Foo {
+    type Assoc<T>: ~const Bar
+    where
+        T: ~const Bar;
+}
+
+#[const_trait] trait Bar {}
+struct N<T>(T);
+impl<T> Bar for N<T> where T: Bar {}
+struct C<T>(T);
+impl<T> const Bar for C<T> where T: ~const Bar {}
+
+impl Foo for u32 {
+    type Assoc<T> = N<T>
+    where
+        T: Bar;
+}
+
+impl const Foo for i32 {
+    type Assoc<T> = C<T>
+    where
+        T: ~const Bar;
+}
+
+fn main() {}
diff --git a/tests/ui/traits/const-traits/item-bound-entailment.stderr b/tests/ui/traits/const-traits/item-bound-entailment.stderr
new file mode 100644
index 0000000..b4a4ebd
--- /dev/null
+++ b/tests/ui/traits/const-traits/item-bound-entailment.stderr
@@ -0,0 +1,11 @@
+warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/item-bound-entailment.rs:4:30
+   |
+LL | #![feature(const_trait_impl, effects)]
+   |                              ^^^^^^^
+   |
+   = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/match-non-const-eq.gated.stderr b/tests/ui/traits/const-traits/match-non-const-eq.gated.stderr
similarity index 83%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/match-non-const-eq.gated.stderr
rename to tests/ui/traits/const-traits/match-non-const-eq.gated.stderr
index c7d2115..89e59e5 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/match-non-const-eq.gated.stderr
+++ b/tests/ui/traits/const-traits/match-non-const-eq.gated.stderr
@@ -6,10 +6,6 @@
    |
    = note: `str` cannot be compared in compile-time, and therefore cannot be used in `match`es
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(effects)]` to the crate attributes to enable
-   |
-LL + #![feature(effects)]
-   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/match-non-const-eq.rs b/tests/ui/traits/const-traits/match-non-const-eq.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/match-non-const-eq.rs
rename to tests/ui/traits/const-traits/match-non-const-eq.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/match-non-const-eq.gated.stderr b/tests/ui/traits/const-traits/match-non-const-eq.stock.stderr
similarity index 83%
copy from tests/ui/rfcs/rfc-2632-const-trait-impl/match-non-const-eq.gated.stderr
copy to tests/ui/traits/const-traits/match-non-const-eq.stock.stderr
index c7d2115..89e59e5 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/match-non-const-eq.gated.stderr
+++ b/tests/ui/traits/const-traits/match-non-const-eq.stock.stderr
@@ -6,10 +6,6 @@
    |
    = note: `str` cannot be compared in compile-time, and therefore cannot be used in `match`es
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(effects)]` to the crate attributes to enable
-   |
-LL + #![feature(effects)]
-   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/mbe-bare-trait-objects-const-trait-bounds.rs b/tests/ui/traits/const-traits/mbe-bare-trait-objects-const-trait-bounds.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/mbe-bare-trait-objects-const-trait-bounds.rs
rename to tests/ui/traits/const-traits/mbe-bare-trait-objects-const-trait-bounds.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/mbe-const-trait-bound-theoretical-regression.rs b/tests/ui/traits/const-traits/mbe-const-trait-bound-theoretical-regression.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/mbe-const-trait-bound-theoretical-regression.rs
rename to tests/ui/traits/const-traits/mbe-const-trait-bound-theoretical-regression.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/mbe-const-trait-bound-theoretical-regression.stderr b/tests/ui/traits/const-traits/mbe-const-trait-bound-theoretical-regression.stderr
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/mbe-const-trait-bound-theoretical-regression.stderr
rename to tests/ui/traits/const-traits/mbe-const-trait-bound-theoretical-regression.stderr
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/mbe-dyn-const-2015.rs b/tests/ui/traits/const-traits/mbe-dyn-const-2015.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/mbe-dyn-const-2015.rs
rename to tests/ui/traits/const-traits/mbe-dyn-const-2015.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/mutually-exclusive-trait-bound-modifiers.rs b/tests/ui/traits/const-traits/mutually-exclusive-trait-bound-modifiers.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/mutually-exclusive-trait-bound-modifiers.rs
rename to tests/ui/traits/const-traits/mutually-exclusive-trait-bound-modifiers.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/mutually-exclusive-trait-bound-modifiers.stderr b/tests/ui/traits/const-traits/mutually-exclusive-trait-bound-modifiers.stderr
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/mutually-exclusive-trait-bound-modifiers.stderr
rename to tests/ui/traits/const-traits/mutually-exclusive-trait-bound-modifiers.stderr
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/nested-closure.rs b/tests/ui/traits/const-traits/nested-closure.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/nested-closure.rs
rename to tests/ui/traits/const-traits/nested-closure.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/non-const-op-const-closure-non-const-outer.rs b/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/non-const-op-const-closure-non-const-outer.rs
rename to tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/non-const-op-const-closure-non-const-outer.stderr b/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.stderr
similarity index 80%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/non-const-op-const-closure-non-const-outer.stderr
rename to tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.stderr
index c362a10..97ad831 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/non-const-op-const-closure-non-const-outer.stderr
+++ b/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.stderr
@@ -5,10 +5,6 @@
    |                      ^^^^^
    |
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(effects)]` to the crate attributes to enable
-   |
-LL + #![feature(effects)]
-   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/non-const-op-in-closure-in-const.rs b/tests/ui/traits/const-traits/non-const-op-in-closure-in-const.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/non-const-op-in-closure-in-const.rs
rename to tests/ui/traits/const-traits/non-const-op-in-closure-in-const.rs
diff --git a/tests/ui/traits/const-traits/non-const-op-in-closure-in-const.stderr b/tests/ui/traits/const-traits/non-const-op-in-closure-in-const.stderr
new file mode 100644
index 0000000..837effb
--- /dev/null
+++ b/tests/ui/traits/const-traits/non-const-op-in-closure-in-const.stderr
@@ -0,0 +1,25 @@
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/non-const-op-in-closure-in-const.rs:10:44
+   |
+LL | impl<A, B> const Convert<B> for A where B: ~const From<A> {
+   |                                            ^^^^^^
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/non-const-op-in-closure-in-const.rs:10:44
+   |
+LL | impl<A, B> const Convert<B> for A where B: ~const From<A> {
+   |                                            ^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0015]: cannot call non-const fn `<B as From<A>>::from` in constant functions
+  --> $DIR/non-const-op-in-closure-in-const.rs:12:9
+   |
+LL |         B::from(self)
+   |         ^^^^^^^^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/traits/const-traits/predicate-entailment-fails.rs b/tests/ui/traits/const-traits/predicate-entailment-fails.rs
new file mode 100644
index 0000000..5d6109b
--- /dev/null
+++ b/tests/ui/traits/const-traits/predicate-entailment-fails.rs
@@ -0,0 +1,43 @@
+//@ compile-flags: -Znext-solver
+#![feature(const_trait_impl, effects)]
+//~^ WARN the feature `effects` is incomplete
+
+#[const_trait] trait Bar {}
+impl const Bar for () {}
+
+
+#[const_trait] trait TildeConst {
+    type Bar<T> where T: ~const Bar;
+
+    fn foo<T>() where T: ~const Bar;
+}
+impl TildeConst for () {
+    type Bar<T> = () where T: const Bar;
+    //~^ ERROR impl has stricter requirements than trait
+
+    fn foo<T>() where T: const Bar {}
+    //~^ ERROR impl has stricter requirements than trait
+}
+
+
+#[const_trait] trait NeverConst {
+    type Bar<T> where T: Bar;
+
+    fn foo<T>() where T: Bar;
+}
+impl NeverConst for i32 {
+    type Bar<T> = () where T: const Bar;
+    //~^ ERROR impl has stricter requirements than trait
+
+    fn foo<T>() where T: const Bar {}
+    //~^ ERROR impl has stricter requirements than trait
+}
+impl const NeverConst for u32 {
+    type Bar<T> = () where T: ~const Bar;
+    //~^ ERROR impl has stricter requirements than trait
+
+    fn foo<T>() where T: ~const Bar {}
+    //~^ ERROR impl has stricter requirements than trait
+}
+
+fn main() {}
diff --git a/tests/ui/traits/const-traits/predicate-entailment-fails.stderr b/tests/ui/traits/const-traits/predicate-entailment-fails.stderr
new file mode 100644
index 0000000..c50009e
--- /dev/null
+++ b/tests/ui/traits/const-traits/predicate-entailment-fails.stderr
@@ -0,0 +1,66 @@
+warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/predicate-entailment-fails.rs:2:30
+   |
+LL | #![feature(const_trait_impl, effects)]
+   |                              ^^^^^^^
+   |
+   = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+error[E0276]: impl has stricter requirements than trait
+  --> $DIR/predicate-entailment-fails.rs:15:31
+   |
+LL |     type Bar<T> where T: ~const Bar;
+   |     ----------- definition of `Bar` from trait
+...
+LL |     type Bar<T> = () where T: const Bar;
+   |                               ^^^^^ impl has extra requirement `T: const Bar`
+
+error[E0276]: impl has stricter requirements than trait
+  --> $DIR/predicate-entailment-fails.rs:18:26
+   |
+LL |     fn foo<T>() where T: ~const Bar;
+   |     -------------------------------- definition of `foo` from trait
+...
+LL |     fn foo<T>() where T: const Bar {}
+   |                          ^^^^^ impl has extra requirement `T: const Bar`
+
+error[E0276]: impl has stricter requirements than trait
+  --> $DIR/predicate-entailment-fails.rs:29:31
+   |
+LL |     type Bar<T> where T: Bar;
+   |     ----------- definition of `Bar` from trait
+...
+LL |     type Bar<T> = () where T: const Bar;
+   |                               ^^^^^ impl has extra requirement `T: const Bar`
+
+error[E0276]: impl has stricter requirements than trait
+  --> $DIR/predicate-entailment-fails.rs:32:26
+   |
+LL |     fn foo<T>() where T: Bar;
+   |     ------------------------- definition of `foo` from trait
+...
+LL |     fn foo<T>() where T: const Bar {}
+   |                          ^^^^^ impl has extra requirement `T: const Bar`
+
+error[E0276]: impl has stricter requirements than trait
+  --> $DIR/predicate-entailment-fails.rs:36:31
+   |
+LL |     type Bar<T> where T: Bar;
+   |     ----------- definition of `Bar` from trait
+...
+LL |     type Bar<T> = () where T: ~const Bar;
+   |                               ^^^^^^ impl has extra requirement `T: ~const Bar`
+
+error[E0276]: impl has stricter requirements than trait
+  --> $DIR/predicate-entailment-fails.rs:39:26
+   |
+LL |     fn foo<T>() where T: Bar;
+   |     ------------------------- definition of `foo` from trait
+...
+LL |     fn foo<T>() where T: ~const Bar {}
+   |                          ^^^^^^ impl has extra requirement `T: ~const Bar`
+
+error: aborting due to 6 previous errors; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0276`.
diff --git a/tests/ui/traits/const-traits/predicate-entailment-passes.rs b/tests/ui/traits/const-traits/predicate-entailment-passes.rs
new file mode 100644
index 0000000..b660329
--- /dev/null
+++ b/tests/ui/traits/const-traits/predicate-entailment-passes.rs
@@ -0,0 +1,39 @@
+//@ compile-flags: -Znext-solver
+//@ check-pass
+
+#![feature(const_trait_impl, effects)]
+//~^ WARN the feature `effects` is incomplete
+
+#[const_trait] trait Bar {}
+impl const Bar for () {}
+
+
+#[const_trait] trait TildeConst {
+    type Bar<T> where T: ~const Bar;
+
+    fn foo<T>() where T: ~const Bar;
+}
+impl TildeConst for () {
+    type Bar<T> = () where T: Bar;
+
+    fn foo<T>() where T: Bar {}
+}
+
+
+#[const_trait] trait AlwaysConst {
+    type Bar<T> where T: const Bar;
+
+    fn foo<T>() where T: const Bar;
+}
+impl AlwaysConst for i32 {
+    type Bar<T> = () where T: Bar;
+
+    fn foo<T>() where T: Bar {}
+}
+impl const AlwaysConst for u32 {
+    type Bar<T> = () where T: ~const Bar;
+
+    fn foo<T>() where T: ~const Bar {}
+}
+
+fn main() {}
diff --git a/tests/ui/traits/const-traits/predicate-entailment-passes.stderr b/tests/ui/traits/const-traits/predicate-entailment-passes.stderr
new file mode 100644
index 0000000..dcaeea7
--- /dev/null
+++ b/tests/ui/traits/const-traits/predicate-entailment-passes.stderr
@@ -0,0 +1,11 @@
+warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/predicate-entailment-passes.rs:4:30
+   |
+LL | #![feature(const_trait_impl, effects)]
+   |                              ^^^^^^^
+   |
+   = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.rs b/tests/ui/traits/const-traits/specialization/const-default-bound-non-const-specialized-bound.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.rs
rename to tests/ui/traits/const-traits/specialization/const-default-bound-non-const-specialized-bound.rs
diff --git a/tests/ui/traits/const-traits/specialization/const-default-bound-non-const-specialized-bound.stderr b/tests/ui/traits/const-traits/specialization/const-default-bound-non-const-specialized-bound.stderr
new file mode 100644
index 0000000..bffc60c
--- /dev/null
+++ b/tests/ui/traits/const-traits/specialization/const-default-bound-non-const-specialized-bound.stderr
@@ -0,0 +1,11 @@
+error: cannot specialize on const impl with non-const impl
+  --> $DIR/const-default-bound-non-const-specialized-bound.rs:28:1
+   |
+LL | / impl<T> Bar for T
+LL | | where
+LL | |     T: Foo, //FIXME ~ ERROR missing `~const` qualifier
+LL | |     T: Specialize,
+   | |__________________^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-const-specialized.rs b/tests/ui/traits/const-traits/specialization/const-default-const-specialized.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-const-specialized.rs
rename to tests/ui/traits/const-traits/specialization/const-default-const-specialized.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-88155.stderr b/tests/ui/traits/const-traits/specialization/const-default-const-specialized.stderr
similarity index 68%
copy from tests/ui/rfcs/rfc-2632-const-trait-impl/issue-88155.stderr
copy to tests/ui/traits/const-traits/specialization/const-default-const-specialized.stderr
index afe1ea3..f127268 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-88155.stderr
+++ b/tests/ui/traits/const-traits/specialization/const-default-const-specialized.stderr
@@ -1,7 +1,7 @@
-error[E0015]: cannot call non-const fn `<T as A>::assoc` in constant functions
-  --> $DIR/issue-88155.rs:10:5
+error[E0015]: cannot call non-const fn `<T as Value>::value` in constant functions
+  --> $DIR/const-default-const-specialized.rs:16:5
    |
-LL |     T::assoc()
+LL |     T::value()
    |     ^^^^^^^^^^
    |
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-impl-non-const-specialized-impl.rs b/tests/ui/traits/const-traits/specialization/const-default-impl-non-const-specialized-impl.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-impl-non-const-specialized-impl.rs
rename to tests/ui/traits/const-traits/specialization/const-default-impl-non-const-specialized-impl.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-impl-non-const-specialized-impl.stderr b/tests/ui/traits/const-traits/specialization/const-default-impl-non-const-specialized-impl.stderr
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-impl-non-const-specialized-impl.stderr
rename to tests/ui/traits/const-traits/specialization/const-default-impl-non-const-specialized-impl.stderr
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/default-keyword.rs b/tests/ui/traits/const-traits/specialization/default-keyword.rs
similarity index 79%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/default-keyword.rs
rename to tests/ui/traits/const-traits/specialization/default-keyword.rs
index d9ffd23..bc45a70 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/default-keyword.rs
+++ b/tests/ui/traits/const-traits/specialization/default-keyword.rs
@@ -1,5 +1,4 @@
-//@ known-bug: #110395
-// FIXME check-pass
+//@ check-pass
 
 #![feature(const_trait_impl)]
 #![feature(min_specialization)]
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95186-specialize-on-tilde-const.rs b/tests/ui/traits/const-traits/specialization/issue-95186-specialize-on-tilde-const.rs
similarity index 93%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95186-specialize-on-tilde-const.rs
rename to tests/ui/traits/const-traits/specialization/issue-95186-specialize-on-tilde-const.rs
index 219e5f3..d80370a 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95186-specialize-on-tilde-const.rs
+++ b/tests/ui/traits/const-traits/specialization/issue-95186-specialize-on-tilde-const.rs
@@ -1,7 +1,6 @@
 // Tests that `~const` trait bounds can be used to specialize const trait impls.
 
-//@ known-bug: #110395
-// FIXME check-pass
+//@ check-pass
 
 #![feature(const_trait_impl)]
 #![feature(rustc_attrs)]
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95187-same-trait-bound-different-constness.rs b/tests/ui/traits/const-traits/specialization/issue-95187-same-trait-bound-different-constness.rs
similarity index 94%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95187-same-trait-bound-different-constness.rs
rename to tests/ui/traits/const-traits/specialization/issue-95187-same-trait-bound-different-constness.rs
index 7514baa..d97469e 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95187-same-trait-bound-different-constness.rs
+++ b/tests/ui/traits/const-traits/specialization/issue-95187-same-trait-bound-different-constness.rs
@@ -2,8 +2,7 @@
 // `T: Foo` in the default impl for the purposes of specialization (i.e., it
 // does not think that the user is attempting to specialize on trait `Foo`).
 
-//@ known-bug: #110395
-// FIXME check-pass
+//@ check-pass
 
 #![feature(rustc_attrs)]
 #![feature(min_specialization)]
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/non-const-default-const-specialized.rs b/tests/ui/traits/const-traits/specialization/non-const-default-const-specialized.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/non-const-default-const-specialized.rs
rename to tests/ui/traits/const-traits/specialization/non-const-default-const-specialized.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-88155.stderr b/tests/ui/traits/const-traits/specialization/non-const-default-const-specialized.stderr
similarity index 68%
copy from tests/ui/rfcs/rfc-2632-const-trait-impl/issue-88155.stderr
copy to tests/ui/traits/const-traits/specialization/non-const-default-const-specialized.stderr
index afe1ea3..a4095d7 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-88155.stderr
+++ b/tests/ui/traits/const-traits/specialization/non-const-default-const-specialized.stderr
@@ -1,7 +1,7 @@
-error[E0015]: cannot call non-const fn `<T as A>::assoc` in constant functions
-  --> $DIR/issue-88155.rs:10:5
+error[E0015]: cannot call non-const fn `<T as Value>::value` in constant functions
+  --> $DIR/non-const-default-const-specialized.rs:15:5
    |
-LL |     T::assoc()
+LL |     T::value()
    |     ^^^^^^^^^^
    |
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness-2.rs b/tests/ui/traits/const-traits/specializing-constness-2.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness-2.rs
rename to tests/ui/traits/const-traits/specializing-constness-2.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-88155.stderr b/tests/ui/traits/const-traits/specializing-constness-2.stderr
similarity index 66%
copy from tests/ui/rfcs/rfc-2632-const-trait-impl/issue-88155.stderr
copy to tests/ui/traits/const-traits/specializing-constness-2.stderr
index afe1ea3..8e6f694 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-88155.stderr
+++ b/tests/ui/traits/const-traits/specializing-constness-2.stderr
@@ -1,8 +1,8 @@
-error[E0015]: cannot call non-const fn `<T as A>::assoc` in constant functions
-  --> $DIR/issue-88155.rs:10:5
+error[E0015]: cannot call non-const fn `<T as A>::a` in constant functions
+  --> $DIR/specializing-constness-2.rs:27:5
    |
-LL |     T::assoc()
-   |     ^^^^^^^^^^
+LL |     <T as A>::a();
+   |     ^^^^^^^^^^^^^
    |
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
 help: add `#![feature(effects)]` to the crate attributes to enable
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness.rs b/tests/ui/traits/const-traits/specializing-constness.rs
similarity index 89%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness.rs
rename to tests/ui/traits/const-traits/specializing-constness.rs
index 4501a21..3aabaf1 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness.rs
+++ b/tests/ui/traits/const-traits/specializing-constness.rs
@@ -22,8 +22,6 @@
 
 impl<T: Spec + Sup> A for T {
 //~^ ERROR: cannot specialize
-//~| ERROR: cannot specialize
-//~| ERROR: cannot specialize
 //FIXME(effects) ~| ERROR: missing `~const` qualifier
     fn a() -> u32 {
         3
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness.stderr b/tests/ui/traits/const-traits/specializing-constness.stderr
similarity index 69%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness.stderr
rename to tests/ui/traits/const-traits/specializing-constness.stderr
index 90721af..e8c4fb0 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness.stderr
+++ b/tests/ui/traits/const-traits/specializing-constness.stderr
@@ -18,17 +18,5 @@
 LL | impl<T: Spec + Sup> A for T {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: cannot specialize on trait `Compat`
-  --> $DIR/specializing-constness.rs:23:16
-   |
-LL | impl<T: Spec + Sup> A for T {
-   |                ^^^
-
-error: cannot specialize on trait `Compat`
-  --> $DIR/specializing-constness.rs:23:9
-   |
-LL | impl<T: Spec + Sup> A for T {
-   |         ^^^^
-
-error: aborting due to 4 previous errors; 1 warning emitted
+error: aborting due to 2 previous errors; 1 warning emitted
 
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/staged-api-user-crate.rs b/tests/ui/traits/const-traits/staged-api-user-crate.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/staged-api-user-crate.rs
rename to tests/ui/traits/const-traits/staged-api-user-crate.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/staged-api-user-crate.stderr b/tests/ui/traits/const-traits/staged-api-user-crate.stderr
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/staged-api-user-crate.stderr
rename to tests/ui/traits/const-traits/staged-api-user-crate.stderr
diff --git a/tests/ui/traits/const-traits/staged-api.rs b/tests/ui/traits/const-traits/staged-api.rs
new file mode 100644
index 0000000..59fe6d5
--- /dev/null
+++ b/tests/ui/traits/const-traits/staged-api.rs
@@ -0,0 +1,75 @@
+//@ revisions: stable unstable
+//@ compile-flags: -Znext-solver
+
+#![cfg_attr(unstable, feature(unstable))] // The feature from the ./auxiliary/staged-api.rs file.
+#![cfg_attr(unstable, feature(local_feature))]
+#![feature(const_trait_impl, effects)]
+#![allow(incomplete_features)]
+#![feature(staged_api)]
+#![stable(feature = "rust1", since = "1.0.0")]
+
+//@ aux-build: staged-api.rs
+extern crate staged_api;
+
+use staged_api::*;
+
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Foo;
+
+#[stable(feature = "rust1", since = "1.0.0")]
+#[cfg_attr(unstable, rustc_const_unstable(feature = "local_feature", issue = "none"))]
+#[cfg_attr(stable, rustc_const_stable(feature = "local_feature", since = "1.0.0"))]
+impl const MyTrait for Foo {
+    //[stable]~^ ERROR trait implementations cannot be const stable yet
+    fn func() {}
+}
+
+// Const stability has no impact on usage in non-const contexts.
+fn non_const_context() {
+    Unstable::func();
+    Foo::func();
+}
+
+#[unstable(feature = "none", issue = "none")]
+const fn const_context() {
+    Unstable::func();
+    //[unstable]~^ ERROR cannot use `#[feature(unstable)]`
+    //[stable]~^^ ERROR not yet stable as a const fn
+    Foo::func();
+    //[unstable]~^ ERROR cannot use `#[feature(local_feature)]`
+    //[stable]~^^ cannot be (indirectly) exposed to stable
+    // We get the error on `stable` since this is a trait function.
+    Unstable2::func();
+    //~^ ERROR not yet stable as a const fn
+    // ^ fails, because the `unstable2` feature is not active
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+#[cfg_attr(unstable, rustc_const_unstable(feature = "local_feature", issue = "none"))]
+pub const fn const_context_not_const_stable() {
+    //[stable]~^ ERROR function has missing const stability attribute
+    Unstable::func();
+    //[stable]~^ ERROR not yet stable as a const fn
+    Foo::func();
+    //[stable]~^ cannot be (indirectly) exposed to stable
+    // We get the error on `stable` since this is a trait function.
+    Unstable2::func();
+    //~^ ERROR not yet stable as a const fn
+    // ^ fails, because the `unstable2` feature is not active
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_stable(feature = "cheese", since = "1.0.0")]
+const fn stable_const_context() {
+    Unstable::func();
+    //[unstable]~^ ERROR cannot use `#[feature(unstable)]`
+    //[stable]~^^ ERROR not yet stable as a const fn
+    Foo::func();
+    //[unstable]~^ ERROR cannot use `#[feature(local_feature)]`
+    //[stable]~^^ cannot be (indirectly) exposed to stable
+    // We get the error on `stable` since this is a trait function.
+    const_context_not_const_stable()
+    //[unstable]~^ ERROR cannot use `#[feature(local_feature)]`
+}
+
+fn main() {}
diff --git a/tests/ui/traits/const-traits/staged-api.stable.stderr b/tests/ui/traits/const-traits/staged-api.stable.stderr
new file mode 100644
index 0000000..4004508
--- /dev/null
+++ b/tests/ui/traits/const-traits/staged-api.stable.stderr
@@ -0,0 +1,89 @@
+error: trait implementations cannot be const stable yet
+  --> $DIR/staged-api.rs:22:1
+   |
+LL | / impl const MyTrait for Foo {
+LL | |
+LL | |     fn func() {}
+LL | | }
+   | |_^
+   |
+   = note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information
+
+error: function has missing const stability attribute
+  --> $DIR/staged-api.rs:49:1
+   |
+LL | / pub const fn const_context_not_const_stable() {
+LL | |
+LL | |     Unstable::func();
+LL | |
+...  |
+LL | |     // ^ fails, because the `unstable2` feature is not active
+LL | | }
+   | |_^
+
+error: `<staged_api::Unstable as staged_api::MyTrait>::func` is not yet stable as a const fn
+  --> $DIR/staged-api.rs:35:5
+   |
+LL |     Unstable::func();
+   |     ^^^^^^^^^^^^^^^^
+   |
+   = help: add `#![feature(unstable)]` to the crate attributes to enable
+
+error: `<Foo as staged_api::MyTrait>::func` cannot be (indirectly) exposed to stable
+  --> $DIR/staged-api.rs:38:5
+   |
+LL |     Foo::func();
+   |     ^^^^^^^^^^^
+   |
+   = help: either mark the callee as `#[rustc_const_stable_indirect]`, or the caller as `#[rustc_const_unstable]`
+
+error: `<staged_api::Unstable2 as staged_api::MyTrait>::func` is not yet stable as a const fn
+  --> $DIR/staged-api.rs:42:5
+   |
+LL |     Unstable2::func();
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = help: add `#![feature(unstable2)]` to the crate attributes to enable
+
+error: `<staged_api::Unstable as staged_api::MyTrait>::func` is not yet stable as a const fn
+  --> $DIR/staged-api.rs:51:5
+   |
+LL |     Unstable::func();
+   |     ^^^^^^^^^^^^^^^^
+   |
+   = help: add `#![feature(unstable)]` to the crate attributes to enable
+
+error: `<Foo as staged_api::MyTrait>::func` cannot be (indirectly) exposed to stable
+  --> $DIR/staged-api.rs:53:5
+   |
+LL |     Foo::func();
+   |     ^^^^^^^^^^^
+   |
+   = help: either mark the callee as `#[rustc_const_stable_indirect]`, or the caller as `#[rustc_const_unstable]`
+
+error: `<staged_api::Unstable2 as staged_api::MyTrait>::func` is not yet stable as a const fn
+  --> $DIR/staged-api.rs:56:5
+   |
+LL |     Unstable2::func();
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = help: add `#![feature(unstable2)]` to the crate attributes to enable
+
+error: `<staged_api::Unstable as staged_api::MyTrait>::func` is not yet stable as a const fn
+  --> $DIR/staged-api.rs:64:5
+   |
+LL |     Unstable::func();
+   |     ^^^^^^^^^^^^^^^^
+   |
+   = help: add `#![feature(unstable)]` to the crate attributes to enable
+
+error: `<Foo as staged_api::MyTrait>::func` cannot be (indirectly) exposed to stable
+  --> $DIR/staged-api.rs:67:5
+   |
+LL |     Foo::func();
+   |     ^^^^^^^^^^^
+   |
+   = help: either mark the callee as `#[rustc_const_stable_indirect]`, or the caller as `#[rustc_const_unstable]`
+
+error: aborting due to 10 previous errors
+
diff --git a/tests/ui/traits/const-traits/staged-api.unstable.stderr b/tests/ui/traits/const-traits/staged-api.unstable.stderr
new file mode 100644
index 0000000..64b3a8a
--- /dev/null
+++ b/tests/ui/traits/const-traits/staged-api.unstable.stderr
@@ -0,0 +1,108 @@
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(unstable)]`
+  --> $DIR/staged-api.rs:35:5
+   |
+LL |     Unstable::func();
+   |     ^^^^^^^^^^^^^^^^
+   |
+   = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features
+help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do)
+   |
+LL + #[rustc_const_unstable(feature = "...", issue = "...")]
+LL | const fn const_context() {
+   |
+help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
+   |
+LL + #[rustc_allow_const_fn_unstable(unstable)]
+LL | const fn const_context() {
+   |
+
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(local_feature)]`
+  --> $DIR/staged-api.rs:38:5
+   |
+LL |     Foo::func();
+   |     ^^^^^^^^^^^
+   |
+   = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features
+help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do)
+   |
+LL + #[rustc_const_unstable(feature = "...", issue = "...")]
+LL | const fn const_context() {
+   |
+help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
+   |
+LL + #[rustc_allow_const_fn_unstable(local_feature)]
+LL | const fn const_context() {
+   |
+
+error: `<staged_api::Unstable2 as staged_api::MyTrait>::func` is not yet stable as a const fn
+  --> $DIR/staged-api.rs:42:5
+   |
+LL |     Unstable2::func();
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = help: add `#![feature(unstable2)]` to the crate attributes to enable
+
+error: `<staged_api::Unstable2 as staged_api::MyTrait>::func` is not yet stable as a const fn
+  --> $DIR/staged-api.rs:56:5
+   |
+LL |     Unstable2::func();
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = help: add `#![feature(unstable2)]` to the crate attributes to enable
+
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(unstable)]`
+  --> $DIR/staged-api.rs:64:5
+   |
+LL |     Unstable::func();
+   |     ^^^^^^^^^^^^^^^^
+   |
+   = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features
+help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do)
+   |
+LL + #[rustc_const_unstable(feature = "...", issue = "...")]
+LL | const fn stable_const_context() {
+   |
+help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
+   |
+LL + #[rustc_allow_const_fn_unstable(unstable)]
+LL | const fn stable_const_context() {
+   |
+
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(local_feature)]`
+  --> $DIR/staged-api.rs:67:5
+   |
+LL |     Foo::func();
+   |     ^^^^^^^^^^^
+   |
+   = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features
+help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do)
+   |
+LL + #[rustc_const_unstable(feature = "...", issue = "...")]
+LL | const fn stable_const_context() {
+   |
+help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
+   |
+LL + #[rustc_allow_const_fn_unstable(local_feature)]
+LL | const fn stable_const_context() {
+   |
+
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(local_feature)]`
+  --> $DIR/staged-api.rs:71:5
+   |
+LL |     const_context_not_const_stable()
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features
+help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do)
+   |
+LL + #[rustc_const_unstable(feature = "...", issue = "...")]
+LL | const fn stable_const_context() {
+   |
+help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
+   |
+LL + #[rustc_allow_const_fn_unstable(local_feature)]
+LL | const fn stable_const_context() {
+   |
+
+error: aborting due to 7 previous errors
+
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/static-const-trait-bound.rs b/tests/ui/traits/const-traits/static-const-trait-bound.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/static-const-trait-bound.rs
rename to tests/ui/traits/const-traits/static-const-trait-bound.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/std-impl-gate.gated.stderr b/tests/ui/traits/const-traits/std-impl-gate.gated.stderr
similarity index 86%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/std-impl-gate.gated.stderr
rename to tests/ui/traits/const-traits/std-impl-gate.gated.stderr
index d761fdc..f3b1713 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/std-impl-gate.gated.stderr
+++ b/tests/ui/traits/const-traits/std-impl-gate.gated.stderr
@@ -11,10 +11,6 @@
    |     ^^^^^^^^^^^^^^^^^^
    |
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(effects)]` to the crate attributes to enable
-   |
-LL + #![feature(effects)]
-   |
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/std-impl-gate.rs b/tests/ui/traits/const-traits/std-impl-gate.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/std-impl-gate.rs
rename to tests/ui/traits/const-traits/std-impl-gate.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/std-impl-gate.stock.stderr b/tests/ui/traits/const-traits/std-impl-gate.stock.stderr
similarity index 77%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/std-impl-gate.stock.stderr
rename to tests/ui/traits/const-traits/std-impl-gate.stock.stderr
index b63ea69..7240b5f 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/std-impl-gate.stock.stderr
+++ b/tests/ui/traits/const-traits/std-impl-gate.stock.stderr
@@ -5,10 +5,6 @@
    |     ^^^^^^^^^^^^^^^^^^
    |
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/traits/const-traits/super-traits-fail-2.nn.stderr b/tests/ui/traits/const-traits/super-traits-fail-2.nn.stderr
new file mode 100644
index 0000000..8de1bb0
--- /dev/null
+++ b/tests/ui/traits/const-traits/super-traits-fail-2.nn.stderr
@@ -0,0 +1,45 @@
+error: `~const` is not allowed here
+  --> $DIR/super-traits-fail-2.rs:12:12
+   |
+LL | trait Bar: ~const Foo {}
+   |            ^^^^^^
+   |
+note: this trait is not a `#[const_trait]`, so it cannot have `~const` trait bounds
+  --> $DIR/super-traits-fail-2.rs:12:1
+   |
+LL | trait Bar: ~const Foo {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/super-traits-fail-2.rs:12:12
+   |
+LL | trait Bar: ~const Foo {}
+   |            ^^^^^^
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/super-traits-fail-2.rs:12:12
+   |
+LL | trait Bar: ~const Foo {}
+   |            ^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/super-traits-fail-2.rs:12:12
+   |
+LL | trait Bar: ~const Foo {}
+   |            ^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0015]: cannot call non-const fn `<T as Foo>::a` in constant functions
+  --> $DIR/super-traits-fail-2.rs:21:7
+   |
+LL |     x.a();
+   |       ^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/traits/const-traits/super-traits-fail-2.ny.stderr b/tests/ui/traits/const-traits/super-traits-fail-2.ny.stderr
new file mode 100644
index 0000000..82b306a
--- /dev/null
+++ b/tests/ui/traits/const-traits/super-traits-fail-2.ny.stderr
@@ -0,0 +1,49 @@
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/super-traits-fail-2.rs:12:12
+   |
+LL | trait Bar: ~const Foo {}
+   |            ^^^^^^
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/super-traits-fail-2.rs:12:12
+   |
+LL | trait Bar: ~const Foo {}
+   |            ^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/super-traits-fail-2.rs:12:12
+   |
+LL | trait Bar: ~const Foo {}
+   |            ^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/super-traits-fail-2.rs:12:12
+   |
+LL | trait Bar: ~const Foo {}
+   |            ^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/super-traits-fail-2.rs:12:12
+   |
+LL | trait Bar: ~const Foo {}
+   |            ^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0015]: cannot call non-const fn `<T as Foo>::a` in constant functions
+  --> $DIR/super-traits-fail-2.rs:21:7
+   |
+LL |     x.a();
+   |       ^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.rs b/tests/ui/traits/const-traits/super-traits-fail-2.rs
similarity index 68%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.rs
rename to tests/ui/traits/const-traits/super-traits-fail-2.rs
index 93a6f38..1e41d70 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.rs
+++ b/tests/ui/traits/const-traits/super-traits-fail-2.rs
@@ -13,11 +13,14 @@
 //[ny,nn]~^ ERROR: `~const` can only be applied to `#[const_trait]`
 //[ny,nn]~| ERROR: `~const` can only be applied to `#[const_trait]`
 //[ny,nn]~| ERROR: `~const` can only be applied to `#[const_trait]`
-//[yn,nn]~^^^^ ERROR: `~const` is not allowed here
+//[ny]~| ERROR: `~const` can only be applied to `#[const_trait]`
+//[ny]~| ERROR: `~const` can only be applied to `#[const_trait]`
+//[yn,nn]~^^^^^^ ERROR: `~const` is not allowed here
 
 const fn foo<T: Bar>(x: &T) {
     x.a();
     //[yy,yn]~^ ERROR the trait bound `T: ~const Foo`
+    //[nn,ny]~^^ ERROR cannot call non-const fn `<T as Foo>::a` in constant functions
 }
 
 fn main() {}
diff --git a/tests/ui/traits/const-traits/super-traits-fail-2.yn.stderr b/tests/ui/traits/const-traits/super-traits-fail-2.yn.stderr
new file mode 100644
index 0000000..ec6ca10
--- /dev/null
+++ b/tests/ui/traits/const-traits/super-traits-fail-2.yn.stderr
@@ -0,0 +1,21 @@
+error: `~const` is not allowed here
+  --> $DIR/super-traits-fail-2.rs:12:12
+   |
+LL | trait Bar: ~const Foo {}
+   |            ^^^^^^
+   |
+note: this trait is not a `#[const_trait]`, so it cannot have `~const` trait bounds
+  --> $DIR/super-traits-fail-2.rs:12:1
+   |
+LL | trait Bar: ~const Foo {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0277]: the trait bound `T: ~const Foo` is not satisfied
+  --> $DIR/super-traits-fail-2.rs:21:5
+   |
+LL |     x.a();
+   |     ^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/const-traits/super-traits-fail-2.yy.stderr b/tests/ui/traits/const-traits/super-traits-fail-2.yy.stderr
new file mode 100644
index 0000000..3fa6256
--- /dev/null
+++ b/tests/ui/traits/const-traits/super-traits-fail-2.yy.stderr
@@ -0,0 +1,9 @@
+error[E0277]: the trait bound `T: ~const Foo` is not satisfied
+  --> $DIR/super-traits-fail-2.rs:21:5
+   |
+LL |     x.a();
+   |     ^^^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.nn.stderr b/tests/ui/traits/const-traits/super-traits-fail-3.nn.stderr
new file mode 100644
index 0000000..1dd4a2e
--- /dev/null
+++ b/tests/ui/traits/const-traits/super-traits-fail-3.nn.stderr
@@ -0,0 +1,59 @@
+error: `~const` is not allowed here
+  --> $DIR/super-traits-fail-3.rs:14:12
+   |
+LL | trait Bar: ~const Foo {}
+   |            ^^^^^^
+   |
+note: this trait is not a `#[const_trait]`, so it cannot have `~const` trait bounds
+  --> $DIR/super-traits-fail-3.rs:14:1
+   |
+LL | trait Bar: ~const Foo {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/super-traits-fail-3.rs:14:12
+   |
+LL | trait Bar: ~const Foo {}
+   |            ^^^^^^
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/super-traits-fail-3.rs:14:12
+   |
+LL | trait Bar: ~const Foo {}
+   |            ^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/super-traits-fail-3.rs:14:12
+   |
+LL | trait Bar: ~const Foo {}
+   |            ^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/super-traits-fail-3.rs:22:17
+   |
+LL | const fn foo<T: ~const Bar>(x: &T) {
+   |                 ^^^^^^
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/super-traits-fail-3.rs:22:17
+   |
+LL | const fn foo<T: ~const Bar>(x: &T) {
+   |                 ^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0015]: cannot call non-const fn `<T as Foo>::a` in constant functions
+  --> $DIR/super-traits-fail-3.rs:25:7
+   |
+LL |     x.a();
+   |       ^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error: aborting due to 7 previous errors
+
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.ny.stderr b/tests/ui/traits/const-traits/super-traits-fail-3.ny.stderr
new file mode 100644
index 0000000..e619b8b
--- /dev/null
+++ b/tests/ui/traits/const-traits/super-traits-fail-3.ny.stderr
@@ -0,0 +1,49 @@
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/super-traits-fail-3.rs:14:12
+   |
+LL | trait Bar: ~const Foo {}
+   |            ^^^^^^
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/super-traits-fail-3.rs:14:12
+   |
+LL | trait Bar: ~const Foo {}
+   |            ^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/super-traits-fail-3.rs:14:12
+   |
+LL | trait Bar: ~const Foo {}
+   |            ^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/super-traits-fail-3.rs:14:12
+   |
+LL | trait Bar: ~const Foo {}
+   |            ^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/super-traits-fail-3.rs:14:12
+   |
+LL | trait Bar: ~const Foo {}
+   |            ^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0015]: cannot call non-const fn `<T as Foo>::a` in constant functions
+  --> $DIR/super-traits-fail-3.rs:25:7
+   |
+LL |     x.a();
+   |       ^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.rs b/tests/ui/traits/const-traits/super-traits-fail-3.rs
similarity index 66%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.rs
rename to tests/ui/traits/const-traits/super-traits-fail-3.rs
index b5643b1..414337956 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.rs
+++ b/tests/ui/traits/const-traits/super-traits-fail-3.rs
@@ -15,12 +15,16 @@
 //[ny,nn]~^ ERROR: `~const` can only be applied to `#[const_trait]`
 //[ny,nn]~| ERROR: `~const` can only be applied to `#[const_trait]`
 //[ny,nn]~| ERROR: `~const` can only be applied to `#[const_trait]`
-//[yn,nn]~^^^^ ERROR: `~const` is not allowed here
+//[ny]~| ERROR: `~const` can only be applied to `#[const_trait]`
+//[ny]~| ERROR: `~const` can only be applied to `#[const_trait]`
+//[yn,nn]~^^^^^^ ERROR: `~const` is not allowed here
 
 const fn foo<T: ~const Bar>(x: &T) {
     //[yn,nn]~^ ERROR: `~const` can only be applied to `#[const_trait]`
+    //[yn,nn]~| ERROR: `~const` can only be applied to `#[const_trait]`
     x.a();
     //[yn]~^ ERROR: the trait bound `T: ~const Foo` is not satisfied
+    //[nn,ny]~^^ ERROR: cannot call non-const fn `<T as Foo>::a` in constant functions
 }
 
 fn main() {}
diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.yn.stderr b/tests/ui/traits/const-traits/super-traits-fail-3.yn.stderr
new file mode 100644
index 0000000..0a36d40
--- /dev/null
+++ b/tests/ui/traits/const-traits/super-traits-fail-3.yn.stderr
@@ -0,0 +1,35 @@
+error: `~const` is not allowed here
+  --> $DIR/super-traits-fail-3.rs:14:12
+   |
+LL | trait Bar: ~const Foo {}
+   |            ^^^^^^
+   |
+note: this trait is not a `#[const_trait]`, so it cannot have `~const` trait bounds
+  --> $DIR/super-traits-fail-3.rs:14:1
+   |
+LL | trait Bar: ~const Foo {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/super-traits-fail-3.rs:22:17
+   |
+LL | const fn foo<T: ~const Bar>(x: &T) {
+   |                 ^^^^^^
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/super-traits-fail-3.rs:22:17
+   |
+LL | const fn foo<T: ~const Bar>(x: &T) {
+   |                 ^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0277]: the trait bound `T: ~const Foo` is not satisfied
+  --> $DIR/super-traits-fail-3.rs:25:5
+   |
+LL |     x.a();
+   |     ^^^^^
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail.rs b/tests/ui/traits/const-traits/super-traits-fail.rs
similarity index 91%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail.rs
rename to tests/ui/traits/const-traits/super-traits-fail.rs
index da41d7f..c07619f 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail.rs
+++ b/tests/ui/traits/const-traits/super-traits-fail.rs
@@ -1,4 +1,3 @@
-//~ ERROR the trait bound
 //@ compile-flags: -Znext-solver
 
 #![allow(incomplete_features)]
diff --git a/tests/ui/traits/const-traits/super-traits-fail.stderr b/tests/ui/traits/const-traits/super-traits-fail.stderr
new file mode 100644
index 0000000..7a734a6
--- /dev/null
+++ b/tests/ui/traits/const-traits/super-traits-fail.stderr
@@ -0,0 +1,9 @@
+error[E0277]: the trait bound `S: ~const Foo` is not satisfied
+  --> $DIR/super-traits-fail.rs:18:20
+   |
+LL | impl const Bar for S {}
+   |                    ^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits.rs b/tests/ui/traits/const-traits/super-traits.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits.rs
rename to tests/ui/traits/const-traits/super-traits.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/syntax.rs b/tests/ui/traits/const-traits/syntax.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/syntax.rs
rename to tests/ui/traits/const-traits/syntax.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-and-const-params.rs b/tests/ui/traits/const-traits/tilde-const-and-const-params.rs
similarity index 90%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-and-const-params.rs
rename to tests/ui/traits/const-traits/tilde-const-and-const-params.rs
index 4b720b5..f6a7c7c 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-and-const-params.rs
+++ b/tests/ui/traits/const-traits/tilde-const-and-const-params.rs
@@ -8,7 +8,6 @@
 impl<const N: usize> Foo<N> {
     fn add<A: ~const Add42>(self) -> Foo<{ A::add(N) }> {
         //~^ ERROR `~const` is not allowed here
-        //~| ERROR mismatched types
         Foo
     }
 }
@@ -26,7 +25,6 @@
 
 fn bar<A: ~const Add42, const N: usize>(_: Foo<N>) -> Foo<{ A::add(N) }> {
     //~^ ERROR `~const` is not allowed here
-    //~| ERROR mismatched types
     Foo
 }
 
diff --git a/tests/ui/traits/const-traits/tilde-const-and-const-params.stderr b/tests/ui/traits/const-traits/tilde-const-and-const-params.stderr
new file mode 100644
index 0000000..84a425f
--- /dev/null
+++ b/tests/ui/traits/const-traits/tilde-const-and-const-params.stderr
@@ -0,0 +1,31 @@
+error: `~const` is not allowed here
+  --> $DIR/tilde-const-and-const-params.rs:9:15
+   |
+LL |     fn add<A: ~const Add42>(self) -> Foo<{ A::add(N) }> {
+   |               ^^^^^^
+   |
+note: this function is not `const`, so it cannot have `~const` trait bounds
+  --> $DIR/tilde-const-and-const-params.rs:9:8
+   |
+LL |     fn add<A: ~const Add42>(self) -> Foo<{ A::add(N) }> {
+   |        ^^^
+
+error: `~const` is not allowed here
+  --> $DIR/tilde-const-and-const-params.rs:26:11
+   |
+LL | fn bar<A: ~const Add42, const N: usize>(_: Foo<N>) -> Foo<{ A::add(N) }> {
+   |           ^^^^^^
+   |
+note: this function is not `const`, so it cannot have `~const` trait bounds
+  --> $DIR/tilde-const-and-const-params.rs:26:4
+   |
+LL | fn bar<A: ~const Add42, const N: usize>(_: Foo<N>) -> Foo<{ A::add(N) }> {
+   |    ^^^
+
+error: using `#![feature(effects)]` without enabling next trait solver globally
+   |
+   = note: the next trait solver must be enabled globally for the effects feature to work correctly
+   = help: use `-Znext-solver` to enable
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-assoc-fn-in-trait-impl.rs b/tests/ui/traits/const-traits/tilde-const-assoc-fn-in-trait-impl.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-assoc-fn-in-trait-impl.rs
rename to tests/ui/traits/const-traits/tilde-const-assoc-fn-in-trait-impl.rs
diff --git a/tests/ui/traits/const-traits/tilde-const-in-struct-args.rs b/tests/ui/traits/const-traits/tilde-const-in-struct-args.rs
new file mode 100644
index 0000000..4722be9
--- /dev/null
+++ b/tests/ui/traits/const-traits/tilde-const-in-struct-args.rs
@@ -0,0 +1,21 @@
+//@ compile-flags: -Znext-solver
+//@ known-bug: #132067
+//@ check-pass
+
+#![feature(const_trait_impl, effects)]
+
+struct S;
+#[const_trait]
+trait Trait<const N: u32> {}
+
+const fn f<
+    T: Trait<
+        {
+            struct I<U: ~const Trait<0>>(U);
+            0
+        },
+    >,
+>() {
+}
+
+pub fn main() {}
diff --git a/tests/ui/traits/const-traits/tilde-const-in-struct-args.stderr b/tests/ui/traits/const-traits/tilde-const-in-struct-args.stderr
new file mode 100644
index 0000000..a9759f1
--- /dev/null
+++ b/tests/ui/traits/const-traits/tilde-const-in-struct-args.stderr
@@ -0,0 +1,11 @@
+warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/tilde-const-in-struct-args.rs:5:30
+   |
+LL | #![feature(const_trait_impl, effects)]
+   |                              ^^^^^^^
+   |
+   = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-inherent-assoc-const-fn.rs b/tests/ui/traits/const-traits/tilde-const-inherent-assoc-const-fn.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-inherent-assoc-const-fn.rs
rename to tests/ui/traits/const-traits/tilde-const-inherent-assoc-const-fn.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-invalid-places.rs b/tests/ui/traits/const-traits/tilde-const-invalid-places.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-invalid-places.rs
rename to tests/ui/traits/const-traits/tilde-const-invalid-places.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-invalid-places.stderr b/tests/ui/traits/const-traits/tilde-const-invalid-places.stderr
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-invalid-places.stderr
rename to tests/ui/traits/const-traits/tilde-const-invalid-places.stderr
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-syntax.rs b/tests/ui/traits/const-traits/tilde-const-syntax.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-syntax.rs
rename to tests/ui/traits/const-traits/tilde-const-syntax.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-trait-assoc-tys.rs b/tests/ui/traits/const-traits/tilde-const-trait-assoc-tys.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-trait-assoc-tys.rs
rename to tests/ui/traits/const-traits/tilde-const-trait-assoc-tys.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-twice.rs b/tests/ui/traits/const-traits/tilde-twice.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-twice.rs
rename to tests/ui/traits/const-traits/tilde-twice.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-twice.stderr b/tests/ui/traits/const-traits/tilde-twice.stderr
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-twice.stderr
rename to tests/ui/traits/const-traits/tilde-twice.stderr
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-default-body-stability.rs b/tests/ui/traits/const-traits/trait-default-body-stability.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/trait-default-body-stability.rs
rename to tests/ui/traits/const-traits/trait-default-body-stability.rs
diff --git a/tests/ui/traits/const-traits/trait-default-body-stability.stderr b/tests/ui/traits/const-traits/trait-default-body-stability.stderr
new file mode 100644
index 0000000..5806b6d
--- /dev/null
+++ b/tests/ui/traits/const-traits/trait-default-body-stability.stderr
@@ -0,0 +1,37 @@
+error: const `impl` for trait `Try` which is not marked with `#[const_trait]`
+  --> $DIR/trait-default-body-stability.rs:19:12
+   |
+LL | impl const Try for T {
+   |            ^^^
+   |
+   = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const`
+   = note: adding a non-const method body in the future would be a breaking change
+
+error: const `impl` for trait `FromResidual` which is not marked with `#[const_trait]`
+  --> $DIR/trait-default-body-stability.rs:34:12
+   |
+LL | impl const FromResidual for T {
+   |            ^^^^^^^^^^^^
+   |
+   = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const`
+   = note: adding a non-const method body in the future would be a breaking change
+
+error[E0015]: `?` cannot determine the branch of `T` in constant functions
+  --> $DIR/trait-default-body-stability.rs:45:9
+   |
+LL |         T?
+   |         ^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error[E0015]: `?` cannot convert from residual of `T` in constant functions
+  --> $DIR/trait-default-body-stability.rs:45:9
+   |
+LL |         T?
+   |         ^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-method-ptr-in-consts-ice.rs b/tests/ui/traits/const-traits/trait-method-ptr-in-consts-ice.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/trait-method-ptr-in-consts-ice.rs
rename to tests/ui/traits/const-traits/trait-method-ptr-in-consts-ice.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-const.rs b/tests/ui/traits/const-traits/trait-where-clause-const.rs
similarity index 83%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-const.rs
rename to tests/ui/traits/const-traits/trait-where-clause-const.rs
index 8ca9b7c..61e2bc3 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-const.rs
+++ b/tests/ui/traits/const-traits/trait-where-clause-const.rs
@@ -20,11 +20,9 @@
 const fn test1<T: ~const Foo + Bar>() {
     T::a();
     T::b();
-    //~^ ERROR mismatched types
-    //~| ERROR the trait bound
+    //~^ ERROR the trait bound
     T::c::<T>();
-    //~^ ERROR mismatched types
-    //~| ERROR the trait bound
+    //~^ ERROR the trait bound
 }
 
 const fn test2<T: ~const Foo + ~const Bar>() {
diff --git a/tests/ui/traits/const-traits/trait-where-clause-const.stderr b/tests/ui/traits/const-traits/trait-where-clause-const.stderr
new file mode 100644
index 0000000..30a7ef1
--- /dev/null
+++ b/tests/ui/traits/const-traits/trait-where-clause-const.stderr
@@ -0,0 +1,15 @@
+error[E0277]: the trait bound `T: ~const Bar` is not satisfied
+  --> $DIR/trait-where-clause-const.rs:22:5
+   |
+LL |     T::b();
+   |     ^^^^^^
+
+error[E0277]: the trait bound `T: ~const Bar` is not satisfied
+  --> $DIR/trait-where-clause-const.rs:24:5
+   |
+LL |     T::c::<T>();
+   |     ^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-run.rs b/tests/ui/traits/const-traits/trait-where-clause-run.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-run.rs
rename to tests/ui/traits/const-traits/trait-where-clause-run.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-self-referential.rs b/tests/ui/traits/const-traits/trait-where-clause-self-referential.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-self-referential.rs
rename to tests/ui/traits/const-traits/trait-where-clause-self-referential.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause.rs b/tests/ui/traits/const-traits/trait-where-clause.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause.rs
rename to tests/ui/traits/const-traits/trait-where-clause.rs
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause.stderr b/tests/ui/traits/const-traits/trait-where-clause.stderr
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause.stderr
rename to tests/ui/traits/const-traits/trait-where-clause.stderr
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/unsatisfied-const-trait-bound.rs b/tests/ui/traits/const-traits/unsatisfied-const-trait-bound.rs
similarity index 100%
rename from tests/ui/rfcs/rfc-2632-const-trait-impl/unsatisfied-const-trait-bound.rs
rename to tests/ui/traits/const-traits/unsatisfied-const-trait-bound.rs
diff --git a/tests/ui/traits/const-traits/unsatisfied-const-trait-bound.stderr b/tests/ui/traits/const-traits/unsatisfied-const-trait-bound.stderr
new file mode 100644
index 0000000..35f3019
--- /dev/null
+++ b/tests/ui/traits/const-traits/unsatisfied-const-trait-bound.stderr
@@ -0,0 +1,35 @@
+error: `-Znext-solver=globally` and `generic_const_exprs` are incompatible, using them at the same time is not allowed
+  --> $DIR/unsatisfied-const-trait-bound.rs:5:39
+   |
+LL | #![feature(const_trait_impl, effects, generic_const_exprs)]
+   |                                       ^^^^^^^^^^^^^^^^^^^
+   |
+   = help: remove one of these features
+
+error[E0277]: the trait bound `T: const Trait` is not satisfied
+  --> $DIR/unsatisfied-const-trait-bound.rs:29:37
+   |
+LL | fn accept0<T: Trait>(_: Container<{ T::make() }>) {}
+   |                                     ^^^^^^^^^
+
+error[E0277]: the trait bound `T: const Trait` is not satisfied
+  --> $DIR/unsatisfied-const-trait-bound.rs:33:50
+   |
+LL | const fn accept1<T: ~const Trait>(_: Container<{ T::make() }>) {}
+   |                                                  ^^^^^^^^^
+
+error[E0277]: the trait bound `Ty: const Trait` is not satisfied
+  --> $DIR/unsatisfied-const-trait-bound.rs:22:5
+   |
+LL |     require::<Ty>();
+   |     ^^^^^^^^^^^^^^^
+   |
+note: required by a bound in `require`
+  --> $DIR/unsatisfied-const-trait-bound.rs:8:15
+   |
+LL | fn require<T: const Trait>() {}
+   |               ^^^^^ required by this bound in `require`
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/error-reporting/apit-with-bad-path.rs b/tests/ui/traits/error-reporting/apit-with-bad-path.rs
new file mode 100644
index 0000000..57184b9
--- /dev/null
+++ b/tests/ui/traits/error-reporting/apit-with-bad-path.rs
@@ -0,0 +1,10 @@
+// Ensure that we don't emit an E0270 for "`impl AsRef<Path>: AsRef<Path>` not satisfied".
+
+fn foo(filename: impl AsRef<Path>) {
+    //~^ ERROR cannot find type `Path` in this scope
+    std::fs::write(filename, "hello").unwrap();
+}
+
+fn main() {
+    foo("/tmp/hello");
+}
diff --git a/tests/ui/traits/error-reporting/apit-with-bad-path.stderr b/tests/ui/traits/error-reporting/apit-with-bad-path.stderr
new file mode 100644
index 0000000..19bd5e7
--- /dev/null
+++ b/tests/ui/traits/error-reporting/apit-with-bad-path.stderr
@@ -0,0 +1,14 @@
+error[E0412]: cannot find type `Path` in this scope
+  --> $DIR/apit-with-bad-path.rs:3:29
+   |
+LL | fn foo(filename: impl AsRef<Path>) {
+   |                             ^^^^ not found in this scope
+   |
+help: consider importing this struct
+   |
+LL + use std::path::Path;
+   |
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0412`.
diff --git a/tests/ui/traits/error-reporting/where-clause-with-bad-path.rs b/tests/ui/traits/error-reporting/where-clause-with-bad-path.rs
new file mode 100644
index 0000000..cbe1488
--- /dev/null
+++ b/tests/ui/traits/error-reporting/where-clause-with-bad-path.rs
@@ -0,0 +1,10 @@
+// Ensure that we don't emit an E0270 for "`impl AsRef<Path>: AsRef<Path>` not satisfied".
+
+fn foo<T: AsRef<Path>>(filename: T) {
+    //~^ ERROR cannot find type `Path` in this scope
+    std::fs::write(filename, "hello").unwrap();
+}
+
+fn main() {
+    foo("/tmp/hello");
+}
diff --git a/tests/ui/traits/error-reporting/where-clause-with-bad-path.stderr b/tests/ui/traits/error-reporting/where-clause-with-bad-path.stderr
new file mode 100644
index 0000000..1137178
--- /dev/null
+++ b/tests/ui/traits/error-reporting/where-clause-with-bad-path.stderr
@@ -0,0 +1,14 @@
+error[E0412]: cannot find type `Path` in this scope
+  --> $DIR/where-clause-with-bad-path.rs:3:17
+   |
+LL | fn foo<T: AsRef<Path>>(filename: T) {
+   |                 ^^^^ not found in this scope
+   |
+help: consider importing this struct
+   |
+LL + use std::path::Path;
+   |
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0412`.
diff --git a/tests/ui/traits/next-solver/diagnostics/deeply-normalize-type-expectation.rs b/tests/ui/traits/next-solver/diagnostics/deeply-normalize-type-expectation.rs
new file mode 100644
index 0000000..5c53b74
--- /dev/null
+++ b/tests/ui/traits/next-solver/diagnostics/deeply-normalize-type-expectation.rs
@@ -0,0 +1,17 @@
+//@ compile-flags: -Znext-solver
+
+// Make sure we try to mention a deeply normalized type in a type mismatch error.
+
+trait Mirror {
+    type Assoc;
+}
+impl<T> Mirror for T {
+    type Assoc = T;
+}
+
+fn needs<T>(_: <T as Mirror>::Assoc) {}
+
+fn main() {
+    needs::<i32>(());
+    //~^ ERROR mismatched types
+}
diff --git a/tests/ui/traits/next-solver/diagnostics/deeply-normalize-type-expectation.stderr b/tests/ui/traits/next-solver/diagnostics/deeply-normalize-type-expectation.stderr
new file mode 100644
index 0000000..8864394
--- /dev/null
+++ b/tests/ui/traits/next-solver/diagnostics/deeply-normalize-type-expectation.stderr
@@ -0,0 +1,17 @@
+error[E0308]: mismatched types
+  --> $DIR/deeply-normalize-type-expectation.rs:15:18
+   |
+LL |     needs::<i32>(());
+   |     ------------ ^^ expected `i32`, found `()`
+   |     |
+   |     arguments to this function are incorrect
+   |
+note: function defined here
+  --> $DIR/deeply-normalize-type-expectation.rs:12:4
+   |
+LL | fn needs<T>(_: <T as Mirror>::Assoc) {}
+   |    ^^^^^    -----------------------
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/typeck/typeck_type_placeholder_item.stderr b/tests/ui/typeck/typeck_type_placeholder_item.stderr
index 8a765c2..5e32d5c 100644
--- a/tests/ui/typeck/typeck_type_placeholder_item.stderr
+++ b/tests/ui/typeck/typeck_type_placeholder_item.stderr
@@ -675,10 +675,6 @@
    |                      ^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: calls in constants are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
 
 error[E0015]: cannot call non-const fn `<Filter<std::ops::Range<i32>, {closure@$DIR/typeck_type_placeholder_item.rs:230:29: 230:32}> as Iterator>::map::<i32, {closure@$DIR/typeck_type_placeholder_item.rs:230:49: 230:52}>` in constants
   --> $DIR/typeck_type_placeholder_item.rs:230:45
@@ -687,10 +683,6 @@
    |                                             ^^^^^^^^^^^^^^
    |
    = note: calls in constants are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
 
 error: aborting due to 74 previous errors
 
diff --git a/tests/ui/unpretty/extern-static.rs b/tests/ui/unpretty/extern-static.rs
new file mode 100644
index 0000000..fbd605b
--- /dev/null
+++ b/tests/ui/unpretty/extern-static.rs
@@ -0,0 +1,6 @@
+//@ compile-flags: -Zunpretty=normal
+//@ check-pass
+
+unsafe extern "C" {
+    pub unsafe static STATIC: ();
+}
diff --git a/tests/ui/unpretty/extern-static.stdout b/tests/ui/unpretty/extern-static.stdout
new file mode 100644
index 0000000..fbd605b
--- /dev/null
+++ b/tests/ui/unpretty/extern-static.stdout
@@ -0,0 +1,6 @@
+//@ compile-flags: -Zunpretty=normal
+//@ check-pass
+
+unsafe extern "C" {
+    pub unsafe static STATIC: ();
+}
diff --git a/tests/ui/unpretty/unsafe-attr.rs b/tests/ui/unpretty/unsafe-attr.rs
new file mode 100644
index 0000000..8734ea8
--- /dev/null
+++ b/tests/ui/unpretty/unsafe-attr.rs
@@ -0,0 +1,11 @@
+//@ compile-flags: -Zunpretty=normal
+//@ check-pass
+
+#[no_mangle]
+extern "C" fn foo() {}
+
+#[unsafe(no_mangle)]
+extern "C" fn bar() {}
+
+#[cfg_attr(FALSE, unsafe(no_mangle))]
+extern "C" fn zoo() {}
diff --git a/tests/ui/unpretty/unsafe-attr.stdout b/tests/ui/unpretty/unsafe-attr.stdout
new file mode 100644
index 0000000..8734ea8
--- /dev/null
+++ b/tests/ui/unpretty/unsafe-attr.stdout
@@ -0,0 +1,11 @@
+//@ compile-flags: -Zunpretty=normal
+//@ check-pass
+
+#[no_mangle]
+extern "C" fn foo() {}
+
+#[unsafe(no_mangle)]
+extern "C" fn bar() {}
+
+#[cfg_attr(FALSE, unsafe(no_mangle))]
+extern "C" fn zoo() {}
diff --git a/tests/ui/unsafe/place-expr-safe.rs b/tests/ui/unsafe/place-expr-safe.rs
new file mode 100644
index 0000000..2590ea7
--- /dev/null
+++ b/tests/ui/unsafe/place-expr-safe.rs
@@ -0,0 +1,14 @@
+//@ check-pass
+
+fn main() {
+    let ptr = std::ptr::null_mut::<i32>();
+    let addr = &raw const *ptr;
+
+    let local = 1;
+    let ptr = &local as *const i32;
+    let addr = &raw const *ptr;
+
+    let boxed = Box::new(1);
+    let ptr = &*boxed as *const i32;
+    let addr = &raw const *ptr;
+}
diff --git a/tests/ui/wf/wf-dyn-incompat-trait-obj-match.rs b/tests/ui/wf/wf-dyn-incompat-trait-obj-match.rs
index 07e9053..6eba6b7 100644
--- a/tests/ui/wf/wf-dyn-incompat-trait-obj-match.rs
+++ b/tests/ui/wf/wf-dyn-incompat-trait-obj-match.rs
@@ -22,8 +22,8 @@
         Some(()) => &S,
         None => &R,  //~ ERROR E0308
     }
-    let t: &dyn Trait = match opt() { //~ ERROR E0038
+    let t: &dyn Trait = match opt() {
         Some(()) => &S, //~ ERROR E0038
-        None => &R,
+        None => &R, //~ ERROR E0038
     };
 }
diff --git a/tests/ui/wf/wf-dyn-incompat-trait-obj-match.stderr b/tests/ui/wf/wf-dyn-incompat-trait-obj-match.stderr
index d7366e1..6cd4ebf 100644
--- a/tests/ui/wf/wf-dyn-incompat-trait-obj-match.stderr
+++ b/tests/ui/wf/wf-dyn-incompat-trait-obj-match.stderr
@@ -31,14 +31,10 @@
    = note: required for the cast from `&S` to `&dyn Trait`
 
 error[E0038]: the trait `Trait` cannot be made into an object
-  --> $DIR/wf-dyn-incompat-trait-obj-match.rs:25:25
+  --> $DIR/wf-dyn-incompat-trait-obj-match.rs:27:17
    |
-LL |       let t: &dyn Trait = match opt() {
-   |  _________________________^
-LL | |         Some(()) => &S,
-LL | |         None => &R,
-LL | |     };
-   | |_____^ `Trait` cannot be made into an object
+LL |         None => &R,
+   |                 ^^ `Trait` cannot be made into an object
    |
 note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/wf-dyn-incompat-trait-obj-match.rs:6:14
diff --git a/triagebot.toml b/triagebot.toml
index 74caa03..2e8851e 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -135,6 +135,43 @@
 """
 label = "O-rfl"
 
+[ping.wasm]
+alias = ["webassembly"]
+message = """\
+Hey WASM notification group! This issue or PR could use some WebAssembly-specific
+guidance. Could one of you weigh in? Thanks <3
+
+(In case it's useful, here are some [instructions] for tackling these sorts of
+issues).
+
+[instructions]: https://rustc-dev-guide.rust-lang.org/notification-groups/wasm.html
+"""
+label = "O-wasm"
+
+[ping.wasi]
+message = """\
+Hey WASI notification group! This issue or PR could use some WASI-specific guidance.
+Could one of you weigh in? Thanks <3
+
+(In case it's useful, here are some [instructions] for tackling these sorts of
+issues).
+
+[instructions]: https://rustc-dev-guide.rust-lang.org/notification-groups/wasi.html
+"""
+label = "O-wasi"
+
+[ping.emscripten]
+message = """\
+Hey Emscripten notification group! This issue or PR could use some Emscripten-specific
+guidance. Could one of you weigh in? Thanks <3
+
+(In case it's useful, here are some [instructions] for tackling these sorts of
+issues).
+
+[instructions]: https://rustc-dev-guide.rust-lang.org/notification-groups/emscripten.html
+"""
+label = "O-emscripten"
+
 [prioritize]
 label = "I-prioritize"
 
@@ -1081,7 +1118,7 @@
 project-stable-mir = [
     "@celinval",
     "@oli-obk",
-    "@ouz-a",
+    "@scottmcm",
 ]
 
 project-exploit-mitigations = [