From 6a5a88eb6e7a3494902f95b07d074621fb69cd8b Mon Sep 17 00:00:00 2001
From: ilikdoge <ilikdoge0@gmail.com>
Date: Wed, 24 Jul 2024 19:07:14 -0700
Subject: [PATCH 01/10] Implement `mixed_integer_ops_unsigned_sub`

---
 library/core/src/num/uint_macros.rs | 103 ++++++++++++++++++++++++++++
 1 file changed, 103 insertions(+)

diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs
index e6bdc4d450d4a..7d39040a6a20d 100644
--- a/library/core/src/num/uint_macros.rs
+++ b/library/core/src/num/uint_macros.rs
@@ -765,6 +765,33 @@ macro_rules! uint_impl {
             }
         }
 
+        /// Checked subtraction with a signed integer. Computes `self - rhs`,
+        /// returning `None` if overflow occurred.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        /// #![feature(mixed_integer_ops_unsigned_sub)]
+        #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".checked_sub_signed(2), None);")]
+        #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".checked_sub_signed(-2), Some(3));")]
+        #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).checked_sub_signed(-4), None);")]
+        /// ```
+        #[unstable(feature = "mixed_integer_ops_unsigned_sub", issue = "126043")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn checked_sub_signed(self, rhs: $SignedT) -> Option<Self> {
+            let (res, overflow) = self.overflowing_sub_signed(rhs);
+
+            if !overflow {
+                Some(res)
+            } else {
+                None
+            }
+        }
+
         #[doc = concat!(
             "Checked integer subtraction. Computes `self - rhs` and checks if the result fits into an [`",
             stringify!($SignedT), "`], returning `None` if overflow occurred."
@@ -1757,6 +1784,35 @@ macro_rules! uint_impl {
             intrinsics::saturating_sub(self, rhs)
         }
 
+        /// Saturating integer subtraction. Computes `self` - `rhs`, saturating at
+        /// the numeric bounds instead of overflowing.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        /// #![feature(mixed_integer_ops_unsigned_sub)]
+        #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".saturating_sub_signed(2), 0);")]
+        #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".saturating_sub_signed(-2), 3);")]
+        #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).saturating_sub_signed(-4), ", stringify!($SelfT), "::MAX);")]
+        /// ```
+        #[unstable(feature = "mixed_integer_ops_unsigned_sub", issue = "126043")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn saturating_sub_signed(self, rhs: $SignedT) -> Self {
+            let (res, overflow) = self.overflowing_sub_signed(rhs);
+
+            if !overflow {
+                res
+            } else if rhs < 0 {
+                Self::MAX
+            } else {
+                0
+            }
+        }
+
         /// Saturating integer multiplication. Computes `self * rhs`,
         /// saturating at the numeric bounds instead of overflowing.
         ///
@@ -1890,6 +1946,27 @@ macro_rules! uint_impl {
             intrinsics::wrapping_sub(self, rhs)
         }
 
+        /// Wrapping (modular) subtraction with a signed integer. Computes
+        /// `self - rhs`, wrapping around at the boundary of the type.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        /// #![feature(mixed_integer_ops_unsigned_sub)]
+        #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".wrapping_sub_signed(2), ", stringify!($SelfT), "::MAX);")]
+        #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".wrapping_sub_signed(-2), 3);")]
+        #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).wrapping_sub_signed(-4), 1);")]
+        /// ```
+        #[unstable(feature = "mixed_integer_ops_unsigned_sub", issue = "126043")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn wrapping_sub_signed(self, rhs: $SignedT) -> Self {
+            self.wrapping_sub(rhs as Self)
+        }
+
         /// Wrapping (modular) multiplication. Computes `self *
         /// rhs`, wrapping around at the boundary of the type.
         ///
@@ -2328,6 +2405,32 @@ macro_rules! uint_impl {
             (c, b || d)
         }
 
+        /// Calculates `self` - `rhs` with a signed `rhs`
+        ///
+        /// Returns a tuple of the subtraction along with a boolean indicating
+        /// whether an arithmetic overflow would occur. If an overflow would
+        /// have occurred then the wrapped value is returned.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        /// #![feature(mixed_integer_ops_unsigned_sub)]
+        #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".overflowing_sub_signed(2), (", stringify!($SelfT), "::MAX, true));")]
+        #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".overflowing_sub_signed(-2), (3, false));")]
+        #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).overflowing_sub_signed(-4), (1, true));")]
+        /// ```
+        #[unstable(feature = "mixed_integer_ops_unsigned_sub", issue = "126043")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn overflowing_sub_signed(self, rhs: $SignedT) -> (Self, bool) {
+            let (res, overflow) = self.overflowing_sub(rhs as Self);
+
+            (res, overflow ^ (rhs < 0))
+        }
+
         /// Computes the absolute difference between `self` and `other`.
         ///
         /// # Examples

From 295cffc4b4042edbbd24e1a2aa28ef84ffcd38ac Mon Sep 17 00:00:00 2001
From: Luca Versari <veluca93@gmail.com>
Date: Sun, 10 Nov 2024 11:36:50 +0100
Subject: [PATCH 02/10] ABI checks: add support for tier2 arches

See #131800 for the data collection behind this change.

Also adds a test that exercise the "empty list of features" path.
---
 compiler/rustc_monomorphize/messages.ftl      | 11 +++-
 compiler/rustc_monomorphize/src/errors.rs     | 14 +++++
 .../src/mono_checks/abi_check.rs              | 57 +++++++++++++------
 compiler/rustc_target/src/target_features.rs  | 24 +++++++-
 tests/ui/simd-abi-checks-empty-list.rs        | 19 +++++++
 tests/ui/simd-abi-checks-empty-list.stderr    | 12 ++++
 tests/ui/simd-abi-checks.rs                   | 18 +++---
 tests/ui/simd-abi-checks.stderr               | 18 +++---
 tests/ui/sse-abi-checks.rs                    |  2 +-
 tests/ui/sse-abi-checks.stderr                |  2 +-
 10 files changed, 136 insertions(+), 41 deletions(-)
 create mode 100644 tests/ui/simd-abi-checks-empty-list.rs
 create mode 100644 tests/ui/simd-abi-checks-empty-list.stderr

diff --git a/compiler/rustc_monomorphize/messages.ftl b/compiler/rustc_monomorphize/messages.ftl
index 6da387bbebcc7..8528a2e68c052 100644
--- a/compiler/rustc_monomorphize/messages.ftl
+++ b/compiler/rustc_monomorphize/messages.ftl
@@ -1,12 +1,19 @@
 monomorphize_abi_error_disabled_vector_type_call =
-  ABI error: this function call uses a vector type that requires the `{$required_feature}` target feature, which is not enabled in the caller
+  this function call uses a SIMD vector type that (with the chosen ABI) requires the `{$required_feature}` target feature, which is not enabled in the caller
   .label = function called here
   .help = consider enabling it globally (`-C target-feature=+{$required_feature}`) or locally (`#[target_feature(enable="{$required_feature}")]`)
 monomorphize_abi_error_disabled_vector_type_def =
-  ABI error: this function definition uses a vector type that requires the `{$required_feature}` target feature, which is not enabled
+  this function definition uses a SIMD vector type that (with the chosen ABI) requires the `{$required_feature}` target feature, which is not enabled
   .label = function defined here
   .help = consider enabling it globally (`-C target-feature=+{$required_feature}`) or locally (`#[target_feature(enable="{$required_feature}")]`)
 
+monomorphize_abi_error_unsupported_vector_type_call =
+  this function call uses a SIMD vector type that is not currently supported with the chosen ABI
+  .label = function called here
+monomorphize_abi_error_unsupported_vector_type_def =
+  this function definition uses a SIMD vector type that is not currently supported with the chosen ABI
+  .label = function defined here
+
 monomorphize_couldnt_dump_mono_stats =
     unexpected error occurred while dumping monomorphization stats: {$error}
 
