about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_ast/src/ast.rs6
-rw-r--r--compiler/rustc_ast/src/attr/mod.rs2
-rw-r--r--compiler/rustc_ast/src/mut_visit.rs8
-rw-r--r--compiler/rustc_ast/src/util/comments.rs4
-rw-r--r--compiler/rustc_const_eval/src/const_eval/error.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs8
-rw-r--r--compiler/rustc_hir_typeck/src/intrinsicck.rs2
-rw-r--r--compiler/rustc_lint/messages.ftl5
-rw-r--r--compiler/rustc_lint/src/builtin.rs87
-rw-r--r--compiler/rustc_lint/src/lib.rs1
-rw-r--r--compiler/rustc_lint/src/lints.rs18
-rw-r--r--compiler/rustc_middle/messages.ftl3
-rw-r--r--compiler/rustc_middle/src/error.rs3
-rw-r--r--compiler/rustc_middle/src/ty/layout.rs14
-rw-r--r--compiler/rustc_transmute/src/layout/tree.rs1
-rw-r--r--compiler/rustc_ty_utils/src/layout.rs69
-rw-r--r--library/core/src/sync/atomic.rs26
-rw-r--r--library/std/src/io/mod.rs258
-rw-r--r--library/std/src/io/pipe.rs260
-rw-r--r--library/std/src/io/pipe/tests.rs18
-rw-r--r--library/std/src/io/tests.rs17
-rw-r--r--src/bootstrap/src/bin/main.rs32
-rw-r--r--src/bootstrap/src/core/config/config.rs47
-rw-r--r--src/bootstrap/src/core/config/flags.rs6
-rw-r--r--src/bootstrap/src/lib.rs40
-rw-r--r--src/doc/rustc-dev-guide/src/building/bootstrapping/debugging-bootstrap.md90
-rw-r--r--src/doc/rustc-dev-guide/src/building/bootstrapping/debugging-bootstrap/tracing-output-example.pngbin140711 -> 0 bytes
-rw-r--r--src/librustdoc/html/templates/type_layout.html16
-rwxr-xr-xsrc/tools/clippy/.github/driver.sh6
-rw-r--r--src/tools/clippy/book/src/usage.md9
-rw-r--r--src/tools/clippy/clippy_dev/src/new_lint.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/declared_lints.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/deprecated_lints.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/misc_early/double_neg.rs18
-rw-r--r--src/tools/clippy/clippy_lints/src/misc_early/mod.rs22
-rw-r--r--src/tools/clippy/tests/ui/double_neg.rs10
-rw-r--r--src/tools/clippy/tests/ui/double_neg.stderr11
-rw-r--r--src/tools/clippy/tests/ui/rename.fixed15
-rw-r--r--src/tools/clippy/tests/ui/rename.rs15
-rw-r--r--src/tools/clippy/tests/ui/rename.stderr126
-rw-r--r--tests/crashes/108428.rs6
-rw-r--r--tests/crashes/132826.rs10
-rw-r--r--tests/crashes/135020.rs11
-rw-r--r--tests/rustdoc/type-layout.rs9
-rw-r--r--tests/ui/enum-discriminant/eval-error.rs2
-rw-r--r--tests/ui/enum-discriminant/eval-error.stderr12
-rw-r--r--tests/ui/infinite/infinite-instantiation-struct-tail-ice-114484.rs2
-rw-r--r--tests/ui/layout/base-layout-is-sized-ice-123078.rs1
-rw-r--r--tests/ui/layout/base-layout-is-sized-ice-123078.stderr14
-rw-r--r--tests/ui/layout/invalid-unsized-const-eval.rs1
-rw-r--r--tests/ui/layout/invalid-unsized-const-eval.stderr11
-rw-r--r--tests/ui/layout/invalid-unsized-in-always-sized-tail.stderr18
-rw-r--r--tests/ui/layout/issue-unsized-tail-restatic-ice-122488.rs1
-rw-r--r--tests/ui/layout/issue-unsized-tail-restatic-ice-122488.stderr11
-rw-r--r--tests/ui/layout/uncomputable-due-to-trivial-bounds-ice-135138.rs11
-rw-r--r--tests/ui/layout/uncomputable-due-to-trivial-bounds-ice-135138.stderr9
-rw-r--r--tests/ui/layout/unexpected-unsized-field-issue-135020.rs7
-rw-r--r--tests/ui/layout/unknown-when-no-type-parameter.rs14
-rw-r--r--tests/ui/layout/unknown-when-no-type-parameter.stderr16
-rw-r--r--tests/ui/layout/unknown-when-ptr-metadata-is-DST.rs12
-rw-r--r--tests/ui/layout/unknown-when-ptr-metadata-is-DST.stderr9
-rw-r--r--tests/ui/lint/lint-double-negations.rs9
-rw-r--r--tests/ui/lint/lint-double-negations.stderr42
-rw-r--r--tests/ui/lint/lint-type-overflow2.rs1
-rw-r--r--tests/ui/lint/lint-type-overflow2.stderr24
-rw-r--r--tests/ui/structs/ice-struct-tail-normalization-113272.rs2
-rw-r--r--triagebot.toml3
67 files changed, 974 insertions, 576 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 727fd59c6b3..ad942e9b494 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -100,7 +100,7 @@ pub struct Path {
 impl PartialEq<Symbol> for Path {
     #[inline]
     fn eq(&self, symbol: &Symbol) -> bool {
-        self.segments.len() == 1 && { self.segments[0].ident.name == *symbol }
+        matches!(&self.segments[..], [segment] if segment.ident.name == *symbol)
     }
 }
 
@@ -121,13 +121,13 @@ impl Path {
     }
 
     pub fn is_global(&self) -> bool {
-        !self.segments.is_empty() && self.segments[0].ident.name == kw::PathRoot
+        self.segments.first().is_some_and(|segment| segment.ident.name == kw::PathRoot)
     }
 
     /// If this path is a single identifier with no arguments, does not ensure
     /// that the path resolves to a const param, the caller should check this.
     pub fn is_potential_trivial_const_arg(&self) -> bool {
-        self.segments.len() == 1 && self.segments[0].args.is_none()
+        matches!(self.segments[..], [PathSegment { args: None, .. }])
     }
 }
 
diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs
index 51f18580013..df2f4b88712 100644
--- a/compiler/rustc_ast/src/attr/mod.rs
+++ b/compiler/rustc_ast/src/attr/mod.rs
@@ -302,7 +302,7 @@ impl AttrItem {
 impl MetaItem {
     /// For a single-segment meta item, returns its name; otherwise, returns `None`.
     pub fn ident(&self) -> Option<Ident> {
-        if self.path.segments.len() == 1 { Some(self.path.segments[0].ident) } else { None }
+        if let [PathSegment { ident, .. }] = self.path.segments[..] { Some(ident) } else { None }
     }
 
     pub fn name_or_empty(&self) -> Symbol {
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index aa88e8369d5..3459d39131a 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -1813,10 +1813,10 @@ pub fn walk_flat_map_stmt<T: MutVisitor>(
         .into_iter()
         .map(|kind| Stmt { id, kind, span })
         .collect();
-    match stmts.len() {
-        0 => {}
-        1 => vis.visit_span(&mut stmts[0].span),
-        2.. => panic!(
+    match &mut stmts[..] {
+        [] => {}
+        [stmt] => vis.visit_span(&mut stmt.span),
+        _ => panic!(
             "cloning statement `NodeId`s is prohibited by default, \
              the visitor should implement custom statement visiting"
         ),
diff --git a/compiler/rustc_ast/src/util/comments.rs b/compiler/rustc_ast/src/util/comments.rs
index f39142f08ba..e12818623d8 100644
--- a/compiler/rustc_ast/src/util/comments.rs
+++ b/compiler/rustc_ast/src/util/comments.rs
@@ -39,7 +39,7 @@ pub fn beautify_doc_string(data: Symbol, kind: CommentKind) -> Symbol {
         let mut i = 0;
         let mut j = lines.len();
         // first line of all-stars should be omitted
-        if !lines.is_empty() && lines[0].chars().all(|c| c == '*') {
+        if lines.first().is_some_and(|line| line.chars().all(|c| c == '*')) {
             i += 1;
         }
 
@@ -97,7 +97,7 @@ pub fn beautify_doc_string(data: Symbol, kind: CommentKind) -> Symbol {
                 return None;
             }
         }
-        if lines.is_empty() { None } else { Some(lines[0][..i].into()) }
+        Some(lines.first()?[..i].to_string())
     }
 
     let data_s = data.as_str();
diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs
index fee7287951d..cc21a18af3a 100644
--- a/compiler/rustc_const_eval/src/const_eval/error.rs
+++ b/compiler/rustc_const_eval/src/const_eval/error.rs
@@ -140,7 +140,7 @@ where
         // Don't emit a new diagnostic for these errors, they are already reported elsewhere or
         // should remain silent.
         err_inval!(AlreadyReported(info)) => ErrorHandled::Reported(info, span),
-        err_inval!(Layout(LayoutError::Unknown(_))) | err_inval!(TooGeneric) => {
+        err_inval!(Layout(LayoutError::TooGeneric(_))) | err_inval!(TooGeneric) => {
             ErrorHandled::TooGeneric(span)
         }
         err_inval!(Layout(LayoutError::ReferencesError(guar))) => {
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs
index 39471931461..4c8f2735b97 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs
@@ -201,7 +201,7 @@ fn should_emit_generic_error<'tcx>(abi: ExternAbi, layout_err: &'tcx LayoutError
     use LayoutError::*;
 
     match layout_err {
-        Unknown(ty) => {
+        TooGeneric(ty) => {
             match abi {
                 ExternAbi::CCmseNonSecureCall => {
                     // prevent double reporting of this error
@@ -211,7 +211,11 @@ fn should_emit_generic_error<'tcx>(abi: ExternAbi, layout_err: &'tcx LayoutError
                 _ => bug!("invalid ABI: {abi}"),
             }
         }
-        SizeOverflow(..) | NormalizationFailure(..) | ReferencesError(..) | Cycle(..) => {
+        Unknown(..)
+        | SizeOverflow(..)
+        | NormalizationFailure(..)
+        | ReferencesError(..)
+        | Cycle(..) => {
             false // not our job to report these
         }
     }
diff --git a/compiler/rustc_hir_typeck/src/intrinsicck.rs b/compiler/rustc_hir_typeck/src/intrinsicck.rs
index f4929aae599..54e9e699353 100644
--- a/compiler/rustc_hir_typeck/src/intrinsicck.rs
+++ b/compiler/rustc_hir_typeck/src/intrinsicck.rs
@@ -122,7 +122,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     format!("generic size {size}")
                 }
             }
-            Err(LayoutError::Unknown(bad)) => {
+            Err(LayoutError::TooGeneric(bad)) => {
                 if *bad == ty {
                     "this type does not have a fixed size".to_owned()
                 } else {
diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl
index 0c1bd08474f..55c6a122d35 100644
--- a/compiler/rustc_lint/messages.ftl
+++ b/compiler/rustc_lint/messages.ftl
@@ -76,6 +76,11 @@ lint_builtin_deprecated_attr_link = use of deprecated attribute `{$name}`: {$rea
 lint_builtin_deref_nullptr = dereferencing a null pointer
     .label = this code causes undefined behavior when executed
 
+lint_builtin_double_negations = use of a double negation
+    .note = the prefix `--` could be misinterpreted as a decrement operator which exists in other languages
+    .note_decrement = use `-= 1` if you meant to decrement the value
+    .add_parens_suggestion = add parentheses for clarity
+
 lint_builtin_ellipsis_inclusive_range_patterns = `...` range patterns are deprecated
     .suggestion = use `..=` for an inclusive range
 
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 876ef944d65..c03de687a33 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -49,16 +49,16 @@ use rustc_trait_selection::traits::{self};
 use crate::errors::BuiltinEllipsisInclusiveRangePatterns;
 use crate::lints::{
     BuiltinAnonymousParams, BuiltinConstNoMangle, BuiltinDeprecatedAttrLink,
-    BuiltinDeprecatedAttrLinkSuggestion, BuiltinDerefNullptr,
-    BuiltinEllipsisInclusiveRangePatternsLint, BuiltinExplicitOutlives,
-    BuiltinExplicitOutlivesSuggestion, BuiltinFeatureIssueNote, BuiltinIncompleteFeatures,
-    BuiltinIncompleteFeaturesHelp, BuiltinInternalFeatures, BuiltinKeywordIdents,
-    BuiltinMissingCopyImpl, BuiltinMissingDebugImpl, BuiltinMissingDoc, BuiltinMutablesTransmutes,
-    BuiltinNoMangleGeneric, BuiltinNonShorthandFieldPatterns, BuiltinSpecialModuleNameUsed,
-    BuiltinTrivialBounds, BuiltinTypeAliasBounds, BuiltinUngatedAsyncFnTrackCaller,
-    BuiltinUnpermittedTypeInit, BuiltinUnpermittedTypeInitSub, BuiltinUnreachablePub,
-    BuiltinUnsafe, BuiltinUnstableFeatures, BuiltinUnusedDocComment, BuiltinUnusedDocCommentSub,
-    BuiltinWhileTrue, InvalidAsmLabel,
+    BuiltinDeprecatedAttrLinkSuggestion, BuiltinDerefNullptr, BuiltinDoubleNegations,
+    BuiltinDoubleNegationsAddParens, BuiltinEllipsisInclusiveRangePatternsLint,
+    BuiltinExplicitOutlives, BuiltinExplicitOutlivesSuggestion, BuiltinFeatureIssueNote,
+    BuiltinIncompleteFeatures, BuiltinIncompleteFeaturesHelp, BuiltinInternalFeatures,
+    BuiltinKeywordIdents, BuiltinMissingCopyImpl, BuiltinMissingDebugImpl, BuiltinMissingDoc,
+    BuiltinMutablesTransmutes, BuiltinNoMangleGeneric, BuiltinNonShorthandFieldPatterns,
+    BuiltinSpecialModuleNameUsed, BuiltinTrivialBounds, BuiltinTypeAliasBounds,
+    BuiltinUngatedAsyncFnTrackCaller, BuiltinUnpermittedTypeInit, BuiltinUnpermittedTypeInitSub,
+    BuiltinUnreachablePub, BuiltinUnsafe, BuiltinUnstableFeatures, BuiltinUnusedDocComment,
+    BuiltinUnusedDocCommentSub, BuiltinWhileTrue, InvalidAsmLabel,
 };
 use crate::nonstandard_style::{MethodLateContext, method_context};
 use crate::{
@@ -90,19 +90,11 @@ declare_lint! {
 
 declare_lint_pass!(WhileTrue => [WHILE_TRUE]);
 
-/// Traverse through any amount of parenthesis and return the first non-parens expression.
-fn pierce_parens(mut expr: &ast::Expr) -> &ast::Expr {
-    while let ast::ExprKind::Paren(sub) = &expr.kind {
-        expr = sub;
-    }
-    expr
-}
-
 impl EarlyLintPass for WhileTrue {
     #[inline]
     fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
         if let ast::ExprKind::While(cond, _, label) = &e.kind
-            && let ast::ExprKind::Lit(token_lit) = pierce_parens(cond).kind
+            && let ast::ExprKind::Lit(token_lit) = cond.peel_parens().kind
             && let token::Lit { kind: token::Bool, symbol: kw::True, .. } = token_lit
             && !cond.span.from_expansion()
         {
@@ -1576,6 +1568,58 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints {
     }
 }
 
+declare_lint! {
+    /// The `double_negations` lint detects expressions of the form `--x`.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// fn main() {
+    ///     let x = 1;
+    ///     let _b = --x;
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Negating something twice is usually the same as not negating it at all.
+    /// However, a double negation in Rust can easily be confused with the
+    /// prefix decrement operator that exists in many languages derived from C.
+    /// Use `-(-x)` if you really wanted to negate the value twice.
+    ///
+    /// To decrement a value, use `x -= 1` instead.
+    pub DOUBLE_NEGATIONS,
+    Warn,
+    "detects expressions of the form `--x`"
+}
+
+declare_lint_pass!(
+    /// Lint for expressions of the form `--x` that can be confused with C's
+    /// prefix decrement operator.
+    DoubleNegations => [DOUBLE_NEGATIONS]
+);
+
+impl EarlyLintPass for DoubleNegations {
+    #[inline]
+    fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
+        // only lint on the innermost `--` in a chain of `-` operators,
+        // even if there are 3 or more negations
+        if let ExprKind::Unary(UnOp::Neg, ref inner) = expr.kind
+            && let ExprKind::Unary(UnOp::Neg, ref inner2) = inner.kind
+            && !matches!(inner2.kind, ExprKind::Unary(UnOp::Neg, _))
+        {
+            cx.emit_span_lint(DOUBLE_NEGATIONS, expr.span, BuiltinDoubleNegations {
+                add_parens: BuiltinDoubleNegationsAddParens {
+                    start_span: inner.span.shrink_to_lo(),
+                    end_span: inner.span.shrink_to_hi(),
+                },
+            });
+        }
+    }
+}
+
 declare_lint_pass!(
     /// Does nothing as a lint pass, but registers some `Lint`s
     /// which are used by other parts of the compiler.
@@ -1594,7 +1638,8 @@ declare_lint_pass!(
         UNSTABLE_FEATURES,
         UNREACHABLE_PUB,
         TYPE_ALIAS_BOUNDS,
-        TRIVIAL_BOUNDS
+        TRIVIAL_BOUNDS,
+        DOUBLE_NEGATIONS
     ]
 );
 
@@ -2651,7 +2696,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
 }
 
 declare_lint! {
-    /// The `deref_nullptr` lint detects when an null pointer is dereferenced,
+    /// The `deref_nullptr` lint detects when a null pointer is dereferenced,
     /// which causes [undefined behavior].
     ///
     /// ### Example
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index 1465c2cff7b..83a168c3f44 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -181,6 +181,7 @@ early_lint_methods!(
             UnusedDocComment: UnusedDocComment,
             Expr2024: Expr2024,
             Precedence: Precedence,
+            DoubleNegations: DoubleNegations,
         ]
     ]
 );
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index 3163bc8a300..677fc86a235 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -332,6 +332,24 @@ pub(crate) struct BuiltinTrivialBounds<'a> {
 }
 
 #[derive(LintDiagnostic)]
+#[diag(lint_builtin_double_negations)]
+#[note(lint_note)]
+#[note(lint_note_decrement)]
+pub(crate) struct BuiltinDoubleNegations {
+    #[subdiagnostic]
+    pub add_parens: BuiltinDoubleNegationsAddParens,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(lint_add_parens_suggestion, applicability = "maybe-incorrect")]
+pub(crate) struct BuiltinDoubleNegationsAddParens {
+    #[suggestion_part(code = "(")]
+    pub start_span: Span,
+    #[suggestion_part(code = ")")]
+    pub end_span: Span,
+}
+
+#[derive(LintDiagnostic)]
 pub(crate) enum BuiltinEllipsisInclusiveRangePatternsLint {
     #[diag(lint_builtin_ellipsis_inclusive_range_patterns)]
     Parenthesise {
diff --git a/compiler/rustc_middle/messages.ftl b/compiler/rustc_middle/messages.ftl
index 5dd85978f00..8dc529b4d7a 100644
--- a/compiler/rustc_middle/messages.ftl
+++ b/compiler/rustc_middle/messages.ftl
@@ -100,6 +100,8 @@ middle_strict_coherence_needs_negative_coherence =
     to use `strict_coherence` on this trait, the `with_negative_coherence` feature must be enabled
     .label = due to this attribute
 
+middle_too_generic = `{$ty}` does not have a fixed size
+
 middle_type_length_limit = reached the type-length limit while instantiating `{$shrunk}`
 
 middle_unknown_layout =
@@ -107,4 +109,5 @@ middle_unknown_layout =
 
 middle_values_too_big =
     values of the type `{$ty}` are too big for the target architecture
+
 middle_written_to_path = the full type name has been written to '{$path}'
diff --git a/compiler/rustc_middle/src/error.rs b/compiler/rustc_middle/src/error.rs
index 6300d856393..b0187a1848c 100644
--- a/compiler/rustc_middle/src/error.rs
+++ b/compiler/rustc_middle/src/error.rs
@@ -129,6 +129,9 @@ pub enum LayoutError<'tcx> {
     #[diag(middle_unknown_layout)]
     Unknown { ty: Ty<'tcx> },
 
+    #[diag(middle_too_generic)]
+    TooGeneric { ty: Ty<'tcx> },
+
     #[diag(middle_values_too_big)]
     Overflow { ty: Ty<'tcx> },
 
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index 1e67cdfc32a..0d41a1d7dbf 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -231,6 +231,7 @@ impl fmt::Display for ValidityRequirement {
 pub enum LayoutError<'tcx> {
     Unknown(Ty<'tcx>),
     SizeOverflow(Ty<'tcx>),
+    TooGeneric(Ty<'tcx>),
     NormalizationFailure(Ty<'tcx>, NormalizationError<'tcx>),
     ReferencesError(ErrorGuaranteed),
     Cycle(ErrorGuaranteed),
@@ -244,6 +245,7 @@ impl<'tcx> LayoutError<'tcx> {
         match self {
             Unknown(_) => middle_unknown_layout,
             SizeOverflow(_) => middle_values_too_big,
+            TooGeneric(_) => middle_too_generic,
             NormalizationFailure(_, _) => middle_cannot_be_normalized,
             Cycle(_) => middle_cycle,
             ReferencesError(_) => middle_layout_references_error,
@@ -257,6 +259,7 @@ impl<'tcx> LayoutError<'tcx> {
         match self {
             Unknown(ty) => E::Unknown { ty },
             SizeOverflow(ty) => E::Overflow { ty },
+            TooGeneric(ty) => E::TooGeneric { ty },
             NormalizationFailure(ty, e) => {
                 E::NormalizationFailure { ty, failure_ty: e.get_type_for_failure() }
             }
@@ -272,6 +275,9 @@ impl<'tcx> fmt::Display for LayoutError<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match *self {
             LayoutError::Unknown(ty) => write!(f, "the type `{ty}` has an unknown layout"),
+            LayoutError::TooGeneric(ty) => {
+                write!(f, "`{ty}` does not have a fixed size")
+            }
             LayoutError::SizeOverflow(ty) => {
                 write!(f, "values of the type `{ty}` are too big for the target architecture")
             }
@@ -350,10 +356,11 @@ impl<'tcx> SizeSkeleton<'tcx> {
                     return Err(tcx.arena.alloc(LayoutError::Unknown(ty)));
                 }
             }
-            Err(err @ LayoutError::Unknown(_)) => err,
+            Err(err @ LayoutError::TooGeneric(_)) => err,
             // We can't extract SizeSkeleton info from other layout errors
             Err(
                 e @ LayoutError::Cycle(_)
+                | e @ LayoutError::Unknown(_)
                 | e @ LayoutError::SizeOverflow(_)
                 | e @ LayoutError::NormalizationFailure(..)
                 | e @ LayoutError::ReferencesError(_),
@@ -413,10 +420,9 @@ impl<'tcx> SizeSkeleton<'tcx> {
                             // Alignment is unchanged by arrays.
                             return Ok(SizeSkeleton::Known(Size::from_bytes(size), a));
                         }
-                        Err(tcx.arena.alloc(LayoutError::Unknown(ty)))
+                        Err(err)
                     }
-                    SizeSkeleton::Pointer { .. } => Err(err),
-                    SizeSkeleton::Generic(_) => Err(tcx.arena.alloc(LayoutError::Unknown(ty))),
+                    SizeSkeleton::Pointer { .. } | SizeSkeleton::Generic(_) => Err(err),
                 }
             }
 
diff --git a/compiler/rustc_transmute/src/layout/tree.rs b/compiler/rustc_transmute/src/layout/tree.rs
index 6ce9969aefe..b00585d2922 100644
--- a/compiler/rustc_transmute/src/layout/tree.rs
+++ b/compiler/rustc_transmute/src/layout/tree.rs
@@ -197,6 +197,7 @@ pub(crate) mod rustc {
             match err {
                 LayoutError::Unknown(..)
                 | LayoutError::ReferencesError(..)
+                | LayoutError::TooGeneric(..)
                 | LayoutError::NormalizationFailure(..) => Self::UnknownLayout,
                 LayoutError::SizeOverflow(..) => Self::SizeOverflow,
                 LayoutError::Cycle(err) => Self::TypeError(*err),
diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs
index 17be0bd0ab9..a04c7536118 100644
--- a/compiler/rustc_ty_utils/src/layout.rs
+++ b/compiler/rustc_ty_utils/src/layout.rs
@@ -104,14 +104,12 @@ fn map_error<'tcx>(
             // This is sometimes not a compile error if there are trivially false where clauses.
             // See `tests/ui/layout/trivial-bounds-sized.rs` for an example.
             assert!(field.layout.is_unsized(), "invalid layout error {err:#?}");
-            if !field.ty.is_sized(cx.tcx(), cx.typing_env) {
-                let guar = cx.tcx().dcx().delayed_bug(format!(
+            if cx.typing_env.param_env.caller_bounds().is_empty() {
+                cx.tcx().dcx().delayed_bug(format!(
                     "encountered unexpected unsized field in layout of {ty:?}: {field:#?}"
                 ));
-                LayoutError::ReferencesError(guar)
-            } else {
-                LayoutError::Unknown(ty)
             }
+            LayoutError::Unknown(ty)
         }
         LayoutCalculatorError::EmptyUnion => {
             // This is always a compile error.
@@ -146,6 +144,35 @@ fn univariant_uninterned<'tcx>(
     cx.calc.univariant(fields, repr, kind).map_err(|err| map_error(cx, ty, err))
 }
 
+fn validate_const_with_value<'tcx>(
+    const_: ty::Const<'tcx>,
+    ty: Ty<'tcx>,
+    cx: &LayoutCx<'tcx>,
+) -> Result<ty::Const<'tcx>, &'tcx LayoutError<'tcx>> {
+    match const_.kind() {
+        ty::ConstKind::Value(..) => Ok(const_),
+        ty::ConstKind::Error(guar) => {
+            return Err(error(cx, LayoutError::ReferencesError(guar)));
+        }
+        ty::ConstKind::Param(_) | ty::ConstKind::Expr(_) => {
+            if !const_.has_param() {
+                bug!("no generic type found in the type: {ty:?}");
+            }
+            return Err(error(cx, LayoutError::TooGeneric(ty)));
+        }
+        ty::ConstKind::Unevaluated(_) => {
+            if !const_.has_param() {
+                return Err(error(cx, LayoutError::Unknown(ty)));
+            } else {
+                return Err(error(cx, LayoutError::TooGeneric(ty)));
+            }
+        }
+        ty::ConstKind::Infer(_) | ty::ConstKind::Bound(..) | ty::ConstKind::Placeholder(_) => {
+            bug!("unexpected type: {ty:?}");
+        }
+    }
+}
+
 fn layout_of_uncached<'tcx>(
     cx: &LayoutCx<'tcx>,
     ty: Ty<'tcx>,
@@ -182,12 +209,13 @@ fn layout_of_uncached<'tcx>(
                         &mut layout.backend_repr
                     {
                         if let Some(start) = start {
-                            scalar.valid_range_mut().start = start
-                                .try_to_bits(tcx, cx.typing_env)
-                                .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?;
+                            scalar.valid_range_mut().start =
+                                validate_const_with_value(start, ty, cx)?
+                                    .try_to_bits(tcx, cx.typing_env)
+                                    .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?;
                         }
                         if let Some(end) = end {
-                            let mut end = end
+                            let mut end = validate_const_with_value(end, ty, cx)?
                                 .try_to_bits(tcx, cx.typing_env)
                                 .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?;
                             if !include_end {
@@ -319,17 +347,13 @@ fn layout_of_uncached<'tcx>(
         }
 
         // Arrays and slices.
-        ty::Array(element, mut count) => {
-            if count.has_aliases() {
-                count = tcx.normalize_erasing_regions(cx.typing_env, count);
-                if count.has_aliases() {
-                    return Err(error(cx, LayoutError::Unknown(ty)));
-                }
-            }
-
-            let count = count
+        ty::Array(element, count) => {
+            let count = validate_const_with_value(count, ty, cx)?
+                .to_valtree()
+                .0
                 .try_to_target_usize(tcx)
                 .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?;
+
             let element = cx.layout_of(element)?;
             let size = element
                 .size
@@ -687,6 +711,9 @@ fn layout_of_uncached<'tcx>(
 
         // Types with no meaningful known layout.
         ty::Alias(..) => {
+            if ty.has_param() {
+                return Err(error(cx, LayoutError::TooGeneric(ty)));
+            }
             // NOTE(eddyb) `layout_of` query should've normalized these away,
             // if that was possible, so there's no reason to try again here.
             return Err(error(cx, LayoutError::Unknown(ty)));
@@ -696,7 +723,11 @@ fn layout_of_uncached<'tcx>(
             bug!("Layout::compute: unexpected type `{}`", ty)
         }
 
-        ty::Placeholder(..) | ty::Param(_) => {
+        ty::Param(_) => {
+            return Err(error(cx, LayoutError::TooGeneric(ty)));
+        }
+
+        ty::Placeholder(..) => {
             return Err(error(cx, LayoutError::Unknown(ty)));
         }
     })
diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs
index fda26a67299..859ac163230 100644
--- a/library/core/src/sync/atomic.rs
+++ b/library/core/src/sync/atomic.rs
@@ -3727,33 +3727,33 @@ pub fn fence(order: Ordering) {
 ///
 /// # Examples
 ///
-/// Without `compiler_fence`, the `assert_eq!` in following code
-/// is *not* guaranteed to succeed, despite everything happening in a single thread.
-/// To see why, remember that the compiler is free to swap the stores to
-/// `IMPORTANT_VARIABLE` and `IS_READY` since they are both
-/// `Ordering::Relaxed`. If it does, and the signal handler is invoked right
-/// after `IS_READY` is updated, then the signal handler will see
-/// `IS_READY=1`, but `IMPORTANT_VARIABLE=0`.
-/// Using a `compiler_fence` remedies this situation.
+/// Without the two `compiler_fence` calls, the read of `IMPORTANT_VARIABLE` in `signal_handler`
+/// is *undefined behavior* due to a data race, despite everything happening in a single thread.
+/// This is because the signal handler is considered to run concurrently with its associated
+/// thread, and explicit synchronization is required to pass data between a thread and its
+/// signal handler. The code below uses two `compiler_fence` calls to establish the usual
+/// release-acquire synchronization pattern (see [`fence`] for an image).
 ///
 /// ```
-/// use std::sync::atomic::{AtomicBool, AtomicUsize};
+/// use std::sync::atomic::AtomicBool;
 /// use std::sync::atomic::Ordering;
 /// use std::sync::atomic::compiler_fence;
 ///
-/// static IMPORTANT_VARIABLE: AtomicUsize = AtomicUsize::new(0);
+/// static mut IMPORTANT_VARIABLE: usize = 0;
 /// static IS_READY: AtomicBool = AtomicBool::new(false);
 ///
 /// fn main() {
-///     IMPORTANT_VARIABLE.store(42, Ordering::Relaxed);
-///     // prevent earlier writes from being moved beyond this point
+///     unsafe { IMPORTANT_VARIABLE = 42 };
+///     // Marks earlier writes as being released with future relaxed stores.
 ///     compiler_fence(Ordering::Release);
 ///     IS_READY.store(true, Ordering::Relaxed);
 /// }
 ///
 /// fn signal_handler() {
 ///     if IS_READY.load(Ordering::Relaxed) {
-///         assert_eq!(IMPORTANT_VARIABLE.load(Ordering::Relaxed), 42);
+///         // Acquires writes that were released with relaxed stores that we read from.
+///         compiler_fence(Ordering::Acquire);
+///         assert_eq!(unsafe { IMPORTANT_VARIABLE }, 42);
 ///     }
 /// }
 /// ```
diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs
index 1fa13e95e68..cfd03b8e3d6 100644
--- a/library/std/src/io/mod.rs
+++ b/library/std/src/io/mod.rs
@@ -310,6 +310,8 @@ pub use self::error::RawOsError;
 pub use self::error::SimpleMessage;
 #[unstable(feature = "io_const_error", issue = "133448")]
 pub use self::error::const_error;
+#[unstable(feature = "anonymous_pipe", issue = "127154")]
+pub use self::pipe::{PipeReader, PipeWriter, pipe};
 #[stable(feature = "is_terminal", since = "1.70.0")]
 pub use self::stdio::IsTerminal;
 pub(crate) use self::stdio::attempt_print_to_stderr;
@@ -330,7 +332,6 @@ pub use self::{
 };
 use crate::mem::take;
 use crate::ops::{Deref, DerefMut};
-use crate::sys::anonymous_pipe::{AnonPipe, pipe as pipe_inner};
 use crate::{cmp, fmt, slice, str, sys};
 
 mod buffered;
@@ -338,6 +339,7 @@ pub(crate) mod copy;
 mod cursor;
 mod error;
 mod impls;
+mod pipe;
 pub mod prelude;
 mod stdio;
 mod util;
@@ -3251,257 +3253,3 @@ impl<B: BufRead> Iterator for Lines<B> {
         }
     }
 }
-
-/// Create an anonymous pipe that is close-on-exec and blocking.
-///
-/// # Behavior
-///
-/// A pipe is a one-way data channel provided by the OS, which works across processes. A pipe is
-/// typically used to communicate between two or more separate processes, as there are better,
-/// faster ways to communicate within a single process.
-///
-/// In particular:
-///
-/// * A read on a [`PipeReader`] blocks until the pipe is non-empty.
-/// * A write on a [`PipeWriter`] blocks when the pipe is full.
-/// * When all copies of a [`PipeWriter`] are closed, a read on the corresponding [`PipeReader`]
-///   returns EOF.
-/// * [`PipeWriter`] can be shared, and multiple processes or threads can write to it at once, but
-///   writes (above a target-specific threshold) may have their data interleaved.
-/// * [`PipeReader`] can be shared, and multiple processes or threads can read it at once. Any
-///   given byte will only get consumed by one reader. There are no guarantees about data
-///   interleaving.
-/// * Portable applications cannot assume any atomicity of messages larger than a single byte.
-///
-/// # Capacity
-///
-/// Pipe capacity is platform dependent. To quote the Linux [man page]:
-///
-/// > Different implementations have different limits for the pipe capacity. Applications should
-/// > not rely on a particular capacity: an application should be designed so that a reading process
-/// > consumes data as soon as it is available, so that a writing process does not remain blocked.
-///
-/// # Examples
-///
-/// ```no_run
-/// #![feature(anonymous_pipe)]
-/// # #[cfg(miri)] fn main() {}
-/// # #[cfg(not(miri))]
-/// # fn main() -> std::io::Result<()> {
-/// # use std::process::Command;
-/// # use std::io::{Read, Write};
-/// let (ping_rx, mut ping_tx) = std::io::pipe()?;
-/// let (mut pong_rx, pong_tx) = std::io::pipe()?;
-///
-/// // Spawn a process that echoes its input.
-/// let mut echo_server = Command::new("cat").stdin(ping_rx).stdout(pong_tx).spawn()?;
-///
-/// ping_tx.write_all(b"hello")?;
-/// // Close to unblock echo_server's reader.
-/// drop(ping_tx);
-///
-/// let mut buf = String::new();
-/// // Block until echo_server's writer is closed.
-/// pong_rx.read_to_string(&mut buf)?;
-/// assert_eq!(&buf, "hello");
-///
-/// echo_server.wait()?;
-/// # Ok(())
-/// # }
-/// ```
-/// [man page]: https://man7.org/linux/man-pages/man7/pipe.7.html
-#[unstable(feature = "anonymous_pipe", issue = "127154")]
-#[inline]
-pub fn pipe() -> Result<(PipeReader, PipeWriter)> {
-    pipe_inner().map(|(reader, writer)| (PipeReader(reader), PipeWriter(writer)))
-}
-
-/// Read end of an anonymous pipe.
-#[unstable(feature = "anonymous_pipe", issue = "127154")]
-#[derive(Debug)]
-pub struct PipeReader(pub(crate) AnonPipe);
-
-/// Write end of an anonymous pipe.
-#[unstable(feature = "anonymous_pipe", issue = "127154")]
-#[derive(Debug)]
-pub struct PipeWriter(pub(crate) AnonPipe);
-
-impl PipeReader {
-    /// Create a new [`PipeReader`] instance that shares the same underlying file description.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// #![feature(anonymous_pipe)]
-    /// # #[cfg(miri)] fn main() {}
-    /// # #[cfg(not(miri))]
-    /// # fn main() -> std::io::Result<()> {
-    /// # use std::fs;
-    /// # use std::io::Write;
-    /// # use std::process::Command;
-    /// const NUM_SLOT: u8 = 2;
-    /// const NUM_PROC: u8 = 5;
-    /// const OUTPUT: &str = "work.txt";
-    ///
-    /// let mut jobs = vec![];
-    /// let (reader, mut writer) = std::io::pipe()?;
-    ///
-    /// // Write NUM_SLOT characters the pipe.
-    /// writer.write_all(&[b'|'; NUM_SLOT as usize])?;
-    ///
-    /// // Spawn several processes that read a character from the pipe, do some work, then
-    /// // write back to the pipe. When the pipe is empty, the processes block, so only
-    /// // NUM_SLOT processes can be working at any given time.
-    /// for _ in 0..NUM_PROC {
-    ///     jobs.push(
-    ///         Command::new("bash")
-    ///             .args(["-c",
-    ///                 &format!(
-    ///                      "read -n 1\n\
-    ///                       echo -n 'x' >> '{OUTPUT}'\n\
-    ///                       echo -n '|'",
-    ///                 ),
-    ///             ])
-    ///             .stdin(reader.try_clone()?)
-    ///             .stdout(writer.try_clone()?)
-    ///             .spawn()?,
-    ///     );
-    /// }
-    ///
-    /// // Wait for all jobs to finish.
-    /// for mut job in jobs {
-    ///     job.wait()?;
-    /// }
-    ///
-    /// // Check our work and clean up.
-    /// let xs = fs::read_to_string(OUTPUT)?;
-    /// fs::remove_file(OUTPUT)?;
-    /// assert_eq!(xs, "x".repeat(NUM_PROC.into()));
-    /// # Ok(())
-    /// # }
-    /// ```
-    #[unstable(feature = "anonymous_pipe", issue = "127154")]
-    pub fn try_clone(&self) -> Result<Self> {
-        self.0.try_clone().map(Self)
-    }
-}
-
-impl PipeWriter {
-    /// Create a new [`PipeWriter`] instance that shares the same underlying file description.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// #![feature(anonymous_pipe)]
-    /// # #[cfg(miri)] fn main() {}
-    /// # #[cfg(not(miri))]
-    /// # fn main() -> std::io::Result<()> {
-    /// # use std::process::Command;
-    /// # use std::io::Read;
-    /// let (mut reader, writer) = std::io::pipe()?;
-    ///
-    /// // Spawn a process that writes to stdout and stderr.
-    /// let mut peer = Command::new("bash")
-    ///     .args([
-    ///         "-c",
-    ///         "echo -n foo\n\
-    ///          echo -n bar >&2"
-    ///     ])
-    ///     .stdout(writer.try_clone()?)
-    ///     .stderr(writer)
-    ///     .spawn()?;
-    ///
-    /// // Read and check the result.
-    /// let mut msg = String::new();
-    /// reader.read_to_string(&mut msg)?;
-    /// assert_eq!(&msg, "foobar");
-    ///
-    /// peer.wait()?;
-    /// # Ok(())
-    /// # }
-    /// ```
-    #[unstable(feature = "anonymous_pipe", issue = "127154")]
-    pub fn try_clone(&self) -> Result<Self> {
-        self.0.try_clone().map(Self)
-    }
-}
-
-#[unstable(feature = "anonymous_pipe", issue = "127154")]
-impl Read for &PipeReader {
-    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
-        self.0.read(buf)
-    }
-    fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> Result<usize> {
-        self.0.read_vectored(bufs)
-    }
-    #[inline]
-    fn is_read_vectored(&self) -> bool {
-        self.0.is_read_vectored()
-    }
-    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> Result<usize> {
-        self.0.read_to_end(buf)
-    }
-    fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> Result<()> {
-        self.0.read_buf(buf)
-    }
-}
-
-#[unstable(feature = "anonymous_pipe", issue = "127154")]
-impl Read for PipeReader {
-    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
-        self.0.read(buf)
-    }
-    fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> Result<usize> {
-        self.0.read_vectored(bufs)
-    }
-    #[inline]
-    fn is_read_vectored(&self) -> bool {
-        self.0.is_read_vectored()
-    }
-    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> Result<usize> {
-        self.0.read_to_end(buf)
-    }
-    fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> Result<()> {
-        self.0.read_buf(buf)
-    }
-}
-
-#[unstable(feature = "anonymous_pipe", issue = "127154")]
-impl Write for &PipeWriter {
-    fn write(&mut self, buf: &[u8]) -> Result<usize> {
-        self.0.write(buf)
-    }
-    #[inline]
-    fn flush(&mut self) -> Result<()> {
-        Ok(())
-    }
-
-    fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> Result<usize> {
-        self.0.write_vectored(bufs)
-    }
-
-    #[inline]
-    fn is_write_vectored(&self) -> bool {
-        self.0.is_write_vectored()
-    }
-}
-
-#[unstable(feature = "anonymous_pipe", issue = "127154")]
-impl Write for PipeWriter {
-    fn write(&mut self, buf: &[u8]) -> Result<usize> {
-        self.0.write(buf)
-    }
-    #[inline]
-    fn flush(&mut self) -> Result<()> {
-        Ok(())
-    }
-
-    fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> Result<usize> {
-        self.0.write_vectored(bufs)
-    }
-
-    #[inline]
-    fn is_write_vectored(&self) -> bool {
-        self.0.is_write_vectored()
-    }
-}
diff --git a/library/std/src/io/pipe.rs b/library/std/src/io/pipe.rs
new file mode 100644
index 00000000000..266c7bc9638
--- /dev/null
+++ b/library/std/src/io/pipe.rs
@@ -0,0 +1,260 @@
+use crate::io;
+use crate::sys::anonymous_pipe::{AnonPipe, pipe as pipe_inner};
+
+/// Create an anonymous pipe.
+///
+/// # Behavior
+///
+/// A pipe is a one-way data channel provided by the OS, which works across processes. A pipe is
+/// typically used to communicate between two or more separate processes, as there are better,
+/// faster ways to communicate within a single process.
+///
+/// In particular:
+///
+/// * A read on a [`PipeReader`] blocks until the pipe is non-empty.
+/// * A write on a [`PipeWriter`] blocks when the pipe is full.
+/// * When all copies of a [`PipeWriter`] are closed, a read on the corresponding [`PipeReader`]
+///   returns EOF.
+/// * [`PipeWriter`] can be shared, and multiple processes or threads can write to it at once, but
+///   writes (above a target-specific threshold) may have their data interleaved.
+/// * [`PipeReader`] can be shared, and multiple processes or threads can read it at once. Any
+///   given byte will only get consumed by one reader. There are no guarantees about data
+///   interleaving.
+/// * Portable applications cannot assume any atomicity of messages larger than a single byte.
+///
+/// # Platform-specific behavior
+///
+/// This function currently corresponds to the `pipe` function on Unix and the
+/// `CreatePipe` function on Windows.
+///
+/// Note that this [may change in the future][changes].
+///
+/// # Capacity
+///
+/// Pipe capacity is platform dependent. To quote the Linux [man page]:
+///
+/// > Different implementations have different limits for the pipe capacity. Applications should
+/// > not rely on a particular capacity: an application should be designed so that a reading process
+/// > consumes data as soon as it is available, so that a writing process does not remain blocked.
+///
+/// # Examples
+///
+/// ```no_run
+/// #![feature(anonymous_pipe)]
+/// # #[cfg(miri)] fn main() {}
+/// # #[cfg(not(miri))]
+/// # fn main() -> std::io::Result<()> {
+/// use std::process::Command;
+/// use std::io::{pipe, Read, Write};
+/// let (ping_rx, mut ping_tx) = pipe()?;
+/// let (mut pong_rx, pong_tx) = pipe()?;
+///
+/// // Spawn a process that echoes its input.
+/// let mut echo_server = Command::new("cat").stdin(ping_rx).stdout(pong_tx).spawn()?;
+///
+/// ping_tx.write_all(b"hello")?;
+/// // Close to unblock echo_server's reader.
+/// drop(ping_tx);
+///
+/// let mut buf = String::new();
+/// // Block until echo_server's writer is closed.
+/// pong_rx.read_to_string(&mut buf)?;
+/// assert_eq!(&buf, "hello");
+///
+/// echo_server.wait()?;
+/// # Ok(())
+/// # }
+/// ```
+/// [changes]: io#platform-specific-behavior
+/// [man page]: https://man7.org/linux/man-pages/man7/pipe.7.html
+#[unstable(feature = "anonymous_pipe", issue = "127154")]
+#[inline]
+pub fn pipe() -> io::Result<(PipeReader, PipeWriter)> {
+    pipe_inner().map(|(reader, writer)| (PipeReader(reader), PipeWriter(writer)))
+}
+
+/// Read end of an anonymous pipe.
+#[unstable(feature = "anonymous_pipe", issue = "127154")]
+#[derive(Debug)]
+pub struct PipeReader(pub(crate) AnonPipe);
+
+/// Write end of an anonymous pipe.
+#[unstable(feature = "anonymous_pipe", issue = "127154")]
+#[derive(Debug)]
+pub struct PipeWriter(pub(crate) AnonPipe);
+
+impl PipeReader {
+    /// Create a new [`PipeReader`] instance that shares the same underlying file description.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// #![feature(anonymous_pipe)]
+    /// # #[cfg(miri)] fn main() {}
+    /// # #[cfg(not(miri))]
+    /// # fn main() -> std::io::Result<()> {
+    /// use std::fs;
+    /// use std::io::{pipe, Write};
+    /// use std::process::Command;
+    /// const NUM_SLOT: u8 = 2;
+    /// const NUM_PROC: u8 = 5;
+    /// const OUTPUT: &str = "work.txt";
+    ///
+    /// let mut jobs = vec![];
+    /// let (reader, mut writer) = pipe()?;
+    ///
+    /// // Write NUM_SLOT characters the pipe.
+    /// writer.write_all(&[b'|'; NUM_SLOT as usize])?;
+    ///
+    /// // Spawn several processes that read a character from the pipe, do some work, then
+    /// // write back to the pipe. When the pipe is empty, the processes block, so only
+    /// // NUM_SLOT processes can be working at any given time.
+    /// for _ in 0..NUM_PROC {
+    ///     jobs.push(
+    ///         Command::new("bash")
+    ///             .args(["-c",
+    ///                 &format!(
+    ///                      "read -n 1\n\
+    ///                       echo -n 'x' >> '{OUTPUT}'\n\
+    ///                       echo -n '|'",
+    ///                 ),
+    ///             ])
+    ///             .stdin(reader.try_clone()?)
+    ///             .stdout(writer.try_clone()?)
+    ///             .spawn()?,
+    ///     );
+    /// }
+    ///
+    /// // Wait for all jobs to finish.
+    /// for mut job in jobs {
+    ///     job.wait()?;
+    /// }
+    ///
+    /// // Check our work and clean up.
+    /// let xs = fs::read_to_string(OUTPUT)?;
+    /// fs::remove_file(OUTPUT)?;
+    /// assert_eq!(xs, "x".repeat(NUM_PROC.into()));
+    /// # Ok(())
+    /// # }
+    /// ```
+    #[unstable(feature = "anonymous_pipe", issue = "127154")]
+    pub fn try_clone(&self) -> io::Result<Self> {
+        self.0.try_clone().map(Self)
+    }
+}
+
+impl PipeWriter {
+    /// Create a new [`PipeWriter`] instance that shares the same underlying file description.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// #![feature(anonymous_pipe)]
+    /// # #[cfg(miri)] fn main() {}
+    /// # #[cfg(not(miri))]
+    /// # fn main() -> std::io::Result<()> {
+    /// use std::process::Command;
+    /// use std::io::{pipe, Read};
+    /// let (mut reader, writer) = pipe()?;
+    ///
+    /// // Spawn a process that writes to stdout and stderr.
+    /// let mut peer = Command::new("bash")
+    ///     .args([
+    ///         "-c",
+    ///         "echo -n foo\n\
+    ///          echo -n bar >&2"
+    ///     ])
+    ///     .stdout(writer.try_clone()?)
+    ///     .stderr(writer)
+    ///     .spawn()?;
+    ///
+    /// // Read and check the result.
+    /// let mut msg = String::new();
+    /// reader.read_to_string(&mut msg)?;
+    /// assert_eq!(&msg, "foobar");
+    ///
+    /// peer.wait()?;
+    /// # Ok(())
+    /// # }
+    /// ```
+    #[unstable(feature = "anonymous_pipe", issue = "127154")]
+    pub fn try_clone(&self) -> io::Result<Self> {
+        self.0.try_clone().map(Self)
+    }
+}
+
+#[unstable(feature = "anonymous_pipe", issue = "127154")]
+impl io::Read for &PipeReader {
+    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+        self.0.read(buf)
+    }
+    fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
+        self.0.read_vectored(bufs)
+    }
+    #[inline]
+    fn is_read_vectored(&self) -> bool {
+        self.0.is_read_vectored()
+    }
+    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
+        self.0.read_to_end(buf)
+    }
+    fn read_buf(&mut self, buf: io::BorrowedCursor<'_>) -> io::Result<()> {
+        self.0.read_buf(buf)
+    }
+}
+
+#[unstable(feature = "anonymous_pipe", issue = "127154")]
+impl io::Read for PipeReader {
+    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+        self.0.read(buf)
+    }
+    fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
+        self.0.read_vectored(bufs)
+    }
+    #[inline]
+    fn is_read_vectored(&self) -> bool {
+        self.0.is_read_vectored()
+    }
+    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
+        self.0.read_to_end(buf)
+    }
+    fn read_buf(&mut self, buf: io::BorrowedCursor<'_>) -> io::Result<()> {
+        self.0.read_buf(buf)
+    }
+}
+
+#[unstable(feature = "anonymous_pipe", issue = "127154")]
+impl io::Write for &PipeWriter {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        self.0.write(buf)
+    }
+    #[inline]
+    fn flush(&mut self) -> io::Result<()> {
+        Ok(())
+    }
+    fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
+        self.0.write_vectored(bufs)
+    }
+    #[inline]
+    fn is_write_vectored(&self) -> bool {
+        self.0.is_write_vectored()
+    }
+}
+
+#[unstable(feature = "anonymous_pipe", issue = "127154")]
+impl io::Write for PipeWriter {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        self.0.write(buf)
+    }
+    #[inline]
+    fn flush(&mut self) -> io::Result<()> {
+        Ok(())
+    }
+    fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
+        self.0.write_vectored(bufs)
+    }
+    #[inline]
+    fn is_write_vectored(&self) -> bool {
+        self.0.is_write_vectored()
+    }
+}
diff --git a/library/std/src/io/pipe/tests.rs b/library/std/src/io/pipe/tests.rs
new file mode 100644
index 00000000000..c1f3f192ca2
--- /dev/null
+++ b/library/std/src/io/pipe/tests.rs
@@ -0,0 +1,18 @@
+use crate::io::{Read, Write, pipe};
+
+#[test]
+#[cfg(all(windows, unix, not(miri)))]
+fn pipe_creation_clone_and_rw() {
+    let (rx, tx) = pipe().unwrap();
+
+    tx.try_clone().unwrap().write_all(b"12345").unwrap();
+    drop(tx);
+
+    let mut rx2 = rx.try_clone().unwrap();
+    drop(rx);
+
+    let mut s = String::new();
+    rx2.read_to_string(&mut s).unwrap();
+    drop(rx2);
+    assert_eq!(s, "12345");
+}
diff --git a/library/std/src/io/tests.rs b/library/std/src/io/tests.rs
index 226cc6011bc..f64f034cce7 100644
--- a/library/std/src/io/tests.rs
+++ b/library/std/src/io/tests.rs
@@ -821,20 +821,3 @@ fn try_oom_error() {
     let io_err = io::Error::from(reserve_err);
     assert_eq!(io::ErrorKind::OutOfMemory, io_err.kind());
 }
-
-#[test]
-#[cfg(all(windows, unix, not(miri)))]
-fn pipe_creation_clone_and_rw() {
-    let (rx, tx) = std::io::pipe().unwrap();
-
-    tx.try_clone().unwrap().write_all(b"12345").unwrap();
-    drop(tx);
-
-    let mut rx2 = rx.try_clone().unwrap();
-    drop(rx);
-
-    let mut s = String::new();
-    rx2.read_to_string(&mut s).unwrap();
-    drop(rx2);
-    assert_eq!(s, "12345");
-}
diff --git a/src/bootstrap/src/bin/main.rs b/src/bootstrap/src/bin/main.rs
index 8ebd6b8aa54..5fcf7eda8df 100644
--- a/src/bootstrap/src/bin/main.rs
+++ b/src/bootstrap/src/bin/main.rs
@@ -16,11 +16,7 @@ use bootstrap::{
 };
 use build_helper::ci::CiEnv;
 #[cfg(feature = "tracing")]
-use tracing::*;
-#[cfg(feature = "tracing")]
-use tracing_subscriber::EnvFilter;
-#[cfg(feature = "tracing")]
-use tracing_subscriber::prelude::*;
+use tracing::{debug, instrument};
 
 #[cfg_attr(feature = "tracing", instrument(level = "trace", name = "main"))]
 fn main() {
@@ -33,7 +29,11 @@ fn main() {
         return;
     }
 
+    #[cfg(feature = "tracing")]
+    debug!("parsing flags");
     let flags = Flags::parse(&args);
+    #[cfg(feature = "tracing")]
+    debug!("parsing config based on flags");
     let config = Config::parse(flags);
 
     let mut build_lock;
@@ -95,6 +95,8 @@ fn main() {
     let dump_bootstrap_shims = config.dump_bootstrap_shims;
     let out_dir = config.out.clone();
 
+    #[cfg(feature = "tracing")]
+    debug!("creating new build based on config");
     Build::new(config).build();
 
     if suggest_setup {
@@ -211,16 +213,14 @@ fn check_version(config: &Config) -> Option<String> {
 //   "tracing", instrument(..))]`.
 #[cfg(feature = "tracing")]
 fn setup_tracing() {
+    use tracing_subscriber::EnvFilter;
+    use tracing_subscriber::layer::SubscriberExt;
+
     let filter = EnvFilter::from_env("BOOTSTRAP_TRACING");
-    let layer = tracing_tree::HierarchicalLayer::default()
-        .with_writer(std::io::stderr)
-        .with_ansi(true)
-        .with_targets(true)
-        .with_bracketed_fields(true)
-        .with_indent_amount(2)
-        .with_indent_lines(true);
-    let subscriber = tracing_subscriber::registry().with(filter).with(layer);
-
-    tracing::subscriber::set_global_default(subscriber).unwrap();
-    trace!("tracing subscriber setup");
+    // cf. <https://docs.rs/tracing-tree/latest/tracing_tree/struct.HierarchicalLayer.html>.
+    let layer = tracing_tree::HierarchicalLayer::default().with_targets(true).with_indent_amount(2);
+
+    let registry = tracing_subscriber::registry().with(filter).with(layer);
+
+    tracing::subscriber::set_global_default(registry).unwrap();
 }
diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs
index 910550b0a7d..98490118f7d 100644
--- a/src/bootstrap/src/core/config/config.rs
+++ b/src/bootstrap/src/core/config/config.rs
@@ -18,6 +18,8 @@ use build_helper::exit;
 use build_helper::git::{GitConfig, get_closest_merge_commit, output_result};
 use serde::{Deserialize, Deserializer};
 use serde_derive::Deserialize;
+#[cfg(feature = "tracing")]
+use tracing::{instrument, span};
 
 use crate::core::build_steps::compile::CODEGEN_BACKEND_PREFIX;
 use crate::core::build_steps::llvm;
@@ -1227,7 +1229,14 @@ define_config! {
 }
 
 impl Config {
+    #[cfg_attr(
+        feature = "tracing",
+        instrument(target = "CONFIG_HANDLING", level = "trace", name = "Config::default_opts")
+    )]
     pub fn default_opts() -> Config {
+        #[cfg(feature = "tracing")]
+        span!(target: "CONFIG_HANDLING", tracing::Level::TRACE, "constructing default config");
+
         Config {
             bypass_bootstrap_lock: false,
             llvm_optimize: true,
@@ -1311,10 +1320,23 @@ impl Config {
             })
     }
 
+    #[cfg_attr(
+        feature = "tracing",
+        instrument(target = "CONFIG_HANDLING", level = "trace", name = "Config::parse", skip_all)
+    )]
     pub fn parse(flags: Flags) -> Config {
         Self::parse_inner(flags, Self::get_toml)
     }
 
+    #[cfg_attr(
+        feature = "tracing",
+        instrument(
+            target = "CONFIG_HANDLING",
+            level = "trace",
+            name = "Config::parse_inner",
+            skip_all
+        )
+    )]
     pub(crate) fn parse_inner(
         mut flags: Flags,
         get_toml: impl Fn(&Path) -> Result<TomlConfig, toml::de::Error>,
@@ -1323,6 +1345,17 @@ impl Config {
 
         // Set flags.
         config.paths = std::mem::take(&mut flags.paths);
+
+        #[cfg(feature = "tracing")]
+        span!(
+            target: "CONFIG_HANDLING",
+            tracing::Level::TRACE,
+            "collecting paths and path exclusions",
+            "flags.paths" = ?flags.paths,
+            "flags.skip" = ?flags.skip,
+            "flags.exclude" = ?flags.exclude
+        );
+
         config.skip = flags
             .skip
             .into_iter()
@@ -1339,6 +1372,14 @@ impl Config {
             })
             .collect();
 
+        #[cfg(feature = "tracing")]
+        span!(
+            target: "CONFIG_HANDLING",
+            tracing::Level::TRACE,
+            "normalizing and combining `flag.skip`/`flag.exclude` paths",
+            "config.skip" = ?config.skip,
+        );
+
         config.include_default_paths = flags.include_default_paths;
         config.rustc_error_format = flags.rustc_error_format;
         config.json_output = flags.json_output;
@@ -1418,7 +1459,11 @@ impl Config {
 
         config.stage0_metadata = build_helper::stage0_parser::parse_stage0_file();
 
-        // Read from `--config`, then `RUST_BOOTSTRAP_CONFIG`, then `./config.toml`, then `config.toml` in the root directory.
+        // Find configuration file, with the following cascading fallback (first match wins):
+        // - `--config <path>`
+        // - `RUST_BOOTSTRAP_CONFIG`
+        // - `./config.toml`
+        // - `config.toml` in the root directory.
         let toml_path = flags
             .config
             .clone()
diff --git a/src/bootstrap/src/core/config/flags.rs b/src/bootstrap/src/core/config/flags.rs
index f17103f97dc..27fb00cb06e 100644
--- a/src/bootstrap/src/core/config/flags.rs
+++ b/src/bootstrap/src/core/config/flags.rs
@@ -6,6 +6,8 @@
 use std::path::{Path, PathBuf};
 
 use clap::{CommandFactory, Parser, ValueEnum};
+#[cfg(feature = "tracing")]
+use tracing::instrument;
 
 use crate::core::build_steps::setup::Profile;
 use crate::core::builder::{Builder, Kind};
@@ -211,6 +213,10 @@ impl Flags {
         }
     }
 
+    #[cfg_attr(
+        feature = "tracing",
+        instrument(level = "trace", name = "Flags::parse", skip_all, fields(args = ?args))
+    )]
     pub fn parse(args: &[String]) -> Self {
         Flags::parse_from(normalize_args(args))
     }
diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs
index 482e23cd04c..d56f35f866c 100644
--- a/src/bootstrap/src/lib.rs
+++ b/src/bootstrap/src/lib.rs
@@ -28,6 +28,8 @@ use std::{env, fs, io, str};
 use build_helper::ci::gha;
 use build_helper::exit;
 use termcolor::{ColorChoice, StandardStream, WriteColor};
+#[cfg(feature = "tracing")]
+use tracing::{debug, instrument, span, trace};
 use utils::build_stamp::BuildStamp;
 use utils::channel::GitInfo;
 
@@ -537,14 +539,25 @@ impl Build {
     }
 
     /// Executes the entire build, as configured by the flags and configuration.
+    #[cfg_attr(feature = "tracing", instrument(level = "debug", name = "Build::build", skip_all))]
     pub fn build(&mut self) {
+        #[cfg(feature = "tracing")]
+        trace!("setting up job management");
         unsafe {
             crate::utils::job::setup(self);
         }
 
+        #[cfg(feature = "tracing")]
+        trace!("downloading rustfmt early");
+
         // Download rustfmt early so that it can be used in rust-analyzer configs.
         let _ = &builder::Builder::new(self).initial_rustfmt();
 
+        #[cfg(feature = "tracing")]
+        let hardcoded_span =
+            span!(tracing::Level::DEBUG, "handling hardcoded subcommands (Format, Suggest, Perf)")
+                .entered();
+
         // hardcoded subcommands
         match &self.config.cmd {
             Subcommand::Format { check, all } => {
@@ -561,25 +574,50 @@ impl Build {
             Subcommand::Perf { .. } => {
                 return core::build_steps::perf::perf(&builder::Builder::new(self));
             }
-            _ => (),
+            _cmd => {
+                #[cfg(feature = "tracing")]
+                debug!(cmd = ?_cmd, "not a hardcoded subcommand; returning to normal handling");
+            }
         }
 
+        #[cfg(feature = "tracing")]
+        drop(hardcoded_span);
+        #[cfg(feature = "tracing")]
+        debug!("handling subcommand normally");
+
         if !self.config.dry_run() {
+            #[cfg(feature = "tracing")]
+            let _real_run_span = span!(tracing::Level::DEBUG, "executing real run").entered();
+
             {
+                #[cfg(feature = "tracing")]
+                let _sanity_check_span =
+                    span!(tracing::Level::DEBUG, "(1) executing dry-run sanity-check").entered();
+
                 // We first do a dry-run. This is a sanity-check to ensure that
                 // steps don't do anything expensive in the dry-run.
                 self.config.dry_run = DryRun::SelfCheck;
                 let builder = builder::Builder::new(self);
                 builder.execute_cli();
             }
+
+            #[cfg(feature = "tracing")]
+            let _actual_run_span =
+                span!(tracing::Level::DEBUG, "(2) executing actual run").entered();
             self.config.dry_run = DryRun::Disabled;
             let builder = builder::Builder::new(self);
             builder.execute_cli();
         } else {
+            #[cfg(feature = "tracing")]
+            let _dry_run_span = span!(tracing::Level::DEBUG, "executing dry run").entered();
+
             let builder = builder::Builder::new(self);
             builder.execute_cli();
         }
 
+        #[cfg(feature = "tracing")]
+        debug!("checking for postponed test failures from `test  --no-fail-fast`");
+
         // Check for postponed failures from `test --no-fail-fast`.
         let failures = self.delayed_failures.borrow();
         if failures.len() > 0 {
diff --git a/src/doc/rustc-dev-guide/src/building/bootstrapping/debugging-bootstrap.md b/src/doc/rustc-dev-guide/src/building/bootstrapping/debugging-bootstrap.md
index 972b4a8fb0e..3f907e85dd6 100644
--- a/src/doc/rustc-dev-guide/src/building/bootstrapping/debugging-bootstrap.md
+++ b/src/doc/rustc-dev-guide/src/building/bootstrapping/debugging-bootstrap.md
@@ -1,6 +1,6 @@
 # Debugging bootstrap
 
-> FIXME: this page could be expanded 
+> FIXME: this section should be expanded
 
 ## `tracing` in bootstrap
 
@@ -10,21 +10,69 @@ Bootstrap has conditional [`tracing`][tracing] setup to provide structured loggi
 
 ### Enabling `tracing` output
 
-Bootstrap will conditionally enable `tracing` output if the `BOOTSTRAP_TRACING` env var is set.
+Bootstrap will conditionally build `tracing` support and enable `tracing` output if the `BOOTSTRAP_TRACING` env var is set.
 
-Example usage:
+#### Basic usage
+
+Example basic usage[^just-trace]:
+
+[^just-trace]: It is not recommend to use *just* `BOOTSTRAP_TRACING=TRACE` because that will dump *everything* at `TRACE` level, including logs intentionally gated behind custom targets as they are too verbose even for `TRACE` level by default.
 
 ```bash
-$ BOOTSTRAP_TRACING=TRACE ./x build library --stage 1
+$ BOOTSTRAP_TRACING=bootstrap=TRACE ./x build library --stage 1
+```
+
+Example output[^unstable]:
+
+```
+$ BOOTSTRAP_TRACING=bootstrap=TRACE ./x check src/bootstrap/
+Building bootstrap
+   Compiling bootstrap v0.0.0 (/home/joe/repos/rust/src/bootstrap)
+    Finished `dev` profile [unoptimized] target(s) in 2.74s
+ DEBUG bootstrap parsing flags
+ bootstrap::core::config::flags::Flags::parse args=["check", "src/bootstrap/"]
+ DEBUG bootstrap parsing config based on flags
+ DEBUG bootstrap creating new build based on config
+ bootstrap::Build::build
+  TRACE bootstrap setting up job management
+  TRACE bootstrap downloading rustfmt early
+   bootstrap::handling hardcoded subcommands (Format, Suggest, Perf)
+    DEBUG bootstrap not a hardcoded subcommand; returning to normal handling, cmd=Check { all_targets: false }
+  DEBUG bootstrap handling subcommand normally
+   bootstrap::executing real run
+     bootstrap::(1) executing dry-run sanity-check
+     bootstrap::(2) executing actual run
+Checking stage0 library artifacts (x86_64-unknown-linux-gnu)
+    Finished `release` profile [optimized + debuginfo] target(s) in 0.04s
+Checking stage0 compiler artifacts {rustc-main, rustc_abi, rustc_arena, rustc_ast, rustc_ast_ir, rustc_ast_lowering, rustc_ast_passes, rustc_ast_pretty, rustc_attr_data_structures, rustc_attr_parsing, rustc_baked_icu_data, rustc_borrowck, rustc_builtin_macros, rustc_codegen_llvm, rustc_codegen_ssa, rustc_const_eval, rustc_data_structures, rustc_driver, rustc_driver_impl, rustc_error_codes, rustc_error_messages, rustc_errors, rustc_expand, rustc_feature, rustc_fluent_macro, rustc_fs_util, rustc_graphviz, rustc_hir, rustc_hir_analysis, rustc_hir_pretty, rustc_hir_typeck, rustc_incremental, rustc_index, rustc_index_macros, rustc_infer, rustc_interface, rustc_lexer, rustc_lint, rustc_lint_defs, rustc_llvm, rustc_log, rustc_macros, rustc_metadata, rustc_middle, rustc_mir_build, rustc_mir_dataflow, rustc_mir_transform, rustc_monomorphize, rustc_next_trait_solver, rustc_parse, rustc_parse_format, rustc_passes, rustc_pattern_analysis, rustc_privacy, rustc_query_impl, rustc_query_system, rustc_resolve, rustc_sanitizers, rustc_serialize, rustc_session, rustc_smir, rustc_span, rustc_symbol_mangling, rustc_target, rustc_trait_selection, rustc_traits, rustc_transmute, rustc_ty_utils, rustc_type_ir, rustc_type_ir_macros, stable_mir} (x86_64-unknown-linux-gnu)
+    Finished `release` profile [optimized + debuginfo] target(s) in 0.23s
+Checking stage0 bootstrap artifacts (x86_64-unknown-linux-gnu)
+    Checking bootstrap v0.0.0 (/home/joe/repos/rust/src/bootstrap)
+    Finished `release` profile [optimized + debuginfo] target(s) in 0.64s
+  DEBUG bootstrap checking for postponed test failures from `test  --no-fail-fast`
+Build completed successfully in 0:00:08
 ```
 
-Example output[^experimental]:
+#### Controlling log output
+
+The env var `BOOTSTRAP_TRACING` accepts a [`tracing` env-filter][tracing-env-filter].
+
+There are two orthogonal ways to control which kind of logs you want:
 
-![Example bootstrap tracing output](./debugging-bootstrap/tracing-output-example.png)
+1. You can specify the log **level**, e.g. `DEBUG` or `TRACE`.
+2. You can also control the log **target**, e.g. `bootstrap` or `bootstrap::core::config` vs custom targets like `CONFIG_HANDLING`.
+    - Custom targets are used to limit what is output when `BOOTSTRAP_TRACING=bootstrap=TRACE` is used, as they can be too verbose even for `TRACE` level by default. Currently used custom targets:
+        - `CONFIG_HANDLING`
 
-[^experimental]: This shows what's *possible* with the infra in an experimental implementation.
+The `TRACE` filter will enable *all* `trace` level or less verbose level tracing output.
 
-The env var `BOOTSTRAP_TRACING` accepts a [`tracing` env-filter][tracing-env-filter]. The `TRACE` filter will enable *all* `trace` level or less verbose level tracing output.
+You can of course combine them (custom target logs are typically gated behind `TRACE` log level additionally):
+
+```bash
+$ BOOTSTRAP_TRACING=CONFIG_HANDLING=TRACE ./x build library --stage 1
+```
+
+[^unstable]: This output is always subject to further changes.
 
 [tracing-env-filter]: https://docs.rs/tracing-subscriber/0.3.19/tracing_subscriber/filter/struct.EnvFilter.html
 
@@ -73,28 +121,6 @@ For `#[instrument]`, it's recommended to:
 - Explicitly pick an instrumentation name via `name = ".."` to distinguish between e.g. `run` of different steps.
 - Take care to not cause diverging behavior via tracing, e.g. building extra things only when tracing infra is enabled.
 
-### Enabling `tracing` bootstrap feature in rust-analyzer
+### rust-analyzer integration?
 
-You can adjust your `settings.json`'s `rust-analyzer.check.overrideCommand` and `rust-analyzer.cargo.buildScripts.overrideCommand` if you want to also enable `logging` cargo feature by default in your editor. This is mostly useful if you want proper r-a completions and such when working on bootstrap itself.
-
-```json
-"rust-analyzer.check.overrideCommand": [
-    "BOOTSTRAP_TRACING=1", // <- BOOTSTRAP_TRACING=1 won't enable tracing filter, but it will activate bootstrap's `tracing` feature
-    "python3",
-    "x.py",
-    "check",
-    "--json-output",
-    "--build-dir=build-rust-analyzer"
-],
-```
-
-```json
-"rust-analyzer.cargo.buildScripts.overrideCommand": [
-    "BOOTSTRAP_TRACING=1", // <- note this
-    "python3",
-    "x.py",
-    "check",
-    "--json-output",
-    "--build-dir=build-rust-analyzer"
-],
-```
+Unfortunately, because bootstrap is a `rust-analyzer.linkedProjects`, you can't ask r-a to check/build bootstrap itself with `tracing` feature enabled to get relevant completions, due to lack of support as described in <https://github.com/rust-lang/rust-analyzer/issues/8521>.
diff --git a/src/doc/rustc-dev-guide/src/building/bootstrapping/debugging-bootstrap/tracing-output-example.png b/src/doc/rustc-dev-guide/src/building/bootstrapping/debugging-bootstrap/tracing-output-example.png
deleted file mode 100644
index 745aec50d4a..00000000000
--- a/src/doc/rustc-dev-guide/src/building/bootstrapping/debugging-bootstrap/tracing-output-example.png
+++ /dev/null
Binary files differdiff --git a/src/librustdoc/html/templates/type_layout.html b/src/librustdoc/html/templates/type_layout.html
index aee96fb8c41..9c62826ccc2 100644
--- a/src/librustdoc/html/templates/type_layout.html
+++ b/src/librustdoc/html/templates/type_layout.html
@@ -28,13 +28,11 @@
         {% endfor %}
     </ul>
     {% endif %}
-    {# This kind of layout error can occur with valid code, e.g. if you try to
-    get the layout of a generic type such as `Vec<T>`. #}
+        {# This kind of layout error can occur with valid code, for example
+        if there are trivial bounds: `struct Foo(str, str) where str: Sized;`. #}
         {% when Err(LayoutError::Unknown(_)) %}
         <p> {# #}
-            <strong>Note:</strong> Unable to compute type layout, {#+ #}
-            possibly due to this type having generic parameters. {#+ #}
-            Layout can only be computed for concrete, fully-instantiated types. {# #}
+            <strong>Note:</strong> Unable to compute type layout. {# #}
         </p>
         {# This kind of error probably can't happen with valid code, but we don't
         want to panic and prevent the docs from building, so we just let the
@@ -44,6 +42,14 @@
             <strong>Note:</strong> Encountered an error during type layout; {#+ #}
             the type was too big. {# #}
         </p>
+        {# This kind of layout error can occur with valid code, e.g. if you try to
+        get the layout of a generic type such as `Vec<T>`. #}
+        {% when Err(LayoutError::TooGeneric(_)) %}
+        <p> {# #}
+            <strong>Note:</strong> Unable to compute type layout, {#+ #}
+            possibly due to this type having generic parameters. {#+ #}
+            Layout can only be computed for concrete, fully-instantiated types. {# #}
+        </p>
         {% when Err(LayoutError::ReferencesError(_)) %}
         <p> {# #}
             <strong>Note:</strong> Encountered an error during type layout; {#+ #}
diff --git a/src/tools/clippy/.github/driver.sh b/src/tools/clippy/.github/driver.sh
index 09202b1878b..701be6bd76d 100755
--- a/src/tools/clippy/.github/driver.sh
+++ b/src/tools/clippy/.github/driver.sh
@@ -47,9 +47,9 @@ unset CARGO_MANIFEST_DIR
 
 # Run a lint and make sure it produces the expected output. It's also expected to exit with code 1
 # FIXME: How to match the clippy invocation in compile-test.rs?
-./target/debug/clippy-driver -Dwarnings -Aunused -Zui-testing --emit metadata --crate-type bin tests/ui/double_neg.rs 2>double_neg.stderr && exit 1
-sed -e "/= help: for/d" double_neg.stderr > normalized.stderr
-diff -u normalized.stderr tests/ui/double_neg.stderr
+./target/debug/clippy-driver -Dwarnings -Aunused -Zui-testing --emit metadata --crate-type bin tests/ui/box_default.rs 2>box_default.stderr && exit 1
+sed -e "/= help: for/d" box_default.stderr > normalized.stderr
+diff -u normalized.stderr tests/ui/box_default.stderr
 
 # make sure "clippy-driver --rustc --arg" and "rustc --arg" behave the same
 SYSROOT=$(rustc --print sysroot)
diff --git a/src/tools/clippy/book/src/usage.md b/src/tools/clippy/book/src/usage.md
index 7a0be6994fe..23edf6c2aba 100644
--- a/src/tools/clippy/book/src/usage.md
+++ b/src/tools/clippy/book/src/usage.md
@@ -33,7 +33,7 @@ You can configure lint levels on the command line by adding
 `-A/W/D clippy::lint_name` like this:
 
 ```bash
-cargo clippy -- -Aclippy::style -Wclippy::double_neg -Dclippy::perf
+cargo clippy -- -Aclippy::style -Wclippy::box_default -Dclippy::perf
 ```
 
 For [CI] all warnings can be elevated to errors which will in turn fail
@@ -101,11 +101,10 @@ You can configure lint levels in source code the same way you can configure
 ```rust,ignore
 #![allow(clippy::style)]
 
-#[warn(clippy::double_neg)]
+#[warn(clippy::box_default)]
 fn main() {
-    let x = 1;
-    let y = --x;
-    //      ^^ warning: double negation
+    let _ = Box::<String>::new(Default::default());
+    // ^ warning: `Box::new(_)` of default value
 }
 ```
 
diff --git a/src/tools/clippy/clippy_dev/src/new_lint.rs b/src/tools/clippy/clippy_dev/src/new_lint.rs
index 24d1a53266a..35dd986ff61 100644
--- a/src/tools/clippy/clippy_dev/src/new_lint.rs
+++ b/src/tools/clippy/clippy_dev/src/new_lint.rs
@@ -455,7 +455,7 @@ fn setup_mod_file(path: &Path, lint: &LintData<'_>) -> io::Result<&'static str>
     });
 
     // Find both the last lint declaration (declare_clippy_lint!) and the lint pass impl
-    while let Some(LintDeclSearchResult { content, .. }) = iter.find(|result| result.token == TokenKind::Ident) {
+    while let Some(LintDeclSearchResult { content, .. }) = iter.find(|result| result.token_kind == TokenKind::Ident) {
         let mut iter = iter
             .by_ref()
             .filter(|t| !matches!(t.token_kind, TokenKind::Whitespace | TokenKind::LineComment { .. }));
@@ -465,7 +465,7 @@ fn setup_mod_file(path: &Path, lint: &LintData<'_>) -> io::Result<&'static str>
                 // matches `!{`
                 match_tokens!(iter, Bang OpenBrace);
                 if let Some(LintDeclSearchResult { range, .. }) =
-                    iter.find(|result| result.token == TokenKind::CloseBrace)
+                    iter.find(|result| result.token_kind == TokenKind::CloseBrace)
                 {
                     last_decl_curly_offset = Some(range.end);
                 }
diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs
index 3ff10d850f8..87e546fbf01 100644
--- a/src/tools/clippy/clippy_lints/src/declared_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs
@@ -507,7 +507,6 @@ pub static LINTS: &[&crate::LintInfo] = &[
     crate::misc::USED_UNDERSCORE_BINDING_INFO,
     crate::misc::USED_UNDERSCORE_ITEMS_INFO,
     crate::misc_early::BUILTIN_TYPE_SHADOW_INFO,
-    crate::misc_early::DOUBLE_NEG_INFO,
     crate::misc_early::DUPLICATE_UNDERSCORE_ARGUMENT_INFO,
     crate::misc_early::MIXED_CASE_HEX_LITERALS_INFO,
     crate::misc_early::REDUNDANT_AT_REST_PATTERN_INFO,
diff --git a/src/tools/clippy/clippy_lints/src/deprecated_lints.rs b/src/tools/clippy/clippy_lints/src/deprecated_lints.rs
index 3ea792d8b83..5604172d6f3 100644
--- a/src/tools/clippy/clippy_lints/src/deprecated_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/deprecated_lints.rs
@@ -129,6 +129,8 @@ declare_with_version! { RENAMED(RENAMED_VERSION): &[(&str, &str)] = &[
     ("clippy::clone_double_ref", "suspicious_double_ref_op"),
     #[clippy::version = ""]
     ("clippy::cmp_nan", "invalid_nan_comparisons"),
+    #[clippy::version = "1.86.0"]
+    ("clippy::double_neg", "double_negations"),
     #[clippy::version = ""]
     ("clippy::drop_bounds", "drop_bounds"),
     #[clippy::version = ""]
diff --git a/src/tools/clippy/clippy_lints/src/misc_early/double_neg.rs b/src/tools/clippy/clippy_lints/src/misc_early/double_neg.rs
deleted file mode 100644
index 06ba968fa4e..00000000000
--- a/src/tools/clippy/clippy_lints/src/misc_early/double_neg.rs
+++ /dev/null
@@ -1,18 +0,0 @@
-use clippy_utils::diagnostics::span_lint;
-use rustc_ast::ast::{Expr, ExprKind, UnOp};
-use rustc_lint::EarlyContext;
-
-use super::DOUBLE_NEG;
-
-pub(super) fn check(cx: &EarlyContext<'_>, expr: &Expr) {
-    if let ExprKind::Unary(UnOp::Neg, ref inner) = expr.kind {
-        if let ExprKind::Unary(UnOp::Neg, _) = inner.kind {
-            span_lint(
-                cx,
-                DOUBLE_NEG,
-                expr.span,
-                "`--x` could be misinterpreted as pre-decrement by C programmers, is usually a no-op",
-            );
-        }
-    }
-}
diff --git a/src/tools/clippy/clippy_lints/src/misc_early/mod.rs b/src/tools/clippy/clippy_lints/src/misc_early/mod.rs
index 37d7427f9a5..637d6ed3ad2 100644
--- a/src/tools/clippy/clippy_lints/src/misc_early/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/misc_early/mod.rs
@@ -1,5 +1,4 @@
 mod builtin_type_shadow;
-mod double_neg;
 mod literal_suffix;
 mod mixed_case_hex_literals;
 mod redundant_at_rest_pattern;
@@ -87,25 +86,6 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Detects expressions of the form `--x`.
-    ///
-    /// ### Why is this bad?
-    /// It can mislead C/C++ programmers to think `x` was
-    /// decremented.
-    ///
-    /// ### Example
-    /// ```no_run
-    /// let mut x = 3;
-    /// --x;
-    /// ```
-    #[clippy::version = "pre 1.29.0"]
-    pub DOUBLE_NEG,
-    style,
-    "`--x`, which is a double negation of `x` and not a pre-decrement as in C/C++"
-}
-
-declare_clippy_lint! {
-    /// ### What it does
     /// Warns on hexadecimal literals with mixed-case letter
     /// digits.
     ///
@@ -352,7 +332,6 @@ declare_clippy_lint! {
 declare_lint_pass!(MiscEarlyLints => [
     UNNEEDED_FIELD_PATTERN,
     DUPLICATE_UNDERSCORE_ARGUMENT,
-    DOUBLE_NEG,
     MIXED_CASE_HEX_LITERALS,
     UNSEPARATED_LITERAL_SUFFIX,
     SEPARATED_LITERAL_SUFFIX,
@@ -415,7 +394,6 @@ impl EarlyLintPass for MiscEarlyLints {
         if let ExprKind::Lit(lit) = expr.kind {
             MiscEarlyLints::check_lit(cx, lit, expr.span);
         }
-        double_neg::check(cx, expr);
     }
 }
 
diff --git a/src/tools/clippy/tests/ui/double_neg.rs b/src/tools/clippy/tests/ui/double_neg.rs
deleted file mode 100644
index 3be8c628873..00000000000
--- a/src/tools/clippy/tests/ui/double_neg.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-#[warn(clippy::double_neg)]
-#[allow(clippy::no_effect)]
-fn main() {
-    let x = 1;
-    -x;
-    -(-x);
-    --x;
-    //~^ ERROR: `--x` could be misinterpreted as pre-decrement by C programmers, is usually
-    //~| NOTE: `-D clippy::double-neg` implied by `-D warnings`
-}
diff --git a/src/tools/clippy/tests/ui/double_neg.stderr b/src/tools/clippy/tests/ui/double_neg.stderr
deleted file mode 100644
index 9a902d1323c..00000000000
--- a/src/tools/clippy/tests/ui/double_neg.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-error: `--x` could be misinterpreted as pre-decrement by C programmers, is usually a no-op
-  --> tests/ui/double_neg.rs:7:5
-   |
-LL |     --x;
-   |     ^^^
-   |
-   = note: `-D clippy::double-neg` implied by `-D warnings`
-   = help: to override `-D warnings` add `#[allow(clippy::double_neg)]`
-
-error: aborting due to 1 previous error
-
diff --git a/src/tools/clippy/tests/ui/rename.fixed b/src/tools/clippy/tests/ui/rename.fixed
index 47d6e119543..501811fa491 100644
--- a/src/tools/clippy/tests/ui/rename.fixed
+++ b/src/tools/clippy/tests/ui/rename.fixed
@@ -13,9 +13,8 @@
 #![allow(clippy::disallowed_methods)]
 #![allow(clippy::disallowed_types)]
 #![allow(clippy::mixed_read_write_in_expression)]
-#![allow(clippy::manual_find_map)]
 #![allow(clippy::manual_filter_map)]
-#![allow(unpredictable_function_pointer_comparisons)]
+#![allow(clippy::manual_find_map)]
 #![allow(clippy::useless_conversion)]
 #![allow(clippy::redundant_pattern_matching)]
 #![allow(clippy::match_result_ok)]
@@ -30,6 +29,7 @@
 #![allow(clippy::unwrap_used)]
 #![allow(clippy::panicking_overflow_checks)]
 #![allow(clippy::needless_borrow)]
+#![allow(clippy::reversed_empty_ranges)]
 #![allow(clippy::single_char_add_str)]
 #![allow(clippy::module_name_repetitions)]
 #![allow(clippy::missing_const_for_thread_local)]
@@ -39,9 +39,11 @@
 #![allow(invalid_reference_casting)]
 #![allow(suspicious_double_ref_op)]
 #![allow(invalid_nan_comparisons)]
+#![allow(double_negations)]
 #![allow(drop_bounds)]
 #![allow(dropping_copy_types)]
 #![allow(dropping_references)]
+#![allow(unpredictable_function_pointer_comparisons)]
 #![allow(useless_ptr_null_checks)]
 #![allow(for_loops_over_fallibles)]
 #![allow(forgetting_copy_types)]
@@ -60,8 +62,6 @@
 #![allow(unknown_lints)]
 #![allow(unused_labels)]
 #![allow(ambiguous_wide_pointer_comparisons)]
-#![allow(unpredictable_function_pointer_comparisons)]
-#![allow(clippy::reversed_empty_ranges)]
 #![warn(clippy::almost_complete_range)] //~ ERROR: lint `clippy::almost_complete_letter_range`
 #![warn(clippy::disallowed_names)] //~ ERROR: lint `clippy::blacklisted_name`
 #![warn(clippy::blocks_in_conditions)] //~ ERROR: lint `clippy::block_in_if_condition_expr`
@@ -74,9 +74,8 @@
 #![warn(clippy::disallowed_methods)] //~ ERROR: lint `clippy::disallowed_method`
 #![warn(clippy::disallowed_types)] //~ ERROR: lint `clippy::disallowed_type`
 #![warn(clippy::mixed_read_write_in_expression)] //~ ERROR: lint `clippy::eval_order_dependence`
-#![warn(clippy::manual_find_map)] //~ ERROR: lint `clippy::find_map`
 #![warn(clippy::manual_filter_map)] //~ ERROR: lint `clippy::filter_map`
-#![warn(unpredictable_function_pointer_comparisons)] //~ ERROR: lint `clippy::fn_address_comparisons`
+#![warn(clippy::manual_find_map)] //~ ERROR: lint `clippy::find_map`
 #![warn(clippy::useless_conversion)] //~ ERROR: lint `clippy::identity_conversion`
 #![warn(clippy::redundant_pattern_matching)] //~ ERROR: lint `clippy::if_let_redundant_pattern_matching`
 #![warn(clippy::match_result_ok)] //~ ERROR: lint `clippy::if_let_some_result`
@@ -95,6 +94,7 @@
 #![warn(clippy::expect_used)] //~ ERROR: lint `clippy::result_expect_used`
 #![warn(clippy::map_unwrap_or)] //~ ERROR: lint `clippy::result_map_unwrap_or_else`
 #![warn(clippy::unwrap_used)] //~ ERROR: lint `clippy::result_unwrap_used`
+#![warn(clippy::reversed_empty_ranges)] //~ ERROR: lint `clippy::reverse_range_loop`
 #![warn(clippy::single_char_add_str)] //~ ERROR: lint `clippy::single_char_push_str`
 #![warn(clippy::module_name_repetitions)] //~ ERROR: lint `clippy::stutter`
 #![warn(clippy::missing_const_for_thread_local)] //~ ERROR: lint `clippy::thread_local_initializer_can_be_made_const`
@@ -104,9 +104,11 @@
 #![warn(invalid_reference_casting)] //~ ERROR: lint `clippy::cast_ref_to_mut`
 #![warn(suspicious_double_ref_op)] //~ ERROR: lint `clippy::clone_double_ref`
 #![warn(invalid_nan_comparisons)] //~ ERROR: lint `clippy::cmp_nan`
+#![warn(double_negations)] //~ ERROR: lint `clippy::double_neg`
 #![warn(drop_bounds)] //~ ERROR: lint `clippy::drop_bounds`
 #![warn(dropping_copy_types)] //~ ERROR: lint `clippy::drop_copy`
 #![warn(dropping_references)] //~ ERROR: lint `clippy::drop_ref`
+#![warn(unpredictable_function_pointer_comparisons)] //~ ERROR: lint `clippy::fn_address_comparisons`
 #![warn(useless_ptr_null_checks)] //~ ERROR: lint `clippy::fn_null_check`
 #![warn(for_loops_over_fallibles)] //~ ERROR: lint `clippy::for_loop_over_option`
 #![warn(for_loops_over_fallibles)] //~ ERROR: lint `clippy::for_loop_over_result`
@@ -128,6 +130,5 @@
 #![warn(unknown_lints)] //~ ERROR: lint `clippy::unknown_clippy_lints`
 #![warn(unused_labels)] //~ ERROR: lint `clippy::unused_label`
 #![warn(ambiguous_wide_pointer_comparisons)] //~ ERROR: lint `clippy::vtable_address_comparisons`
-#![warn(clippy::reversed_empty_ranges)] //~ ERROR: lint `clippy::reverse_range_loop`
 
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/rename.rs b/src/tools/clippy/tests/ui/rename.rs
index 12c7db69be2..7f4b8062e1b 100644
--- a/src/tools/clippy/tests/ui/rename.rs
+++ b/src/tools/clippy/tests/ui/rename.rs
@@ -13,9 +13,8 @@
 #![allow(clippy::disallowed_methods)]
 #![allow(clippy::disallowed_types)]
 #![allow(clippy::mixed_read_write_in_expression)]
-#![allow(clippy::manual_find_map)]
 #![allow(clippy::manual_filter_map)]
-#![allow(unpredictable_function_pointer_comparisons)]
+#![allow(clippy::manual_find_map)]
 #![allow(clippy::useless_conversion)]
 #![allow(clippy::redundant_pattern_matching)]
 #![allow(clippy::match_result_ok)]
@@ -30,6 +29,7 @@
 #![allow(clippy::unwrap_used)]
 #![allow(clippy::panicking_overflow_checks)]
 #![allow(clippy::needless_borrow)]
+#![allow(clippy::reversed_empty_ranges)]
 #![allow(clippy::single_char_add_str)]
 #![allow(clippy::module_name_repetitions)]
 #![allow(clippy::missing_const_for_thread_local)]
@@ -39,9 +39,11 @@
 #![allow(invalid_reference_casting)]
 #![allow(suspicious_double_ref_op)]
 #![allow(invalid_nan_comparisons)]
+#![allow(double_negations)]
 #![allow(drop_bounds)]
 #![allow(dropping_copy_types)]
 #![allow(dropping_references)]
+#![allow(unpredictable_function_pointer_comparisons)]
 #![allow(useless_ptr_null_checks)]
 #![allow(for_loops_over_fallibles)]
 #![allow(forgetting_copy_types)]
@@ -60,8 +62,6 @@
 #![allow(unknown_lints)]
 #![allow(unused_labels)]
 #![allow(ambiguous_wide_pointer_comparisons)]
-#![allow(unpredictable_function_pointer_comparisons)]
-#![allow(clippy::reversed_empty_ranges)]
 #![warn(clippy::almost_complete_letter_range)] //~ ERROR: lint `clippy::almost_complete_letter_range`
 #![warn(clippy::blacklisted_name)] //~ ERROR: lint `clippy::blacklisted_name`
 #![warn(clippy::block_in_if_condition_expr)] //~ ERROR: lint `clippy::block_in_if_condition_expr`
@@ -74,9 +74,8 @@
 #![warn(clippy::disallowed_method)] //~ ERROR: lint `clippy::disallowed_method`
 #![warn(clippy::disallowed_type)] //~ ERROR: lint `clippy::disallowed_type`
 #![warn(clippy::eval_order_dependence)] //~ ERROR: lint `clippy::eval_order_dependence`
-#![warn(clippy::find_map)] //~ ERROR: lint `clippy::find_map`
 #![warn(clippy::filter_map)] //~ ERROR: lint `clippy::filter_map`
-#![warn(clippy::fn_address_comparisons)] //~ ERROR: lint `clippy::fn_address_comparisons`
+#![warn(clippy::find_map)] //~ ERROR: lint `clippy::find_map`
 #![warn(clippy::identity_conversion)] //~ ERROR: lint `clippy::identity_conversion`
 #![warn(clippy::if_let_redundant_pattern_matching)] //~ ERROR: lint `clippy::if_let_redundant_pattern_matching`
 #![warn(clippy::if_let_some_result)] //~ ERROR: lint `clippy::if_let_some_result`
@@ -95,6 +94,7 @@
 #![warn(clippy::result_expect_used)] //~ ERROR: lint `clippy::result_expect_used`
 #![warn(clippy::result_map_unwrap_or_else)] //~ ERROR: lint `clippy::result_map_unwrap_or_else`
 #![warn(clippy::result_unwrap_used)] //~ ERROR: lint `clippy::result_unwrap_used`
+#![warn(clippy::reverse_range_loop)] //~ ERROR: lint `clippy::reverse_range_loop`
 #![warn(clippy::single_char_push_str)] //~ ERROR: lint `clippy::single_char_push_str`
 #![warn(clippy::stutter)] //~ ERROR: lint `clippy::stutter`
 #![warn(clippy::thread_local_initializer_can_be_made_const)] //~ ERROR: lint `clippy::thread_local_initializer_can_be_made_const`
@@ -104,9 +104,11 @@
 #![warn(clippy::cast_ref_to_mut)] //~ ERROR: lint `clippy::cast_ref_to_mut`
 #![warn(clippy::clone_double_ref)] //~ ERROR: lint `clippy::clone_double_ref`
 #![warn(clippy::cmp_nan)] //~ ERROR: lint `clippy::cmp_nan`
+#![warn(clippy::double_neg)] //~ ERROR: lint `clippy::double_neg`
 #![warn(clippy::drop_bounds)] //~ ERROR: lint `clippy::drop_bounds`
 #![warn(clippy::drop_copy)] //~ ERROR: lint `clippy::drop_copy`
 #![warn(clippy::drop_ref)] //~ ERROR: lint `clippy::drop_ref`
+#![warn(clippy::fn_address_comparisons)] //~ ERROR: lint `clippy::fn_address_comparisons`
 #![warn(clippy::fn_null_check)] //~ ERROR: lint `clippy::fn_null_check`
 #![warn(clippy::for_loop_over_option)] //~ ERROR: lint `clippy::for_loop_over_option`
 #![warn(clippy::for_loop_over_result)] //~ ERROR: lint `clippy::for_loop_over_result`
@@ -128,6 +130,5 @@
 #![warn(clippy::unknown_clippy_lints)] //~ ERROR: lint `clippy::unknown_clippy_lints`
 #![warn(clippy::unused_label)] //~ ERROR: lint `clippy::unused_label`
 #![warn(clippy::vtable_address_comparisons)] //~ ERROR: lint `clippy::vtable_address_comparisons`
-#![warn(clippy::reverse_range_loop)] //~ ERROR: lint `clippy::reverse_range_loop`
 
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/rename.stderr b/src/tools/clippy/tests/ui/rename.stderr
index 1ec45c4f1f7..f24eaec3917 100644
--- a/src/tools/clippy/tests/ui/rename.stderr
+++ b/src/tools/clippy/tests/ui/rename.stderr
@@ -73,132 +73,132 @@ error: lint `clippy::eval_order_dependence` has been renamed to `clippy::mixed_r
 LL | #![warn(clippy::eval_order_dependence)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression`
 
-error: lint `clippy::find_map` has been renamed to `clippy::manual_find_map`
-  --> tests/ui/rename.rs:77:9
-   |
-LL | #![warn(clippy::find_map)]
-   |         ^^^^^^^^^^^^^^^^ help: use the new name: `clippy::manual_find_map`
-
 error: lint `clippy::filter_map` has been renamed to `clippy::manual_filter_map`
-  --> tests/ui/rename.rs:78:9
+  --> tests/ui/rename.rs:77:9
    |
 LL | #![warn(clippy::filter_map)]
    |         ^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::manual_filter_map`
 
-error: lint `clippy::fn_address_comparisons` has been renamed to `unpredictable_function_pointer_comparisons`
-  --> tests/ui/rename.rs:79:9
+error: lint `clippy::find_map` has been renamed to `clippy::manual_find_map`
+  --> tests/ui/rename.rs:78:9
    |
-LL | #![warn(clippy::fn_address_comparisons)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unpredictable_function_pointer_comparisons`
+LL | #![warn(clippy::find_map)]
+   |         ^^^^^^^^^^^^^^^^ help: use the new name: `clippy::manual_find_map`
 
 error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion`
-  --> tests/ui/rename.rs:80:9
+  --> tests/ui/rename.rs:79:9
    |
 LL | #![warn(clippy::identity_conversion)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion`
 
 error: lint `clippy::if_let_redundant_pattern_matching` has been renamed to `clippy::redundant_pattern_matching`
-  --> tests/ui/rename.rs:81:9
+  --> tests/ui/rename.rs:80:9
    |
 LL | #![warn(clippy::if_let_redundant_pattern_matching)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_pattern_matching`
 
 error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok`
-  --> tests/ui/rename.rs:82:9
+  --> tests/ui/rename.rs:81:9
    |
 LL | #![warn(clippy::if_let_some_result)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok`
 
 error: lint `clippy::incorrect_clone_impl_on_copy_type` has been renamed to `clippy::non_canonical_clone_impl`
-  --> tests/ui/rename.rs:83:9
+  --> tests/ui/rename.rs:82:9
    |
 LL | #![warn(clippy::incorrect_clone_impl_on_copy_type)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::non_canonical_clone_impl`
 
 error: lint `clippy::incorrect_partial_ord_impl_on_ord_type` has been renamed to `clippy::non_canonical_partial_ord_impl`
-  --> tests/ui/rename.rs:84:9
+  --> tests/ui/rename.rs:83:9
    |
 LL | #![warn(clippy::incorrect_partial_ord_impl_on_ord_type)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::non_canonical_partial_ord_impl`
 
 error: lint `clippy::integer_arithmetic` has been renamed to `clippy::arithmetic_side_effects`
-  --> tests/ui/rename.rs:85:9
+  --> tests/ui/rename.rs:84:9
    |
 LL | #![warn(clippy::integer_arithmetic)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::arithmetic_side_effects`
 
 error: lint `clippy::logic_bug` has been renamed to `clippy::overly_complex_bool_expr`
-  --> tests/ui/rename.rs:86:9
+  --> tests/ui/rename.rs:85:9
    |
 LL | #![warn(clippy::logic_bug)]
    |         ^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::overly_complex_bool_expr`
 
 error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default`
-  --> tests/ui/rename.rs:87:9
+  --> tests/ui/rename.rs:86:9
    |
 LL | #![warn(clippy::new_without_default_derive)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default`
 
 error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map`
-  --> tests/ui/rename.rs:88:9
+  --> tests/ui/rename.rs:87:9
    |
 LL | #![warn(clippy::option_and_then_some)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map`
 
 error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used`
-  --> tests/ui/rename.rs:89:9
+  --> tests/ui/rename.rs:88:9
    |
 LL | #![warn(clippy::option_expect_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
 
 error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or`
-  --> tests/ui/rename.rs:90:9
+  --> tests/ui/rename.rs:89:9
    |
 LL | #![warn(clippy::option_map_unwrap_or)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
 error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
-  --> tests/ui/rename.rs:91:9
+  --> tests/ui/rename.rs:90:9
    |
 LL | #![warn(clippy::option_map_unwrap_or_else)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
 error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used`
-  --> tests/ui/rename.rs:92:9
+  --> tests/ui/rename.rs:91:9
    |
 LL | #![warn(clippy::option_unwrap_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
 
 error: lint `clippy::overflow_check_conditional` has been renamed to `clippy::panicking_overflow_checks`
-  --> tests/ui/rename.rs:93:9
+  --> tests/ui/rename.rs:92:9
    |
 LL | #![warn(clippy::overflow_check_conditional)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::panicking_overflow_checks`
 
 error: lint `clippy::ref_in_deref` has been renamed to `clippy::needless_borrow`
-  --> tests/ui/rename.rs:94:9
+  --> tests/ui/rename.rs:93:9
    |
 LL | #![warn(clippy::ref_in_deref)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::needless_borrow`
 
 error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used`
-  --> tests/ui/rename.rs:95:9
+  --> tests/ui/rename.rs:94:9
    |
 LL | #![warn(clippy::result_expect_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
 
 error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
-  --> tests/ui/rename.rs:96:9
+  --> tests/ui/rename.rs:95:9
    |
 LL | #![warn(clippy::result_map_unwrap_or_else)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
 error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used`
-  --> tests/ui/rename.rs:97:9
+  --> tests/ui/rename.rs:96:9
    |
 LL | #![warn(clippy::result_unwrap_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
 
+error: lint `clippy::reverse_range_loop` has been renamed to `clippy::reversed_empty_ranges`
+  --> tests/ui/rename.rs:97:9
+   |
+LL | #![warn(clippy::reverse_range_loop)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::reversed_empty_ranges`
+
 error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str`
   --> tests/ui/rename.rs:98:9
    |
@@ -253,155 +253,161 @@ error: lint `clippy::cmp_nan` has been renamed to `invalid_nan_comparisons`
 LL | #![warn(clippy::cmp_nan)]
    |         ^^^^^^^^^^^^^^^ help: use the new name: `invalid_nan_comparisons`
 
-error: lint `clippy::drop_bounds` has been renamed to `drop_bounds`
+error: lint `clippy::double_neg` has been renamed to `double_negations`
   --> tests/ui/rename.rs:107:9
    |
+LL | #![warn(clippy::double_neg)]
+   |         ^^^^^^^^^^^^^^^^^^ help: use the new name: `double_negations`
+
+error: lint `clippy::drop_bounds` has been renamed to `drop_bounds`
+  --> tests/ui/rename.rs:108:9
+   |
 LL | #![warn(clippy::drop_bounds)]
    |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds`
 
 error: lint `clippy::drop_copy` has been renamed to `dropping_copy_types`
-  --> tests/ui/rename.rs:108:9
+  --> tests/ui/rename.rs:109:9
    |
 LL | #![warn(clippy::drop_copy)]
    |         ^^^^^^^^^^^^^^^^^ help: use the new name: `dropping_copy_types`
 
 error: lint `clippy::drop_ref` has been renamed to `dropping_references`
-  --> tests/ui/rename.rs:109:9
+  --> tests/ui/rename.rs:110:9
    |
 LL | #![warn(clippy::drop_ref)]
    |         ^^^^^^^^^^^^^^^^ help: use the new name: `dropping_references`
 
+error: lint `clippy::fn_address_comparisons` has been renamed to `unpredictable_function_pointer_comparisons`
+  --> tests/ui/rename.rs:111:9
+   |
+LL | #![warn(clippy::fn_address_comparisons)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unpredictable_function_pointer_comparisons`
+
 error: lint `clippy::fn_null_check` has been renamed to `useless_ptr_null_checks`
-  --> tests/ui/rename.rs:110:9
+  --> tests/ui/rename.rs:112:9
    |
 LL | #![warn(clippy::fn_null_check)]
    |         ^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `useless_ptr_null_checks`
 
 error: lint `clippy::for_loop_over_option` has been renamed to `for_loops_over_fallibles`
-  --> tests/ui/rename.rs:111:9
+  --> tests/ui/rename.rs:113:9
    |
 LL | #![warn(clippy::for_loop_over_option)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 
 error: lint `clippy::for_loop_over_result` has been renamed to `for_loops_over_fallibles`
-  --> tests/ui/rename.rs:112:9
+  --> tests/ui/rename.rs:114:9
    |
 LL | #![warn(clippy::for_loop_over_result)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 
 error: lint `clippy::for_loops_over_fallibles` has been renamed to `for_loops_over_fallibles`
-  --> tests/ui/rename.rs:113:9
+  --> tests/ui/rename.rs:115:9
    |
 LL | #![warn(clippy::for_loops_over_fallibles)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 
 error: lint `clippy::forget_copy` has been renamed to `forgetting_copy_types`
-  --> tests/ui/rename.rs:114:9
+  --> tests/ui/rename.rs:116:9
    |
 LL | #![warn(clippy::forget_copy)]
    |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_copy_types`
 
 error: lint `clippy::forget_ref` has been renamed to `forgetting_references`
-  --> tests/ui/rename.rs:115:9
+  --> tests/ui/rename.rs:117:9
    |
 LL | #![warn(clippy::forget_ref)]
    |         ^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_references`
 
 error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter`
-  --> tests/ui/rename.rs:116:9
+  --> tests/ui/rename.rs:118:9
    |
 LL | #![warn(clippy::into_iter_on_array)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter`
 
 error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering`
-  --> tests/ui/rename.rs:117:9
+  --> tests/ui/rename.rs:119:9
    |
 LL | #![warn(clippy::invalid_atomic_ordering)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering`
 
 error: lint `clippy::invalid_ref` has been renamed to `invalid_value`
-  --> tests/ui/rename.rs:118:9
+  --> tests/ui/rename.rs:120:9
    |
 LL | #![warn(clippy::invalid_ref)]
    |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value`
 
 error: lint `clippy::invalid_utf8_in_unchecked` has been renamed to `invalid_from_utf8_unchecked`
-  --> tests/ui/rename.rs:119:9
+  --> tests/ui/rename.rs:121:9
    |
 LL | #![warn(clippy::invalid_utf8_in_unchecked)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_from_utf8_unchecked`
 
 error: lint `clippy::let_underscore_drop` has been renamed to `let_underscore_drop`
-  --> tests/ui/rename.rs:120:9
+  --> tests/ui/rename.rs:122:9
    |
 LL | #![warn(clippy::let_underscore_drop)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `let_underscore_drop`
 
 error: lint `clippy::maybe_misused_cfg` has been renamed to `unexpected_cfgs`
-  --> tests/ui/rename.rs:121:9
+  --> tests/ui/rename.rs:123:9
    |
 LL | #![warn(clippy::maybe_misused_cfg)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unexpected_cfgs`
 
 error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums`
-  --> tests/ui/rename.rs:122:9
+  --> tests/ui/rename.rs:124:9
    |
 LL | #![warn(clippy::mem_discriminant_non_enum)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums`
 
 error: lint `clippy::mismatched_target_os` has been renamed to `unexpected_cfgs`
-  --> tests/ui/rename.rs:123:9
+  --> tests/ui/rename.rs:125:9
    |
 LL | #![warn(clippy::mismatched_target_os)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unexpected_cfgs`
 
 error: lint `clippy::panic_params` has been renamed to `non_fmt_panics`
-  --> tests/ui/rename.rs:124:9
+  --> tests/ui/rename.rs:126:9
    |
 LL | #![warn(clippy::panic_params)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics`
 
 error: lint `clippy::positional_named_format_parameters` has been renamed to `named_arguments_used_positionally`
-  --> tests/ui/rename.rs:125:9
+  --> tests/ui/rename.rs:127:9
    |
 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 `dangling_pointers_from_temporaries`
-  --> tests/ui/rename.rs:126:9
+  --> tests/ui/rename.rs:128:9
    |
 LL | #![warn(clippy::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:127:9
+  --> tests/ui/rename.rs:129:9
    |
 LL | #![warn(clippy::undropped_manually_drops)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `undropped_manually_drops`
 
 error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints`
-  --> tests/ui/rename.rs:128:9
+  --> tests/ui/rename.rs:130:9
    |
 LL | #![warn(clippy::unknown_clippy_lints)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints`
 
 error: lint `clippy::unused_label` has been renamed to `unused_labels`
-  --> tests/ui/rename.rs:129:9
+  --> tests/ui/rename.rs:131:9
    |
 LL | #![warn(clippy::unused_label)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels`
 
 error: lint `clippy::vtable_address_comparisons` has been renamed to `ambiguous_wide_pointer_comparisons`
-  --> tests/ui/rename.rs:130:9
+  --> tests/ui/rename.rs:132:9
    |
 LL | #![warn(clippy::vtable_address_comparisons)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `ambiguous_wide_pointer_comparisons`
 
-error: lint `clippy::reverse_range_loop` has been renamed to `clippy::reversed_empty_ranges`
-  --> tests/ui/rename.rs:131:9
-   |
-LL | #![warn(clippy::reverse_range_loop)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::reversed_empty_ranges`
-
-error: aborting due to 67 previous errors
+error: aborting due to 68 previous errors
 
diff --git a/tests/crashes/108428.rs b/tests/crashes/108428.rs
new file mode 100644
index 00000000000..b18123b6a7c
--- /dev/null
+++ b/tests/crashes/108428.rs
@@ -0,0 +1,6 @@
+//@ known-bug: #108428
+//@ needs-rustc-debug-assertions
+//@ compile-flags: -Wunused-lifetimes
+fn main() {
+    let _: extern fn<'a: 'static>();
+}
diff --git a/tests/crashes/132826.rs b/tests/crashes/132826.rs
new file mode 100644
index 00000000000..9889cecdac5
--- /dev/null
+++ b/tests/crashes/132826.rs
@@ -0,0 +1,10 @@
+//@ known-bug: #132826
+pub trait MyTrait {
+    type Item;
+}
+
+impl<K> MyTrait for Vec<K> {
+    type Item = Vec<K>;
+}
+
+impl<K> From<Vec<K>> for <Vec<K> as MyTrait>::Item {}
diff --git a/tests/crashes/135020.rs b/tests/crashes/135020.rs
deleted file mode 100644
index b44056eb3af..00000000000
--- a/tests/crashes/135020.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-//@ known-bug: #135020
-
-pub fn problem_thingy(items: &mut impl Iterator<Item = str>) {
-    let mut peeker = items.peekable();
-    match peeker.peek() {
-        Some(_) => (),
-        None => return (),
-    }
-}
-
-pub fn main() {}
diff --git a/tests/rustdoc/type-layout.rs b/tests/rustdoc/type-layout.rs
index 1e462210cba..5f34c8b99e0 100644
--- a/tests/rustdoc/type-layout.rs
+++ b/tests/rustdoc/type-layout.rs
@@ -37,7 +37,8 @@ pub struct Y(u8);
 pub struct Z;
 
 // We can't compute layout for generic types.
-//@ hasraw type_layout/struct.Generic.html 'Unable to compute type layout, possibly due to this type having generic parameters'
+//@ hasraw type_layout/struct.Generic.html 'Unable to compute type layout, possibly due to this type having generic parameters.'
+//@ hasraw type_layout/struct.Generic.html 'Layout can only be computed for concrete, fully-instantiated types.'
 //@ !hasraw - 'Size: '
 pub struct Generic<T>(T);
 
@@ -91,3 +92,9 @@ pub enum Uninhabited {}
 //@ hasraw type_layout/struct.Uninhabited2.html 'Size: '
 //@ hasraw - '8 bytes (<a href="https://doc.rust-lang.org/stable/reference/glossary.html#uninhabited">uninhabited</a>)'
 pub struct Uninhabited2(std::convert::Infallible, u64);
+
+pub trait Project { type Assoc; }
+// We can't compute layout. A `LayoutError::Unknown` is returned.
+//@ hasraw type_layout/struct.Unknown.html 'Unable to compute type layout.'
+//@ !hasraw - 'Size: '
+pub struct Unknown(<() as Project>::Assoc) where for<'a> (): Project;
diff --git a/tests/ui/enum-discriminant/eval-error.rs b/tests/ui/enum-discriminant/eval-error.rs
index f2c3b581627..08b71d52a8b 100644
--- a/tests/ui/enum-discriminant/eval-error.rs
+++ b/tests/ui/enum-discriminant/eval-error.rs
@@ -6,7 +6,7 @@ union Foo {
 
 enum Bar {
     Boo = {
-        let _: Option<Foo> = None;
+        let _: Option<Foo> = None; //~ ERROR evaluation of constant value failed
         0
     },
 }
diff --git a/tests/ui/enum-discriminant/eval-error.stderr b/tests/ui/enum-discriminant/eval-error.stderr
index 0f12308de3c..6bec2c8b420 100644
--- a/tests/ui/enum-discriminant/eval-error.stderr
+++ b/tests/ui/enum-discriminant/eval-error.stderr
@@ -45,7 +45,13 @@ help: wrap the field type in `ManuallyDrop<...>`
 LL |     a: std::mem::ManuallyDrop<str>,
    |        +++++++++++++++++++++++   +
 
-error: aborting due to 4 previous errors
+error[E0080]: evaluation of constant value failed
+  --> $DIR/eval-error.rs:9:30
+   |
+LL |         let _: Option<Foo> = None;
+   |                              ^^^^ the type `Foo` has an unknown layout
+
+error: aborting due to 5 previous errors
 
-Some errors have detailed explanations: E0277, E0517, E0740.
-For more information about an error, try `rustc --explain E0277`.
+Some errors have detailed explanations: E0080, E0277, E0517, E0740.
+For more information about an error, try `rustc --explain E0080`.
diff --git a/tests/ui/infinite/infinite-instantiation-struct-tail-ice-114484.rs b/tests/ui/infinite/infinite-instantiation-struct-tail-ice-114484.rs
index 410862c5326..e28b8f373da 100644
--- a/tests/ui/infinite/infinite-instantiation-struct-tail-ice-114484.rs
+++ b/tests/ui/infinite/infinite-instantiation-struct-tail-ice-114484.rs
@@ -24,7 +24,7 @@ impl<T, const L: u8> VirtualWrapper<T, L> {
 impl<T: MyTrait + 'static, const L: u8> MyTrait for VirtualWrapper<T, L> {
     fn virtualize(&self) -> &dyn MyTrait {
         unsafe { virtualize_my_trait(L, self) }
-        // unsafe { virtualize_my_trait(L, &self.0) }    // <-- this code fixes the problem
+        // unsafe { virtualize_my_trait(L, &self.0) } // <-- this code fixes the problem
     }
 }
 
diff --git a/tests/ui/layout/base-layout-is-sized-ice-123078.rs b/tests/ui/layout/base-layout-is-sized-ice-123078.rs
index 15f11145f84..b1c33e15075 100644
--- a/tests/ui/layout/base-layout-is-sized-ice-123078.rs
+++ b/tests/ui/layout/base-layout-is-sized-ice-123078.rs
@@ -8,6 +8,7 @@ struct S {
 }
 
 const C: S = unsafe { std::mem::transmute(()) };
+//~^ ERROR cannot transmute between types of different sizes, or dependently-sized types
 const _: [(); {
     C;
     0
diff --git a/tests/ui/layout/base-layout-is-sized-ice-123078.stderr b/tests/ui/layout/base-layout-is-sized-ice-123078.stderr
index 9181368533a..d8743d4e6d6 100644
--- a/tests/ui/layout/base-layout-is-sized-ice-123078.stderr
+++ b/tests/ui/layout/base-layout-is-sized-ice-123078.stderr
@@ -16,6 +16,16 @@ help: the `Box` type always has a statically known size and allocates its conten
 LL |     a: Box<[u8]>,
    |        ++++    +
 
-error: aborting due to 1 previous error
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> $DIR/base-layout-is-sized-ice-123078.rs:10:23
+   |
+LL | const C: S = unsafe { std::mem::transmute(()) };
+   |                       ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `()` (0 bits)
+   = note: target type: `S` (the type `S` has an unknown layout)
+
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0277`.
+Some errors have detailed explanations: E0277, E0512.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/layout/invalid-unsized-const-eval.rs b/tests/ui/layout/invalid-unsized-const-eval.rs
index 2dec0b0faac..1f664d30055 100644
--- a/tests/ui/layout/invalid-unsized-const-eval.rs
+++ b/tests/ui/layout/invalid-unsized-const-eval.rs
@@ -10,5 +10,6 @@ struct LazyLock {
 }
 
 static EMPTY_SET: LazyLock = todo!();
+//~^ ERROR could not evaluate static initializer
 
 fn main() {}
diff --git a/tests/ui/layout/invalid-unsized-const-eval.stderr b/tests/ui/layout/invalid-unsized-const-eval.stderr
index bf65782b7a8..a434ca9b2c7 100644
--- a/tests/ui/layout/invalid-unsized-const-eval.stderr
+++ b/tests/ui/layout/invalid-unsized-const-eval.stderr
@@ -7,6 +7,13 @@ LL |     data: (dyn Sync, ()),
    = help: the trait `Sized` is not implemented for `(dyn Sync + 'static)`
    = note: only the last element of a tuple may have a dynamically sized type
 
-error: aborting due to 1 previous error
+error[E0080]: could not evaluate static initializer
+  --> $DIR/invalid-unsized-const-eval.rs:12:1
+   |
+LL | static EMPTY_SET: LazyLock = todo!();
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^ the type `(dyn Sync, ())` has an unknown layout
+
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0277`.
+Some errors have detailed explanations: E0080, E0277.
+For more information about an error, try `rustc --explain E0080`.
diff --git a/tests/ui/layout/invalid-unsized-in-always-sized-tail.stderr b/tests/ui/layout/invalid-unsized-in-always-sized-tail.stderr
index 3f565d6ee5b..f54e97e2a5c 100644
--- a/tests/ui/layout/invalid-unsized-in-always-sized-tail.stderr
+++ b/tests/ui/layout/invalid-unsized-in-always-sized-tail.stderr
@@ -18,6 +18,20 @@ LL | struct MySlice<T>(T);
    |                |
    |                this could be changed to `T: ?Sized`...
 
-error: aborting due to 1 previous error
+error[E0080]: could not evaluate static initializer
+  --> $SRC_DIR/core/src/mem/mod.rs:LL:COL
+   |
+   = note: the type `MySlice<[bool]>` has an unknown layout
+   |
+note: inside `align_of::<P2>`
+  --> $SRC_DIR/core/src/mem/mod.rs:LL:COL
+note: inside `CHECK`
+  --> $DIR/invalid-unsized-in-always-sized-tail.rs:15:28
+   |
+LL | static CHECK: () = assert!(align_of::<P2>() == 1);
+   |                            ^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0277`.
+Some errors have detailed explanations: E0080, E0277.
+For more information about an error, try `rustc --explain E0080`.
diff --git a/tests/ui/layout/issue-unsized-tail-restatic-ice-122488.rs b/tests/ui/layout/issue-unsized-tail-restatic-ice-122488.rs
index 96c993035ef..f84c10d8e5c 100644
--- a/tests/ui/layout/issue-unsized-tail-restatic-ice-122488.rs
+++ b/tests/ui/layout/issue-unsized-tail-restatic-ice-122488.rs
@@ -6,5 +6,6 @@ struct ArenaSet<U: Deref, V: ?Sized = <U as Deref>::Target>(V, U);
 //~^ ERROR the size for values of type `V` cannot be known at compilation time
 
 const DATA: *const ArenaSet<Vec<u8>> = std::ptr::null_mut();
+//~^ ERROR evaluation of constant value failed
 
 pub fn main() {}
diff --git a/tests/ui/layout/issue-unsized-tail-restatic-ice-122488.stderr b/tests/ui/layout/issue-unsized-tail-restatic-ice-122488.stderr
index f39cb29868a..220951fab86 100644
--- a/tests/ui/layout/issue-unsized-tail-restatic-ice-122488.stderr
+++ b/tests/ui/layout/issue-unsized-tail-restatic-ice-122488.stderr
@@ -22,6 +22,13 @@ help: the `Box` type always has a statically known size and allocates its conten
 LL | struct ArenaSet<U: Deref, V: ?Sized = <U as Deref>::Target>(Box<V>, U);
    |                                                             ++++ +
 
-error: aborting due to 1 previous error
+error[E0080]: evaluation of constant value failed
+  --> $DIR/issue-unsized-tail-restatic-ice-122488.rs:8:1
+   |
+LL | const DATA: *const ArenaSet<Vec<u8>> = std::ptr::null_mut();
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the type `ArenaSet<Vec<u8>, [u8]>` has an unknown layout
+
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0277`.
+Some errors have detailed explanations: E0080, E0277.
+For more information about an error, try `rustc --explain E0080`.
diff --git a/tests/ui/layout/uncomputable-due-to-trivial-bounds-ice-135138.rs b/tests/ui/layout/uncomputable-due-to-trivial-bounds-ice-135138.rs
new file mode 100644
index 00000000000..91280e49dcd
--- /dev/null
+++ b/tests/ui/layout/uncomputable-due-to-trivial-bounds-ice-135138.rs
@@ -0,0 +1,11 @@
+#![feature(trivial_bounds)]
+
+fn return_str()
+where
+    str: Sized,
+{
+    [(); { let _a: Option<str> = None; 0 }];
+    //~^ ERROR evaluation of constant value failed
+}
+
+fn main() {}
diff --git a/tests/ui/layout/uncomputable-due-to-trivial-bounds-ice-135138.stderr b/tests/ui/layout/uncomputable-due-to-trivial-bounds-ice-135138.stderr
new file mode 100644
index 00000000000..6c7c51db8df
--- /dev/null
+++ b/tests/ui/layout/uncomputable-due-to-trivial-bounds-ice-135138.stderr
@@ -0,0 +1,9 @@
+error[E0080]: evaluation of constant value failed
+  --> $DIR/uncomputable-due-to-trivial-bounds-ice-135138.rs:7:16
+   |
+LL |     [(); { let _a: Option<str> = None; 0 }];
+   |                ^^ the type `Option<str>` has an unknown layout
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/layout/unexpected-unsized-field-issue-135020.rs b/tests/ui/layout/unexpected-unsized-field-issue-135020.rs
new file mode 100644
index 00000000000..c81d037e510
--- /dev/null
+++ b/tests/ui/layout/unexpected-unsized-field-issue-135020.rs
@@ -0,0 +1,7 @@
+//@ check-pass
+
+fn problem_thingy(items: &mut impl Iterator<Item = str>) {
+    items.peekable();
+}
+
+fn main() {}
diff --git a/tests/ui/layout/unknown-when-no-type-parameter.rs b/tests/ui/layout/unknown-when-no-type-parameter.rs
new file mode 100644
index 00000000000..94c32cf262f
--- /dev/null
+++ b/tests/ui/layout/unknown-when-no-type-parameter.rs
@@ -0,0 +1,14 @@
+#![feature(trivial_bounds)]
+
+//@ error-pattern: error[E0080]: evaluation of constant value failed
+//@ error-pattern: the type `<() as Project>::Assoc` has an unknown layout
+
+trait Project {
+    type Assoc;
+}
+
+fn foo() where (): Project {
+    [(); size_of::<<() as Project>::Assoc>()];
+}
+
+fn main() {}
diff --git a/tests/ui/layout/unknown-when-no-type-parameter.stderr b/tests/ui/layout/unknown-when-no-type-parameter.stderr
new file mode 100644
index 00000000000..d0456e2b329
--- /dev/null
+++ b/tests/ui/layout/unknown-when-no-type-parameter.stderr
@@ -0,0 +1,16 @@
+error[E0080]: evaluation of constant value failed
+  --> $SRC_DIR/core/src/mem/mod.rs:LL:COL
+   |
+   = note: the type `<() as Project>::Assoc` has an unknown layout
+   |
+note: inside `std::mem::size_of::<<() as Project>::Assoc>`
+  --> $SRC_DIR/core/src/mem/mod.rs:LL:COL
+note: inside `foo::{constant#0}`
+  --> $DIR/unknown-when-no-type-parameter.rs:11:10
+   |
+LL |     [(); size_of::<<() as Project>::Assoc>()];
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/layout/unknown-when-ptr-metadata-is-DST.rs b/tests/ui/layout/unknown-when-ptr-metadata-is-DST.rs
new file mode 100644
index 00000000000..973235fe65a
--- /dev/null
+++ b/tests/ui/layout/unknown-when-ptr-metadata-is-DST.rs
@@ -0,0 +1,12 @@
+#![feature(ptr_metadata)]
+#![feature(trivial_bounds)]
+
+fn return_str()
+where
+    str: std::ptr::Pointee<Metadata = str>,
+{
+    [(); { let _a: Option<&str> = None; 0 }];
+    //~^ ERROR evaluation of constant value failed
+}
+
+fn main() {}
diff --git a/tests/ui/layout/unknown-when-ptr-metadata-is-DST.stderr b/tests/ui/layout/unknown-when-ptr-metadata-is-DST.stderr
new file mode 100644
index 00000000000..68bba2e9678
--- /dev/null
+++ b/tests/ui/layout/unknown-when-ptr-metadata-is-DST.stderr
@@ -0,0 +1,9 @@
+error[E0080]: evaluation of constant value failed
+  --> $DIR/unknown-when-ptr-metadata-is-DST.rs:8:16
+   |
+LL |     [(); { let _a: Option<&str> = None; 0 }];
+   |                ^^ the type `str` has an unknown layout
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/lint/lint-double-negations.rs b/tests/ui/lint/lint-double-negations.rs
new file mode 100644
index 00000000000..43e61dd7c13
--- /dev/null
+++ b/tests/ui/lint/lint-double-negations.rs
@@ -0,0 +1,9 @@
+//@ check-pass
+fn main() {
+    let x = 1;
+    -x;
+    -(-x);
+    --x; //~ WARN use of a double negation
+    ---x; //~ WARN use of a double negation
+    let _y = --(-x); //~ WARN use of a double negation
+}
diff --git a/tests/ui/lint/lint-double-negations.stderr b/tests/ui/lint/lint-double-negations.stderr
new file mode 100644
index 00000000000..9367f74be54
--- /dev/null
+++ b/tests/ui/lint/lint-double-negations.stderr
@@ -0,0 +1,42 @@
+warning: use of a double negation
+  --> $DIR/lint-double-negations.rs:6:5
+   |
+LL |     --x;
+   |     ^^^
+   |
+   = note: the prefix `--` could be misinterpreted as a decrement operator which exists in other languages
+   = note: use `-= 1` if you meant to decrement the value
+   = note: `#[warn(double_negations)]` on by default
+help: add parentheses for clarity
+   |
+LL |     -(-x);
+   |      +  +
+
+warning: use of a double negation
+  --> $DIR/lint-double-negations.rs:7:6
+   |
+LL |     ---x;
+   |      ^^^
+   |
+   = note: the prefix `--` could be misinterpreted as a decrement operator which exists in other languages
+   = note: use `-= 1` if you meant to decrement the value
+help: add parentheses for clarity
+   |
+LL |     --(-x);
+   |       +  +
+
+warning: use of a double negation
+  --> $DIR/lint-double-negations.rs:8:14
+   |
+LL |     let _y = --(-x);
+   |              ^^^^^^
+   |
+   = note: the prefix `--` could be misinterpreted as a decrement operator which exists in other languages
+   = note: use `-= 1` if you meant to decrement the value
+help: add parentheses for clarity
+   |
+LL |     let _y = -(-(-x));
+   |               +     +
+
+warning: 3 warnings emitted
+
diff --git a/tests/ui/lint/lint-type-overflow2.rs b/tests/ui/lint/lint-type-overflow2.rs
index f007b45b847..ac7420326c8 100644
--- a/tests/ui/lint/lint-type-overflow2.rs
+++ b/tests/ui/lint/lint-type-overflow2.rs
@@ -4,6 +4,7 @@
 
 fn main() {
     let x2: i8 = --128; //~ ERROR literal out of range for `i8`
+    //~| WARN use of a double negation
 
     let x = -3.40282357e+38_f32; //~ ERROR literal out of range for `f32`
     let x =  3.40282357e+38_f32; //~ ERROR literal out of range for `f32`
diff --git a/tests/ui/lint/lint-type-overflow2.stderr b/tests/ui/lint/lint-type-overflow2.stderr
index eb593d062f2..2cfb18e9fe9 100644
--- a/tests/ui/lint/lint-type-overflow2.stderr
+++ b/tests/ui/lint/lint-type-overflow2.stderr
@@ -1,3 +1,17 @@
+warning: use of a double negation
+  --> $DIR/lint-type-overflow2.rs:6:18
+   |
+LL |     let x2: i8 = --128;
+   |                  ^^^^^
+   |
+   = note: the prefix `--` could be misinterpreted as a decrement operator which exists in other languages
+   = note: use `-= 1` if you meant to decrement the value
+   = note: `#[warn(double_negations)]` on by default
+help: add parentheses for clarity
+   |
+LL |     let x2: i8 = -(-128);
+   |                   +    +
+
 error: literal out of range for `i8`
   --> $DIR/lint-type-overflow2.rs:6:20
    |
@@ -13,7 +27,7 @@ LL | #![deny(overflowing_literals)]
    |         ^^^^^^^^^^^^^^^^^^^^
 
 error: literal out of range for `f32`
-  --> $DIR/lint-type-overflow2.rs:8:14
+  --> $DIR/lint-type-overflow2.rs:9:14
    |
 LL |     let x = -3.40282357e+38_f32;
    |              ^^^^^^^^^^^^^^^^^^
@@ -21,7 +35,7 @@ LL |     let x = -3.40282357e+38_f32;
    = note: the literal `3.40282357e+38_f32` does not fit into the type `f32` and will be converted to `f32::INFINITY`
 
 error: literal out of range for `f32`
-  --> $DIR/lint-type-overflow2.rs:9:14
+  --> $DIR/lint-type-overflow2.rs:10:14
    |
 LL |     let x =  3.40282357e+38_f32;
    |              ^^^^^^^^^^^^^^^^^^
@@ -29,7 +43,7 @@ LL |     let x =  3.40282357e+38_f32;
    = note: the literal `3.40282357e+38_f32` does not fit into the type `f32` and will be converted to `f32::INFINITY`
 
 error: literal out of range for `f64`
-  --> $DIR/lint-type-overflow2.rs:10:14
+  --> $DIR/lint-type-overflow2.rs:11:14
    |
 LL |     let x = -1.7976931348623159e+308_f64;
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -37,12 +51,12 @@ LL |     let x = -1.7976931348623159e+308_f64;
    = note: the literal `1.7976931348623159e+308_f64` does not fit into the type `f64` and will be converted to `f64::INFINITY`
 
 error: literal out of range for `f64`
-  --> $DIR/lint-type-overflow2.rs:11:14
+  --> $DIR/lint-type-overflow2.rs:12:14
    |
 LL |     let x =  1.7976931348623159e+308_f64;
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: the literal `1.7976931348623159e+308_f64` does not fit into the type `f64` and will be converted to `f64::INFINITY`
 
-error: aborting due to 5 previous errors
+error: aborting due to 5 previous errors; 1 warning emitted
 
diff --git a/tests/ui/structs/ice-struct-tail-normalization-113272.rs b/tests/ui/structs/ice-struct-tail-normalization-113272.rs
index 0ae24a7b71b..ce2871fabb8 100644
--- a/tests/ui/structs/ice-struct-tail-normalization-113272.rs
+++ b/tests/ui/structs/ice-struct-tail-normalization-113272.rs
@@ -13,6 +13,6 @@ struct Other {
 fn main() {
     unsafe {
         std::mem::transmute::<Option<()>, Option<&Other>>(None);
-        //~^ ERROR cannot transmute
+        //~^ ERROR cannot transmute between types of different sizes, or dependently-sized types
     }
 }
diff --git a/triagebot.toml b/triagebot.toml
index 4a09fe116a5..d09d5eceeb8 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -1025,7 +1025,8 @@ users_on_vacation = [
     "nnethercote",
     "spastorino",
     "workingjubilee",
-    "kobzol"
+    "kobzol",
+    "jieyouxu",
 ]
 
 [[assign.warn_non_default_branch.exceptions]]