diff --git a/compiler/rustc_monomorphize/src/errors.rs b/compiler/rustc_monomorphize/src/errors.rs
index 5048a8d5d993f..02865cad302cb 100644
--- a/compiler/rustc_monomorphize/src/errors.rs
+++ b/compiler/rustc_monomorphize/src/errors.rs
@@ -110,3 +110,17 @@ pub(crate) struct AbiErrorDisabledVectorTypeCall<'a> {
     pub span: Span,
     pub required_feature: &'a str,
 }
+
+#[derive(LintDiagnostic)]
+#[diag(monomorphize_abi_error_unsupported_vector_type_def)]
+pub(crate) struct AbiErrorUnsupportedVectorTypeDef {
+    #[label]
+    pub span: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(monomorphize_abi_error_unsupported_vector_type_call)]
+pub(crate) struct AbiErrorUnsupportedVectorTypeCall {
+    #[label]
+    pub span: Span,
+}
diff --git a/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs b/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs
index 221200e9497d6..d53595929e733 100644
--- a/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs
+++ b/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs
@@ -10,7 +10,10 @@ use rustc_span::{DUMMY_SP, Span, Symbol};
 use rustc_target::abi::call::{FnAbi, PassMode};
 use rustc_target::abi::{BackendRepr, RegKind};
 
-use crate::errors::{AbiErrorDisabledVectorTypeCall, AbiErrorDisabledVectorTypeDef};
+use crate::errors::{
+    AbiErrorDisabledVectorTypeCall, AbiErrorDisabledVectorTypeDef,
+    AbiErrorUnsupportedVectorTypeCall, AbiErrorUnsupportedVectorTypeDef,
+};
 
 fn uses_vector_registers(mode: &PassMode, repr: &BackendRepr) -> bool {
     match mode {
@@ -23,11 +26,15 @@ fn uses_vector_registers(mode: &PassMode, repr: &BackendRepr) -> bool {
     }
 }
 
+/// Checks whether a certain function ABI is compatible with the target features currently enabled
+/// for a certain function.
+/// If not, `emit_err` is called, with `Some(feature)` if a certain feature should be enabled and
+/// with `None` if no feature is known that would make the ABI compatible.
 fn do_check_abi<'tcx>(
     tcx: TyCtxt<'tcx>,
     abi: &FnAbi<'tcx, Ty<'tcx>>,
     target_feature_def: DefId,
-    mut emit_err: impl FnMut(&'static str),
+    mut emit_err: impl FnMut(Option<&'static str>),
 ) {
     let Some(feature_def) = tcx.sess.target.features_for_correct_vector_abi() else {
         return;
@@ -40,7 +47,7 @@ fn do_check_abi<'tcx>(
             let feature = match feature_def.iter().find(|(bits, _)| size.bits() <= *bits) {
                 Some((_, feature)) => feature,
                 None => {
-                    emit_err("<no available feature for this size>");
+                    emit_err(None);
                     continue;
                 }
             };
@@ -48,7 +55,7 @@ fn do_check_abi<'tcx>(
             if !tcx.sess.unstable_target_features.contains(&feature_sym)
                 && !codegen_attrs.target_features.iter().any(|x| x.name == feature_sym)
             {
-                emit_err(feature);
+                emit_err(Some(&feature));
             }
         }
     }
@@ -65,12 +72,21 @@ fn check_instance_abi<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) {
     };
     do_check_abi(tcx, abi, instance.def_id(), |required_feature| {
         let span = tcx.def_span(instance.def_id());
-        tcx.emit_node_span_lint(
-            ABI_UNSUPPORTED_VECTOR_TYPES,
-            CRATE_HIR_ID,
-            span,
-            AbiErrorDisabledVectorTypeDef { span, required_feature },
-        );
+        if let Some(required_feature) = required_feature {
+            tcx.emit_node_span_lint(
+                ABI_UNSUPPORTED_VECTOR_TYPES,
+                CRATE_HIR_ID,
+                span,
+                AbiErrorDisabledVectorTypeDef { span, required_feature },
+            );
+        } else {
+            tcx.emit_node_span_lint(
+                ABI_UNSUPPORTED_VECTOR_TYPES,
+                CRATE_HIR_ID,
+                span,
+                AbiErrorUnsupportedVectorTypeDef { span },
+            );
+        }
     })
 }
 
@@ -109,12 +125,21 @@ fn check_call_site_abi<'tcx>(
         return;
     };
     do_check_abi(tcx, callee_abi, caller.def_id(), |required_feature| {
-        tcx.emit_node_span_lint(
-            ABI_UNSUPPORTED_VECTOR_TYPES,
-            CRATE_HIR_ID,
-            span,
-            AbiErrorDisabledVectorTypeCall { span, required_feature },
-        );
+        if let Some(required_feature) = required_feature {
+            tcx.emit_node_span_lint(
+                ABI_UNSUPPORTED_VECTOR_TYPES,
+                CRATE_HIR_ID,
+                span,
+                AbiErrorDisabledVectorTypeCall { span, required_feature },
+            );
+        } else {
+            tcx.emit_node_span_lint(
+                ABI_UNSUPPORTED_VECTOR_TYPES,
+                CRATE_HIR_ID,
+                span,
+                AbiErrorUnsupportedVectorTypeCall { span },
+            );
+        }
     });
 }
 
diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs
index b7588b0181426..88536926b1122 100644
--- a/compiler/rustc_target/src/target_features.rs
+++ b/compiler/rustc_target/src/target_features.rs
@@ -586,9 +586,20 @@ pub fn all_rust_features() -> impl Iterator<Item = (&'static str, Stability)> {
 // certain size to have their "proper" ABI on each architecture.
 // Note that they must be kept sorted by vector size.
 const X86_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] =
-    &[(128, "sse"), (256, "avx"), (512, "avx512f")];
+    &[(128, "sse"), (256, "avx"), (512, "avx512f")]; // FIXME: might need changes for AVX10.
 const AARCH64_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "neon")];
 
+// We might want to add "helium" too.
+const ARM_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "neon")];
+
+const POWERPC_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "altivec")];
+const WASM_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "simd128")];
+const S390X_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "vector")];
+const RISCV_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] =
+    &[/*(64, "zvl64b"), */ (128, "v")];
+// Always warn on SPARC, as the necessary target features cannot be enabled in Rust at the moment.
+const SPARC_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[/*(128, "vis")*/];
+
 impl super::spec::Target {
     pub fn rust_target_features(&self) -> &'static [(&'static str, Stability, ImpliedFeatures)] {
         match &*self.arch {
@@ -613,8 +624,15 @@ impl super::spec::Target {
     pub fn features_for_correct_vector_abi(&self) -> Option<&'static [(u64, &'static str)]> {
         match &*self.arch {
             "x86" | "x86_64" => Some(X86_FEATURES_FOR_CORRECT_VECTOR_ABI),
-            "aarch64" => Some(AARCH64_FEATURES_FOR_CORRECT_VECTOR_ABI),
-            // FIXME: add support for non-tier1 architectures
+            "aarch64" | "arm64ec" => Some(AARCH64_FEATURES_FOR_CORRECT_VECTOR_ABI),
+            "arm" => Some(ARM_FEATURES_FOR_CORRECT_VECTOR_ABI),
+            "powerpc" | "powerpc64" => Some(POWERPC_FEATURES_FOR_CORRECT_VECTOR_ABI),
+            "loongarch64" => Some(&[]), // on-stack ABI, so we complain about all by-val vectors
+            "riscv32" | "riscv64" => Some(RISCV_FEATURES_FOR_CORRECT_VECTOR_ABI),
+            "wasm32" | "wasm64" => Some(WASM_FEATURES_FOR_CORRECT_VECTOR_ABI),
+            "s390x" => Some(S390X_FEATURES_FOR_CORRECT_VECTOR_ABI),
+            "sparc" | "sparc64" => Some(SPARC_FEATURES_FOR_CORRECT_VECTOR_ABI),
+            // FIXME: add support for non-tier2 architectures
             _ => None,
         }
     }
diff --git a/tests/ui/simd-abi-checks-empty-list.rs b/tests/ui/simd-abi-checks-empty-list.rs
new file mode 100644
index 0000000000000..c1785051e5a53
--- /dev/null
+++ b/tests/ui/simd-abi-checks-empty-list.rs
@@ -0,0 +1,19 @@
+//@ needs-llvm-components: sparc
+//@ compile-flags: --target=sparc-unknown-none-elf --crate-type=rlib
+//@ build-pass
+//@ ignore-pass (test emits codegen-time warnings)
+#![no_core]
+#![feature(no_core, lang_items, repr_simd)]
+#![allow(improper_ctypes_definitions)]
+#[lang = "sized"]
+trait Sized {}
+
+#[lang = "copy"]
+trait Copy {}
+
+#[repr(simd)]
+pub struct SimdVec([i32; 4]);
+
+pub extern "C" fn pass_by_vec(_: SimdVec) {}
+//~^ this function definition uses a SIMD vector type that is not currently supported with the chosen ABI
+//~| WARNING this was previously accepted by the compiler
diff --git a/tests/ui/simd-abi-checks-empty-list.stderr b/tests/ui/simd-abi-checks-empty-list.stderr
new file mode 100644
index 0000000000000..d7ce52eab80fd
--- /dev/null
+++ b/tests/ui/simd-abi-checks-empty-list.stderr
@@ -0,0 +1,12 @@
+warning: this function definition uses a SIMD vector type that is not currently supported with the chosen ABI
+  --> $DIR/simd-abi-checks-empty-list.rs:17:1
+   |
+LL | pub extern "C" fn pass_by_vec(_: SimdVec) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
+   = note: `#[warn(abi_unsupported_vector_types)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/simd-abi-checks.rs b/tests/ui/simd-abi-checks.rs
index 094c89930b752..9e3af26e9c469 100644
--- a/tests/ui/simd-abi-checks.rs
+++ b/tests/ui/simd-abi-checks.rs
@@ -12,19 +12,19 @@ use std::arch::x86_64::*;
 struct Wrapper(__m256);
 
 unsafe extern "C" fn w(_: Wrapper) {
-    //~^ ABI error: this function definition uses a vector type that requires the `avx` target feature, which is not enabled
+    //~^ this function definition uses a SIMD vector type that (with the chosen ABI) requires the `avx` target feature, which is not enabled
     //~| WARNING this was previously accepted by the compiler
     todo!()
 }
 
 unsafe extern "C" fn f(_: __m256) {
-    //~^ ABI error: this function definition uses a vector type that requires the `avx` target feature, which is not enabled
+    //~^ this function definition uses a SIMD vector type that (with the chosen ABI) requires the `avx` target feature, which is not enabled
     //~| WARNING this was previously accepted by the compiler
     todo!()
 }
 
 unsafe extern "C" fn g() -> __m256 {
-    //~^ ABI error: this function definition uses a vector type that requires the `avx` target feature, which is not enabled
+    //~^ this function definition uses a SIMD vector type that (with the chosen ABI) requires the `avx` target feature, which is not enabled
     //~| WARNING this was previously accepted by the compiler
     todo!()
 }
@@ -53,16 +53,16 @@ unsafe fn test() {
 fn main() {
     unsafe {
         f(g());
-        //~^ WARNING ABI error: this function call uses a vector type that requires the `avx` target feature, which is not enabled in the caller
-        //~| WARNING ABI error: this function call uses a vector type that requires the `avx` target feature, which is not enabled in the caller
+        //~^ WARNING this function call uses a SIMD vector type that (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller
+        //~| WARNING this function call uses a SIMD vector type that (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller
         //~| WARNING this was previously accepted by the compiler
         //~| WARNING this was previously accepted by the compiler
     }
 
     unsafe {
         gavx(favx());
-        //~^ WARNING ABI error: this function call uses a vector type that requires the `avx` target feature, which is not enabled in the caller
-        //~| WARNING ABI error: this function call uses a vector type that requires the `avx` target feature, which is not enabled in the caller
+        //~^ WARNING this function call uses a SIMD vector type that (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller
+        //~| WARNING this function call uses a SIMD vector type that (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller
         //~| WARNING this was previously accepted by the compiler
         //~| WARNING this was previously accepted by the compiler
     }
@@ -73,8 +73,8 @@ fn main() {
 
     unsafe {
         w(Wrapper(g()));
-        //~^ WARNING ABI error: this function call uses a vector type that requires the `avx` target feature, which is not enabled in the caller
-        //~| WARNING ABI error: this function call uses a vector type that requires the `avx` target feature, which is not enabled in the caller
+        //~^ WARNING this function call uses a SIMD vector type that (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller
+        //~| WARNING this function call uses a SIMD vector type that (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller
         //~| WARNING this was previously accepted by the compiler
         //~| WARNING this was previously accepted by the compiler
     }
diff --git a/tests/ui/simd-abi-checks.stderr b/tests/ui/simd-abi-checks.stderr
index aa7e940016981..7d2915f7dea64 100644
--- a/tests/ui/simd-abi-checks.stderr
+++ b/tests/ui/simd-abi-checks.stderr
@@ -1,4 +1,4 @@
-warning: ABI error: this function call uses a vector type that requires the `avx` target feature, which is not enabled in the caller
+warning: this function call uses a SIMD vector type that (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller
   --> $DIR/simd-abi-checks.rs:55:11
    |
 LL |         f(g());
@@ -9,7 +9,7 @@ LL |         f(g());
    = help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`)
    = note: `#[warn(abi_unsupported_vector_types)]` on by default
 
-warning: ABI error: this function call uses a vector type that requires the `avx` target feature, which is not enabled in the caller
+warning: this function call uses a SIMD vector type that (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller
   --> $DIR/simd-abi-checks.rs:55:9
    |
 LL |         f(g());
@@ -19,7 +19,7 @@ LL |         f(g());
    = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
    = help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`)
 
-warning: ABI error: this function call uses a vector type that requires the `avx` target feature, which is not enabled in the caller
+warning: this function call uses a SIMD vector type that (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller
   --> $DIR/simd-abi-checks.rs:63:14
    |
 LL |         gavx(favx());
@@ -29,7 +29,7 @@ LL |         gavx(favx());
    = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
    = help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`)
 
-warning: ABI error: this function call uses a vector type that requires the `avx` target feature, which is not enabled in the caller
+warning: this function call uses a SIMD vector type that (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller
   --> $DIR/simd-abi-checks.rs:63:9
    |
 LL |         gavx(favx());
@@ -39,7 +39,7 @@ LL |         gavx(favx());
    = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
    = help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`)
 
-warning: ABI error: this function call uses a vector type that requires the `avx` target feature, which is not enabled in the caller
+warning: this function call uses a SIMD vector type that (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller
   --> $DIR/simd-abi-checks.rs:75:19
    |
 LL |         w(Wrapper(g()));
@@ -49,7 +49,7 @@ LL |         w(Wrapper(g()));
    = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
    = help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`)
 
-warning: ABI error: this function call uses a vector type that requires the `avx` target feature, which is not enabled in the caller
+warning: this function call uses a SIMD vector type that (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller
   --> $DIR/simd-abi-checks.rs:75:9
    |
 LL |         w(Wrapper(g()));
@@ -59,7 +59,7 @@ LL |         w(Wrapper(g()));
    = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
    = help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`)
 
-warning: ABI error: this function definition uses a vector type that requires the `avx` target feature, which is not enabled
+warning: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `avx` target feature, which is not enabled
   --> $DIR/simd-abi-checks.rs:26:1
    |
 LL | unsafe extern "C" fn g() -> __m256 {
@@ -69,7 +69,7 @@ LL | unsafe extern "C" fn g() -> __m256 {
    = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
    = help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`)
 
-warning: ABI error: this function definition uses a vector type that requires the `avx` target feature, which is not enabled
+warning: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `avx` target feature, which is not enabled
   --> $DIR/simd-abi-checks.rs:20:1
    |
 LL | unsafe extern "C" fn f(_: __m256) {
@@ -79,7 +79,7 @@ LL | unsafe extern "C" fn f(_: __m256) {
    = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
    = help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`)
 
-warning: ABI error: this function definition uses a vector type that requires the `avx` target feature, which is not enabled
+warning: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `avx` target feature, which is not enabled
   --> $DIR/simd-abi-checks.rs:14:1
    |
 LL | unsafe extern "C" fn w(_: Wrapper) {
diff --git a/tests/ui/sse-abi-checks.rs b/tests/ui/sse-abi-checks.rs
index d2afd38fcc85f..c453e91d11b2a 100644
--- a/tests/ui/sse-abi-checks.rs
+++ b/tests/ui/sse-abi-checks.rs
@@ -19,6 +19,6 @@ pub struct SseVector([i64; 2]);
 
 #[no_mangle]
 pub unsafe extern "C" fn f(_: SseVector) {
-    //~^ ABI error: this function definition uses a vector type that requires the `sse` target feature, which is not enabled
+    //~^ this function definition uses a SIMD vector type that (with the chosen ABI) requires the `sse` target feature, which is not enabled
     //~| WARNING this was previously accepted by the compiler
 }
diff --git a/tests/ui/sse-abi-checks.stderr b/tests/ui/sse-abi-checks.stderr
index 77c4e1fc07ab4..7dd13af5091ac 100644
--- a/tests/ui/sse-abi-checks.stderr
+++ b/tests/ui/sse-abi-checks.stderr
@@ -1,4 +1,4 @@
-warning: ABI error: this function definition uses a vector type that requires the `sse` target feature, which is not enabled
+warning: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `sse` target feature, which is not enabled
   --> $DIR/sse-abi-checks.rs:21:1
    |
 LL | pub unsafe extern "C" fn f(_: SseVector) {

From 98a71766b8b6ece6fabb8429e5fe53805ba28b78 Mon Sep 17 00:00:00 2001
From: Kirill Podoprigora <kirill.bast9@mail.ru>
Date: Wed, 13 Nov 2024 15:05:31 +0200
Subject: [PATCH 03/10] Add ``exact-llvm-major-version`` directive

---
 src/tools/compiletest/src/directive-list.rs |  1 +
 src/tools/compiletest/src/header.rs         | 13 +++++++++++++
 src/tools/compiletest/src/header/tests.rs   |  9 +++++++++
 tests/codegen/try_question_mark_nop.rs      |  3 +--
 4 files changed, 24 insertions(+), 2 deletions(-)

diff --git a/src/tools/compiletest/src/directive-list.rs b/src/tools/compiletest/src/directive-list.rs
index 4a102f0c2cbed..038de9036bf98 100644
--- a/src/tools/compiletest/src/directive-list.rs
+++ b/src/tools/compiletest/src/directive-list.rs
@@ -25,6 +25,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
     "dont-check-failure-status",
     "edition",
     "error-pattern",
+    "exact-llvm-major-version",
     "exec-env",
     "failure-status",
     "filecheck-flags",
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
index 300a03e5f3377..5b198c3e60b24 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -1585,6 +1585,19 @@ fn ignore_llvm(config: &Config, line: &str) -> IgnoreDecision {
                     };
                 }
             }
+        } else if let Some(version_string) =
+            config.parse_name_value_directive(line, "exact-llvm-major-version")
+        {
+            // Syntax is "only-llvm-major-version: <version>"
+            let version = extract_llvm_version(&version_string);
+            if actual_version.major > version.major || actual_version.major < version.major {
+                return IgnoreDecision::Ignore {
+                    reason: format!(
+                        "ignored when the LLVM major version is {}, but it should be {}",
+                        actual_version.major, version.major
+                    ),
+                };
+            }
         }
     }
     IgnoreDecision::Continue
diff --git a/src/tools/compiletest/src/header/tests.rs b/src/tools/compiletest/src/header/tests.rs
index c3fb8d4ab8019..1eca48c1c3a83 100644
--- a/src/tools/compiletest/src/header/tests.rs
+++ b/src/tools/compiletest/src/header/tests.rs
@@ -284,6 +284,15 @@ fn llvm_version() {
 
     let config: Config = cfg().llvm_version("10.0.0").build();
     assert!(!check_ignore(&config, "//@ min-llvm-version: 9.0"));
+
+    let config: Config = cfg().llvm_version("10.0.0").build();
+    assert!(check_ignore(&config, "//@ exact-llvm-major-version: 9.0"));
+
+    let config: Config = cfg().llvm_version("9.0.0").build();
+    assert!(check_ignore(&config, "//@ exact-llvm-major-version: 10.0"));
+
+    let config: Config = cfg().llvm_version("10.0.0").build();
+    assert!(!check_ignore(&config, "//@ exact-llvm-major-version: 10.0"));
 }
 
 #[test]
diff --git a/tests/codegen/try_question_mark_nop.rs b/tests/codegen/try_question_mark_nop.rs
index b68ecce869e42..36a0d9066c895 100644
--- a/tests/codegen/try_question_mark_nop.rs
+++ b/tests/codegen/try_question_mark_nop.rs
@@ -2,8 +2,7 @@
 //@ only-x86_64
 // FIXME: Remove the `min-llvm-version`.
 //@ revisions: NINETEEN TWENTY
-//@[NINETEEN] min-llvm-version: 19
-//@[NINETEEN] ignore-llvm-version: 20-99
+//@[NINETEEN] exact-llvm-major-version: 19
 //@[TWENTY] min-llvm-version: 20
 //@ min-llvm-version: 19
 

From 1136bbf0668d84d2b4b09b772e33fd8532994f83 Mon Sep 17 00:00:00 2001
From: clubby789 <jamie@hill-daniel.co.uk>
Date: Wed, 13 Nov 2024 13:17:01 +0000
Subject: [PATCH 04/10] Trim extra space when suggesting removing bad `let`

---
 compiler/rustc_parse/src/parser/pat.rs | 4 +++-
 tests/ui/parser/unnecessary-let.stderr | 8 ++++----
 2 files changed, 7 insertions(+), 5 deletions(-)

diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs
index 7f1140133202d..3546e5b0f0495 100644
--- a/compiler/rustc_parse/src/parser/pat.rs
+++ b/compiler/rustc_parse/src/parser/pat.rs
@@ -683,7 +683,9 @@ impl<'a> Parser<'a> {
             })
         {
             self.bump();
-            self.dcx().emit_err(RemoveLet { span: lo });
+            // Trim extra space after the `let`
+            let span = lo.with_hi(self.token.span.lo());
+            self.dcx().emit_err(RemoveLet { span });
             lo = self.token.span;
         }
 
diff --git a/tests/ui/parser/unnecessary-let.stderr b/tests/ui/parser/unnecessary-let.stderr
index c6ac0d562f82c..05ac1faafd4d9 100644
--- a/tests/ui/parser/unnecessary-let.stderr
+++ b/tests/ui/parser/unnecessary-let.stderr
@@ -2,12 +2,12 @@ error: expected pattern, found `let`
   --> $DIR/unnecessary-let.rs:2:9
    |
 LL |     for let x of [1, 2, 3] {}
-   |         ^^^
+   |         ^^^^
    |
 help: remove the unnecessary `let` keyword
    |
 LL -     for let x of [1, 2, 3] {}
-LL +     for  x of [1, 2, 3] {}
+LL +     for x of [1, 2, 3] {}
    |
 
 error: missing `in` in `for` loop
@@ -25,12 +25,12 @@ error: expected pattern, found `let`
   --> $DIR/unnecessary-let.rs:7:9
    |
 LL |         let 1 => {}
-   |         ^^^
+   |         ^^^^
    |
 help: remove the unnecessary `let` keyword
    |
 LL -         let 1 => {}
-LL +          1 => {}
+LL +         1 => {}
    |
 
 error: aborting due to 3 previous errors

From 81f61058519a408ca8d55e87435f092cc967de8b Mon Sep 17 00:00:00 2001
From: Kirill Podoprigora <kirill.bast9@mail.ru>
Date: Wed, 13 Nov 2024 15:31:07 +0200
Subject: [PATCH 05/10] Address review

---
 src/tools/compiletest/src/header.rs       | 6 +++---
 src/tools/compiletest/src/header/tests.rs | 6 ++++++
 2 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
index 5b198c3e60b24..0e81f675474aa 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -1588,12 +1588,12 @@ fn ignore_llvm(config: &Config, line: &str) -> IgnoreDecision {
         } else if let Some(version_string) =
             config.parse_name_value_directive(line, "exact-llvm-major-version")
         {
-            // Syntax is "only-llvm-major-version: <version>"
+            // Syntax is "exact-llvm-major-version: <version>"
             let version = extract_llvm_version(&version_string);
-            if actual_version.major > version.major || actual_version.major < version.major {
+            if actual_version.major != version.major {
                 return IgnoreDecision::Ignore {
                     reason: format!(
-                        "ignored when the LLVM major version is {}, but it should be {}",
+                        "ignored when the actual LLVM major version is {}, but the test only targets major version {}",
                         actual_version.major, version.major
                     ),
                 };
diff --git a/src/tools/compiletest/src/header/tests.rs b/src/tools/compiletest/src/header/tests.rs
index 1eca48c1c3a83..6c52a1b950782 100644
--- a/src/tools/compiletest/src/header/tests.rs
+++ b/src/tools/compiletest/src/header/tests.rs
@@ -293,6 +293,12 @@ fn llvm_version() {
 
     let config: Config = cfg().llvm_version("10.0.0").build();
     assert!(!check_ignore(&config, "//@ exact-llvm-major-version: 10.0"));
+
+    let config: Config = cfg().llvm_version("10.0.0").build();
+    assert!(!check_ignore(&config, "//@ exact-llvm-major-version: 10"));
+
+    let config: Config = cfg().llvm_version("10.6.2").build();
+    assert!(!check_ignore(&config, "//@ exact-llvm-major-version: 10"));
 }
 
 #[test]

From 29889cca4252877041883bf0586f8161c02726d9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?=
 <39484203+jieyouxu@users.noreply.github.com>
Date: Wed, 13 Nov 2024 21:35:46 +0800
Subject: [PATCH 06/10] Unvacation

---
 triagebot.toml | 1 -
 1 file changed, 1 deletion(-)

diff --git a/triagebot.toml b/triagebot.toml
index 462d5df306f73..0ac971d48d8d0 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -975,7 +975,6 @@ cc = ["@kobzol"]
 warn_non_default_branch = true
 contributing_url = "https://rustc-dev-guide.rust-lang.org/getting-started.html"
 users_on_vacation = [
-    "jieyouxu",
     "jyn514",
     "oli-obk",
 ]

From 9016711bf1f43db68f0ba51a9852b65a2270ae61 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= <me@fmease.dev>
Date: Tue, 29 Oct 2024 02:34:25 +0100
Subject: [PATCH 07/10] rustdoc: Treat decl macros like other items

---
 src/librustdoc/clean/inline.rs           | 18 +++--------
 src/librustdoc/clean/mod.rs              | 11 +++----
 src/librustdoc/clean/types.rs            |  2 ++
 src/librustdoc/clean/utils.rs            | 15 ++-------
 src/librustdoc/html/format.rs            | 41 ------------------------
 src/librustdoc/html/highlight.rs         |  7 ----
 src/librustdoc/html/render/print_item.rs |  9 ++++--
 tests/rustdoc/decl_macro.rs              |  2 ++
 tests/rustdoc/macro_rules-matchers.rs    | 28 +++++-----------
 9 files changed, 31 insertions(+), 102 deletions(-)

diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index 97529e420e3bd..5ddd6188c2d86 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -134,11 +134,7 @@ pub(crate) fn try_inline(
             })
         }
         Res::Def(DefKind::Macro(kind), did) => {
-            let is_doc_hidden = cx.tcx.is_doc_hidden(did)
-                || attrs_without_docs
-                    .map(|(attrs, _)| attrs)
-                    .is_some_and(|attrs| utils::attrs_have_doc_flag(attrs.iter(), sym::hidden));
-            let mac = build_macro(cx, did, name, import_def_id, kind, is_doc_hidden);
+            let mac = build_macro(cx, did, name, kind);
 
             let type_kind = match kind {
                 MacroKind::Bang => ItemType::Macro,
@@ -740,18 +736,14 @@ fn build_macro(
     cx: &mut DocContext<'_>,
     def_id: DefId,
     name: Symbol,
-    import_def_id: Option<LocalDefId>,
     macro_kind: MacroKind,
-    is_doc_hidden: bool,
 ) -> clean::ItemKind {
     match CStore::from_tcx(cx.tcx).load_macro_untracked(def_id, cx.tcx) {
         LoadedMacro::MacroDef { def, .. } => match macro_kind {
-            MacroKind::Bang => {
-                let vis = cx.tcx.visibility(import_def_id.map(|d| d.to_def_id()).unwrap_or(def_id));
-                clean::MacroItem(clean::Macro {
-                    source: utils::display_macro_source(cx, name, &def, def_id, vis, is_doc_hidden),
-                })
-            }
+            MacroKind::Bang => clean::MacroItem(clean::Macro {
+                source: utils::display_macro_source(cx, name, &def),
+                macro_rules: def.macro_rules,
+            }),
             MacroKind::Derive | MacroKind::Attr => {
                 clean::ProcMacroItem(clean::ProcMacro { kind: macro_kind, helpers: Vec::new() })
             }
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 6b6142a6eaa97..598e7e7abe6b4 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -2787,13 +2787,10 @@ fn clean_maybe_renamed_item<'tcx>(
                 fields: variant_data.fields().iter().map(|x| clean_field(x, cx)).collect(),
             }),
             ItemKind::Impl(impl_) => return clean_impl(impl_, item.owner_id.def_id, cx),
-            ItemKind::Macro(macro_def, MacroKind::Bang) => {
-                let ty_vis = cx.tcx.visibility(def_id);
-                MacroItem(Macro {
-                    // FIXME this shouldn't be false
-                    source: display_macro_source(cx, name, macro_def, def_id, ty_vis, false),
-                })
-            }
+            ItemKind::Macro(macro_def, MacroKind::Bang) => MacroItem(Macro {
+                source: display_macro_source(cx, name, macro_def),
+                macro_rules: macro_def.macro_rules,
+            }),
             ItemKind::Macro(_, macro_kind) => clean_proc_macro(item, &mut name, macro_kind, cx),
             // proc macros can have a name set by attributes
             ItemKind::Fn(ref sig, generics, body_id) => {
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index e5c9539b5e7a3..e3a0dbe1a7f30 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -2543,6 +2543,8 @@ pub(crate) struct ImportSource {
 #[derive(Clone, Debug)]
 pub(crate) struct Macro {
     pub(crate) source: String,
+    /// Whether the macro was defined via `macro_rules!` as opposed to `macro`.
+    pub(crate) macro_rules: bool,
 }
 
 #[derive(Clone, Debug)]
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index 560831197f05f..a2e52185153b5 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -24,7 +24,6 @@ use crate::clean::{
     clean_middle_ty, inline,
 };
 use crate::core::DocContext;
-use crate::html::format::visibility_to_src_with_space;
 
 #[cfg(test)]
 mod tests;
@@ -599,7 +598,7 @@ pub(crate) static DOC_CHANNEL: Lazy<&'static str> =
 
 /// Render a sequence of macro arms in a format suitable for displaying to the user
 /// as part of an item declaration.
-pub(super) fn render_macro_arms<'a>(
+fn render_macro_arms<'a>(
     tcx: TyCtxt<'_>,
     matchers: impl Iterator<Item = &'a TokenTree>,
     arm_delim: &str,
@@ -620,9 +619,6 @@ pub(super) fn display_macro_source(
     cx: &mut DocContext<'_>,
     name: Symbol,
     def: &ast::MacroDef,
-    def_id: DefId,
-    vis: ty::Visibility<DefId>,
-    is_doc_hidden: bool,
 ) -> String {
     // Extract the spans of all matchers. They represent the "interface" of the macro.
     let matchers = def.body.tokens.chunks(4).map(|arm| &arm[0]);
@@ -632,18 +628,13 @@ pub(super) fn display_macro_source(
     } else {
         if matchers.len() <= 1 {
             format!(
-                "{vis}macro {name}{matchers} {{\n    ...\n}}",
-                vis = visibility_to_src_with_space(Some(vis), cx.tcx, def_id, is_doc_hidden),
+                "macro {name}{matchers} {{\n    ...\n}}",
                 matchers = matchers
                     .map(|matcher| render_macro_matcher(cx.tcx, matcher))
                     .collect::<String>(),
             )
         } else {
-            format!(
-                "{vis}macro {name} {{\n{arms}}}",
-                vis = visibility_to_src_with_space(Some(vis), cx.tcx, def_id, is_doc_hidden),
-                arms = render_macro_arms(cx.tcx, matchers, ","),
-            )
+            format!("macro {name} {{\n{arms}}}", arms = render_macro_arms(cx.tcx, matchers, ","))
         }
     }
 }
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index e9d5ba2ea57e1..2f9e7976ca142 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -1615,47 +1615,6 @@ pub(crate) fn visibility_print_with_space<'a, 'tcx: 'a>(
     })
 }
 
-/// This function is the same as print_with_space, except that it renders no links.
-/// It's used for macros' rendered source view, which is syntax highlighted and cannot have
-/// any HTML in it.
-pub(crate) fn visibility_to_src_with_space<'a, 'tcx: 'a>(
-    visibility: Option<ty::Visibility<DefId>>,
-    tcx: TyCtxt<'tcx>,
-    item_did: DefId,
-    is_doc_hidden: bool,
-) -> impl Display + 'a + Captures<'tcx> {
-    let vis: Cow<'static, str> = match visibility {
-        None => "".into(),
-        Some(ty::Visibility::Public) => "pub ".into(),
-        Some(ty::Visibility::Restricted(vis_did)) => {
-            // FIXME(camelid): This may not work correctly if `item_did` is a module.
-            //                 However, rustdoc currently never displays a module's
-            //                 visibility, so it shouldn't matter.
-            let parent_module = find_nearest_parent_module(tcx, item_did);
-
-            if vis_did.is_crate_root() {
-                "pub(crate) ".into()
-            } else if parent_module == Some(vis_did) {
-                // `pub(in foo)` where `foo` is the parent module
-                // is the same as no visibility modifier
-                "".into()
-            } else if parent_module.and_then(|parent| find_nearest_parent_module(tcx, parent))
-                == Some(vis_did)
-            {
-                "pub(super) ".into()
-            } else {
-                format!("pub(in {}) ", tcx.def_path_str(vis_did)).into()
-            }
-        }
-    };
-    display_fn(move |f| {
-        if is_doc_hidden {
-            f.write_str("#[doc(hidden)] ")?;
-        }
-        f.write_str(&vis)
-    })
-}
-
 pub(crate) trait PrintWithSpace {
     fn print_with_space(&self) -> &str;
 }
diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs
index b68b729509635..4def80764ea78 100644
--- a/src/librustdoc/html/highlight.rs
+++ b/src/librustdoc/html/highlight.rs
@@ -58,13 +58,6 @@ pub(crate) fn render_example_with_highlighting(
     write_footer(out, playground_button);
 }
 
-/// Highlights `src` as an item-decl, returning the HTML output.
-pub(crate) fn render_item_decl_with_highlighting(src: &str, out: &mut Buffer) {
-    write!(out, "<pre class=\"rust item-decl\">");
-    write_code(out, src, None, None);
-    write!(out, "</pre>");
-}
-
 fn write_header(
     out: &mut Buffer,
     class: &str,
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index c6a2d87cbd02b..d247e90d298db 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -35,7 +35,6 @@ use crate::html::format::{
     Buffer, Ending, PrintWithSpace, display_fn, join_with_double_colon, print_abi_with_space,
     print_constness_with_space, print_where_clause, visibility_print_with_space,
 };
-use crate::html::highlight;
 use crate::html::markdown::{HeadingOffset, MarkdownSummaryLine};
 use crate::html::render::{document_full, document_item_info};
 use crate::html::url_parts_builder::UrlPartsBuilder;
@@ -1745,7 +1744,13 @@ fn item_variants(
 }
 
 fn item_macro(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean::Macro) {
-    highlight::render_item_decl_with_highlighting(&t.source, w);
+    wrap_item(w, |w| {
+        // FIXME: Also print `#[doc(hidden)]` for `macro_rules!` if it `is_doc_hidden`.
+        if !t.macro_rules {
+            write!(w, "{}", visibility_print_with_space(it, cx));
+        }
+        write!(w, "{}", Escape(&t.source));
+    });
     write!(w, "{}", document(cx, it, None, HeadingOffset::H2))
 }
 
diff --git a/tests/rustdoc/decl_macro.rs b/tests/rustdoc/decl_macro.rs
index da471e7c224a7..040859baffbfc 100644
--- a/tests/rustdoc/decl_macro.rs
+++ b/tests/rustdoc/decl_macro.rs
@@ -48,6 +48,8 @@ mod a {
         }
         mod c {
             //@ has decl_macro/a/b/c/macro.by_example_vis_named.html //pre 'pub(in a) macro by_example_vis_named($foo:expr) {'
+            // Regression test for <https://github.com/rust-lang/rust/issues/83000>:
+            //@ has - '//pre[@class="rust item-decl"]//a[@class="mod"]/@href' '../../index.html'
             pub(in a) macro by_example_vis_named {
                 ($foo:expr) => {}
             }
diff --git a/tests/rustdoc/macro_rules-matchers.rs b/tests/rustdoc/macro_rules-matchers.rs
index c3ee8febdf532..2c9fb50539a27 100644
--- a/tests/rustdoc/macro_rules-matchers.rs
+++ b/tests/rustdoc/macro_rules-matchers.rs
@@ -3,29 +3,17 @@
 
 #![crate_name = "foo"]
 
-//@ has 'foo/macro.todo.html'
-//@ has - '//span[@class="macro"]' 'macro_rules!'
-//@ hasraw - ' todo {'
-
-//@ hasraw - '{ () =&gt; { ... }; ($('
-//@ has - '//span[@class="macro-nonterminal"]' '$'
-//@ has - '//span[@class="macro-nonterminal"]' 'arg'
-//@ hasraw - ':tt)+'
-//@ hasraw - ') =&gt; { ... }; }'
+//@ has 'foo/macro.todo.html' '//pre' 'macro_rules! todo { \
+//      () => { ... }; \
+//      ($($arg:tt)+) => { ... }; \
+// }'
 pub use std::todo;
 
 mod mod1 {
-    //@ has 'foo/macro.macro1.html'
-    //@ hasraw - 'macro_rules!'
-    //@ hasraw - 'macro1'
-    //@ hasraw - '{ () =&gt; { ... }; ($('
-    //@ has - '//span[@class="macro-nonterminal"]' '$'
-    //@ has - '//span[@class="macro-nonterminal"]' 'arg'
-    //@ hasraw - ':'
-    //@ hasraw - 'expr'
-    //@ hasraw - '),'
-    //@ hasraw - '+'
-    //@ hasraw - ') =&gt; { ... }; }'
+    //@ has 'foo/macro.macro1.html' '//pre' 'macro_rules! macro1 { \
+    //      () => { ... }; \
+    //      ($($arg:expr),+) => { ... }; \
+    // }'
     #[macro_export]
     macro_rules! macro1 {
         () => {};

From d9aac8cfcefcd4063fc39ff19e9ace373471bbbc Mon Sep 17 00:00:00 2001
From: Guillaume Gomez <guillaume1.gomez@gmail.com>
Date: Wed, 13 Nov 2024 16:56:18 +0100
Subject: [PATCH 08/10] Fix duplicated footnote IDs

---
 src/librustdoc/html/markdown.rs           | 46 +++++++++++++++--------
 src/librustdoc/html/markdown/footnotes.rs | 33 +++++++++-------
 src/librustdoc/html/render/context.rs     |  4 +-
 3 files changed, 51 insertions(+), 32 deletions(-)

diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index 7826a5d8394a7..1d42ec8eec7cb 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -1333,12 +1333,14 @@ impl Markdown<'_> {
 
         let mut s = String::with_capacity(md.len() * 3 / 2);
 
-        let p = HeadingLinks::new(p, None, ids, heading_offset);
-        let p = footnotes::Footnotes::new(p);
-        let p = LinkReplacer::new(p.map(|(ev, _)| ev), links);
-        let p = TableWrapper::new(p);
-        let p = CodeBlocks::new(p, codes, edition, playground);
-        html::push_html(&mut s, p);
+        ids.handle_footnotes(|ids, existing_footnotes| {
+            let p = HeadingLinks::new(p, None, ids, heading_offset);
+            let p = footnotes::Footnotes::new(p, existing_footnotes);
+            let p = LinkReplacer::new(p.map(|(ev, _)| ev), links);
+            let p = TableWrapper::new(p);
+            let p = CodeBlocks::new(p, codes, edition, playground);
+            html::push_html(&mut s, p);
+        });
 
         s
     }
@@ -1367,13 +1369,13 @@ impl MarkdownWithToc<'_> {
 
         let mut toc = TocBuilder::new();
 
-        {
+        ids.handle_footnotes(|ids, existing_footnotes| {
             let p = HeadingLinks::new(p, Some(&mut toc), ids, HeadingOffset::H1);
-            let p = footnotes::Footnotes::new(p);
+            let p = footnotes::Footnotes::new(p, existing_footnotes);
             let p = TableWrapper::new(p.map(|(ev, _)| ev));
             let p = CodeBlocks::new(p, codes, edition, playground);
             html::push_html(&mut s, p);
-        }
+        });
 
         (toc.into_toc(), s)
     }
@@ -1401,13 +1403,15 @@ impl MarkdownItemInfo<'_> {
 
         let mut s = String::with_capacity(md.len() * 3 / 2);
 
-        let p = HeadingLinks::new(p, None, ids, HeadingOffset::H1);
-        let p = footnotes::Footnotes::new(p);
-        let p = TableWrapper::new(p.map(|(ev, _)| ev));
-        let p = p.filter(|event| {
-            !matches!(event, Event::Start(Tag::Paragraph) | Event::End(TagEnd::Paragraph))
+        ids.handle_footnotes(|ids, existing_footnotes| {
+            let p = HeadingLinks::new(p, None, ids, HeadingOffset::H1);
+            let p = footnotes::Footnotes::new(p, existing_footnotes);
+            let p = TableWrapper::new(p.map(|(ev, _)| ev));
+            let p = p.filter(|event| {
+                !matches!(event, Event::Start(Tag::Paragraph) | Event::End(TagEnd::Paragraph))
+            });
+            html::push_html(&mut s, p);
         });
-        html::push_html(&mut s, p);
 
         s
     }
@@ -1882,6 +1886,7 @@ pub(crate) fn rust_code_blocks(md: &str, extra_info: &ExtraInfo<'_>) -> Vec<Rust
 #[derive(Clone, Default, Debug)]
 pub struct IdMap {
     map: FxHashMap<Cow<'static, str>, usize>,
+    existing_footnotes: usize,
 }
 
 // The map is pre-initialized and cloned each time to avoid reinitializing it repeatedly.
@@ -1943,7 +1948,7 @@ fn init_id_map() -> FxHashMap<Cow<'static, str>, usize> {
 
 impl IdMap {
     pub fn new() -> Self {
-        IdMap { map: DEFAULT_ID_MAP.get_or_init(init_id_map).clone() }
+        IdMap { map: DEFAULT_ID_MAP.get_or_init(init_id_map).clone(), existing_footnotes: 0 }
     }
 
     pub(crate) fn derive<S: AsRef<str> + ToString>(&mut self, candidate: S) -> String {
@@ -1959,4 +1964,13 @@ impl IdMap {
         self.map.insert(id.clone().into(), 1);
         id
     }
+
+    /// Method to handle `existing_footnotes` increment automatically (to prevent forgetting
+    /// about it).
+    pub(crate) fn handle_footnotes<F: FnOnce(&mut Self, &mut usize)>(&mut self, closure: F) {
+        let mut existing_footnotes = self.existing_footnotes;
+
+        closure(self, &mut existing_footnotes);
+        self.existing_footnotes = existing_footnotes;
+    }
 }
diff --git a/src/librustdoc/html/markdown/footnotes.rs b/src/librustdoc/html/markdown/footnotes.rs
index 3f0e586b8e372..0958d446c2d6c 100644
--- a/src/librustdoc/html/markdown/footnotes.rs
+++ b/src/librustdoc/html/markdown/footnotes.rs
@@ -8,36 +8,35 @@ use super::SpannedEvent;
 
 /// Moves all footnote definitions to the end and add back links to the
 /// references.
-pub(super) struct Footnotes<'a, I> {
+pub(super) struct Footnotes<'a, 'b, I> {
     inner: I,
     footnotes: FxIndexMap<String, FootnoteDef<'a>>,
+    existing_footnotes: &'b mut usize,
 }
 
 /// The definition of a single footnote.
 struct FootnoteDef<'a> {
     content: Vec<Event<'a>>,
     /// The number that appears in the footnote reference and list.
-    id: u16,
+    id: usize,
 }
 
-impl<'a, I> Footnotes<'a, I> {
-    pub(super) fn new(iter: I) -> Self {
-        Footnotes { inner: iter, footnotes: FxIndexMap::default() }
+impl<'a, 'b, I> Footnotes<'a, 'b, I> {
+    pub(super) fn new(iter: I, existing_footnotes: &'b mut usize) -> Self {
+        Footnotes { inner: iter, footnotes: FxIndexMap::default(), existing_footnotes }
     }
 
-    fn get_entry(&mut self, key: &str) -> (&mut Vec<Event<'a>>, u16) {
-        let new_id = self.footnotes.len() + 1;
+    fn get_entry(&mut self, key: &str) -> (&mut Vec<Event<'a>>, usize) {
+        let new_id = self.footnotes.len() + 1 + *self.existing_footnotes;
         let key = key.to_owned();
-        let FootnoteDef { content, id } = self
-            .footnotes
-            .entry(key)
-            .or_insert(FootnoteDef { content: Vec::new(), id: new_id as u16 });
+        let FootnoteDef { content, id } =
+            self.footnotes.entry(key).or_insert(FootnoteDef { content: Vec::new(), id: new_id });
         // Don't allow changing the ID of existing entrys, but allow changing the contents.
         (content, *id)
     }
 }
 
-impl<'a, I: Iterator<Item = SpannedEvent<'a>>> Iterator for Footnotes<'a, I> {
+impl<'a, 'b, I: Iterator<Item = SpannedEvent<'a>>> Iterator for Footnotes<'a, 'b, I> {
     type Item = SpannedEvent<'a>;
 
     fn next(&mut self) -> Option<Self::Item> {
@@ -47,8 +46,13 @@ impl<'a, I: Iterator<Item = SpannedEvent<'a>>> Iterator for Footnotes<'a, I> {
                     // When we see a reference (to a footnote we may not know) the definition of,
                     // reserve a number for it, and emit a link to that number.
                     let (_, id) = self.get_entry(reference);
-                    let reference =
-                        format!("<sup id=\"fnref{0}\"><a href=\"#fn{0}\">{0}</a></sup>", id);
+                    let reference = format!(
+                        "<sup id=\"fnref{0}\"><a href=\"#fn{0}\">{1}</a></sup>",
+                        id,
+                        // Although the ID count is for the whole page, the footnote reference
+                        // are local to the item so we make this ID "local" when displayed.
+                        id - *self.existing_footnotes
+                    );
                     return Some((Event::Html(reference.into()), range));
                 }
                 Some((Event::Start(Tag::FootnoteDefinition(def)), _)) => {
@@ -64,6 +68,7 @@ impl<'a, I: Iterator<Item = SpannedEvent<'a>>> Iterator for Footnotes<'a, I> {
                         // After all the markdown is emmited, emit an <hr> then all the footnotes
                         // in a list.
                         let defs: Vec<_> = self.footnotes.drain(..).map(|(_, x)| x).collect();
+                        *self.existing_footnotes += defs.len();
                         let defs_html = render_footnotes_defs(defs);
                         return Some((Event::Html(defs_html.into()), 0..0));
                     } else {
diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs
index dc4d45e592eb7..5f255c18ec6aa 100644
--- a/src/librustdoc/html/render/context.rs
+++ b/src/librustdoc/html/render/context.rs
@@ -76,9 +76,9 @@ pub(crate) struct Context<'tcx> {
 
 // `Context` is cloned a lot, so we don't want the size to grow unexpectedly.
 #[cfg(all(not(windows), target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(Context<'_>, 184);
-#[cfg(all(windows, target_pointer_width = "64"))]
 rustc_data_structures::static_assert_size!(Context<'_>, 192);
+#[cfg(all(windows, target_pointer_width = "64"))]
+rustc_data_structures::static_assert_size!(Context<'_>, 200);
 
 /// Shared mutable state used in [`Context`] and elsewhere.
 pub(crate) struct SharedContext<'tcx> {

From 7a8257dc471762343457c2963b1ccf1a868d06e8 Mon Sep 17 00:00:00 2001
From: Guillaume Gomez <guillaume1.gomez@gmail.com>
Date: Wed, 13 Nov 2024 16:56:40 +0100
Subject: [PATCH 09/10] Add regression test for #131901

---
 tests/rustdoc/footnote-ids.rs | 41 +++++++++++++++++++++++++++++++++++
 1 file changed, 41 insertions(+)
 create mode 100644 tests/rustdoc/footnote-ids.rs

diff --git a/tests/rustdoc/footnote-ids.rs b/tests/rustdoc/footnote-ids.rs
new file mode 100644
index 0000000000000..d3a8435bb4701
--- /dev/null
+++ b/tests/rustdoc/footnote-ids.rs
@@ -0,0 +1,41 @@
+// This test ensures that footnotes ID are not duplicated across an item page.
+// This is a regression test for <https://github.com/rust-lang/rust/issues/131901>.
+
+#![crate_name = "foo"]
+
+//@ has 'foo/struct.Foo.html'
+
+pub struct Foo;
+
+impl Foo {
+    //@ has - '//a[@href="#fn1"]' '1'
+    //@ has - '//li[@id="fn1"]' 'Hiya'
+    //@ has - '//a[@href="#fn2"]' '2'
+    //@ has - '//li[@id="fn2"]' 'Tiya'
+    /// Link 1 [^1]
+    /// Link 1.1 [^2]
+    ///
+    /// [^1]: Hiya
+    /// [^2]: Tiya
+    pub fn l1(){}
+
+    //@ has - '//a[@href="#fn3"]' '1'
+    //@ has - '//li[@id="fn3"]' 'Yiya'
+    //@ has - '//a[@href="#fn4"]' '2'
+    //@ has - '//li[@id="fn4"]' 'Biya'
+    /// Link 2 [^1]
+    /// Link 3 [^2]
+    ///
+    /// [^1]: Yiya
+    /// [^2]: Biya
+    pub fn l2() {}
+}
+
+impl Foo {
+    //@ has - '//a[@href="#fn5"]' '1'
+    //@ has - '//li[@id="fn5"]' 'Ciya'
+    /// Link 3 [^1]
+    ///
+    /// [^1]: Ciya
+    pub fn l3(){}
+}

From 117038197db34e7ed2e2683455fcd7dcfc423140 Mon Sep 17 00:00:00 2001
From: lcnr <rust@lcnr.de>
Date: Wed, 13 Nov 2024 17:29:38 +0100
Subject: [PATCH 10/10] actually test next solver

---
 ...ze-self-type-constrains-trait-args.current.stderr} |  2 +-
 ...malize-self-type-constrains-trait-args.next.stderr | 11 +++++++++++
 .../normalize-self-type-constrains-trait-args.rs      |  3 +++
 3 files changed, 15 insertions(+), 1 deletion(-)
 rename tests/ui/traits/next-solver/normalize/{normalize-self-type-constrains-trait-args.stderr => normalize-self-type-constrains-trait-args.current.stderr} (85%)
 create mode 100644 tests/ui/traits/next-solver/normalize/normalize-self-type-constrains-trait-args.next.stderr

diff --git a/tests/ui/traits/next-solver/normalize/normalize-self-type-constrains-trait-args.stderr b/tests/ui/traits/next-solver/normalize/normalize-self-type-constrains-trait-args.current.stderr
similarity index 85%
rename from tests/ui/traits/next-solver/normalize/normalize-self-type-constrains-trait-args.stderr
rename to tests/ui/traits/next-solver/normalize/normalize-self-type-constrains-trait-args.current.stderr
index 5554f0ccc0aa7..ef636811fd57b 100644
--- a/tests/ui/traits/next-solver/normalize/normalize-self-type-constrains-trait-args.stderr
+++ b/tests/ui/traits/next-solver/normalize/normalize-self-type-constrains-trait-args.current.stderr
@@ -1,5 +1,5 @@
 warning: the feature `lazy_type_alias` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/normalize-self-type-constrains-trait-args.rs:5:12
+  --> $DIR/normalize-self-type-constrains-trait-args.rs:8:12
    |
 LL | #![feature(lazy_type_alias)]
    |            ^^^^^^^^^^^^^^^
diff --git a/tests/ui/traits/next-solver/normalize/normalize-self-type-constrains-trait-args.next.stderr b/tests/ui/traits/next-solver/normalize/normalize-self-type-constrains-trait-args.next.stderr
new file mode 100644
index 0000000000000..ef636811fd57b
--- /dev/null
+++ b/tests/ui/traits/next-solver/normalize/normalize-self-type-constrains-trait-args.next.stderr
@@ -0,0 +1,11 @@
+warning: the feature `lazy_type_alias` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/normalize-self-type-constrains-trait-args.rs:8:12
+   |
+LL | #![feature(lazy_type_alias)]
+   |            ^^^^^^^^^^^^^^^
+   |
+   = note: see issue #112792 <https://github.com/rust-lang/rust/issues/112792> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/traits/next-solver/normalize/normalize-self-type-constrains-trait-args.rs b/tests/ui/traits/next-solver/normalize/normalize-self-type-constrains-trait-args.rs
index 0ece8f8321ce6..c2a0167134639 100644
--- a/tests/ui/traits/next-solver/normalize/normalize-self-type-constrains-trait-args.rs
+++ b/tests/ui/traits/next-solver/normalize/normalize-self-type-constrains-trait-args.rs
@@ -1,3 +1,6 @@
+//@ revisions: current next
+//@[next] compile-flags: -Znext-solver
+//@ ignore-compare-mode-next-solver (explicit revisions)
 //@ check-pass
 
 // This goal is also possible w/ a GAT, but lazy_type_alias