From 396cf1e1f51ed37e320f47e0c7ff0dc7ddcb288b Mon Sep 17 00:00:00 2001
From: Ralf Jung <post@ralfj.de>
Date: Sat, 17 Feb 2024 09:57:24 +0100
Subject: [PATCH 1/3] require simd_insert, simd_extract indices to be constants

---
 compiler/rustc_borrowck/messages.ftl          |  8 ++++++-
 .../rustc_borrowck/src/session_diagnostics.rs |  6 ++++--
 compiler/rustc_borrowck/src/type_check/mod.rs | 21 +++++++++++++++----
 compiler/rustc_codegen_ssa/src/mir/block.rs   |  3 +--
 4 files changed, 29 insertions(+), 9 deletions(-)

diff --git a/compiler/rustc_borrowck/messages.ftl b/compiler/rustc_borrowck/messages.ftl
index 8c5a1d89709..bf14d5eb9a0 100644
--- a/compiler/rustc_borrowck/messages.ftl
+++ b/compiler/rustc_borrowck/messages.ftl
@@ -163,7 +163,13 @@ borrowck_returned_lifetime_wrong =
 borrowck_returned_ref_escaped =
     returns a reference to a captured variable which escapes the closure body
 
-borrowck_simd_shuffle_last_const = last argument of `simd_shuffle` is required to be a `const` item
+borrowck_simd_intrinsic_arg_const =
+    {$arg ->
+        [1] 1st
+        [2] 2nd
+        [3] 3rd
+        *[other] {$arg}th
+    } argument of `{$intrinsic}` is required to be a `const` item
 
 borrowck_suggest_create_freash_reborrow =
     consider reborrowing the `Pin` instead of moving it
diff --git a/compiler/rustc_borrowck/src/session_diagnostics.rs b/compiler/rustc_borrowck/src/session_diagnostics.rs
index 1685624f247..a055ce95e8e 100644
--- a/compiler/rustc_borrowck/src/session_diagnostics.rs
+++ b/compiler/rustc_borrowck/src/session_diagnostics.rs
@@ -454,8 +454,10 @@ pub(crate) enum TypeNoCopy<'a, 'tcx> {
 }
 
 #[derive(Diagnostic)]
-#[diag(borrowck_simd_shuffle_last_const)]
-pub(crate) struct SimdShuffleLastConst {
+#[diag(borrowck_simd_intrinsic_arg_const)]
+pub(crate) struct SimdIntrinsicArgConst {
     #[primary_span]
     pub span: Span,
+    pub arg: usize,
+    pub intrinsic: String,
 }
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index 64469727d0d..5d5ed62e731 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -49,7 +49,7 @@ use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
 use rustc_mir_dataflow::move_paths::MoveData;
 use rustc_mir_dataflow::ResultsCursor;
 
-use crate::session_diagnostics::{MoveUnsized, SimdShuffleLastConst};
+use crate::session_diagnostics::{MoveUnsized, SimdIntrinsicArgConst};
 use crate::{
     borrow_set::BorrowSet,
     constraints::{OutlivesConstraint, OutlivesConstraintSet},
@@ -1666,9 +1666,22 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
 
         let func_ty = func.ty(body, self.infcx.tcx);
         if let ty::FnDef(def_id, _) = *func_ty.kind() {
-            if let Some(sym::simd_shuffle) = self.tcx().intrinsic(def_id) {
-                if !matches!(args[2], Spanned { node: Operand::Constant(_), .. }) {
-                    self.tcx().dcx().emit_err(SimdShuffleLastConst { span: term.source_info.span });
+            // Some of the SIMD intrinsics are special: they need a particular argument to be a constant.
+            // (Eventually this should use const-generics, but those are not up for the task yet:
+            // https://github.com/rust-lang/rust/issues/85229.)
+            if let Some(name @ (sym::simd_shuffle | sym::simd_insert | sym::simd_extract)) =
+                self.tcx().intrinsic(def_id)
+            {
+                let idx = match name {
+                    sym::simd_shuffle => 2,
+                    _ => 1,
+                };
+                if !matches!(args[idx], Spanned { node: Operand::Constant(_), .. }) {
+                    self.tcx().dcx().emit_err(SimdIntrinsicArgConst {
+                        span: term.source_info.span,
+                        arg: idx + 1,
+                        intrinsic: name.to_string(),
+                    });
                 }
             }
         }
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index 75d413dedad..00007110938 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -864,8 +864,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     .map(|(i, arg)| {
                         // The indices passed to simd_shuffle in the
                         // third argument must be constant. This is
-                        // checked by const-qualification, which also
-                        // promotes any complex rvalues to constants.
+                        // checked by the type-checker.
                         if i == 2 && intrinsic == sym::simd_shuffle {
                             if let mir::Operand::Constant(constant) = &arg.node {
                                 let (llval, ty) = self.simd_shuffle_indices(bx, constant);

From 90f5fed05b8a48e52a9844ac3e542d3a077e3519 Mon Sep 17 00:00:00 2001
From: Ralf Jung <post@ralfj.de>
Date: Tue, 20 Feb 2024 07:58:18 +0100
Subject: [PATCH 2/3] update tests

---
 tests/ui/simd/array-trait.rs     |  9 ++-------
 tests/ui/simd/array-trait.stderr | 16 ++--------------
 tests/ui/simd/array-type.rs      | 16 ++++------------
 3 files changed, 8 insertions(+), 33 deletions(-)

diff --git a/tests/ui/simd/array-trait.rs b/tests/ui/simd/array-trait.rs
index bf1e219460f..55fec7a3948 100644
--- a/tests/ui/simd/array-trait.rs
+++ b/tests/ui/simd/array-trait.rs
@@ -33,12 +33,7 @@ extern "platform-intrinsic" {
 pub fn main() {
     let mut t = T::<i32x4>([0; 4]);
     unsafe {
-        for i in 0_i32..4 {
-            t = simd_insert(t, i as u32, i);
-        }
-        for i in 0_i32..4 {
-            assert_eq!(i, simd_extract(t, i as u32));
-            //~^ ERROR: use of moved value: `t`
-        }
+        t = simd_insert(t, 3, 3);
+        assert_eq!(3, simd_extract(t, 3));
     }
 }
diff --git a/tests/ui/simd/array-trait.stderr b/tests/ui/simd/array-trait.stderr
index bbaead569df..16ff732396d 100644
--- a/tests/ui/simd/array-trait.stderr
+++ b/tests/ui/simd/array-trait.stderr
@@ -23,18 +23,6 @@ LL | pub struct T<S: Simd>([S::Lane; S::SIZE]);
    = help: try adding a `where` bound using this expression: `where [(); S::SIZE]:`
    = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error[E0382]: use of moved value: `t`
-  --> $DIR/array-trait.rs:40:40
-   |
-LL |     let mut t = T::<i32x4>([0; 4]);
-   |         ----- move occurs because `t` has type `T<i32x4>`, which does not implement the `Copy` trait
-...
-LL |         for i in 0_i32..4 {
-   |         ----------------- inside of this loop
-LL |             assert_eq!(i, simd_extract(t, i as u32));
-   |                                        ^ value moved here, in previous iteration of loop
+error: aborting due to 3 previous errors
 
-error: aborting due to 4 previous errors
-
-Some errors have detailed explanations: E0077, E0382.
-For more information about an error, try `rustc --explain E0077`.
+For more information about this error, try `rustc --explain E0077`.
diff --git a/tests/ui/simd/array-type.rs b/tests/ui/simd/array-type.rs
index c9f5ed0d031..0864c3e7418 100644
--- a/tests/ui/simd/array-type.rs
+++ b/tests/ui/simd/array-type.rs
@@ -22,21 +22,13 @@ pub fn main() {
     let mut s = S([0; 4]);
 
     unsafe {
-        for i in 0_i32..4 {
-            s = simd_insert(s, i as u32, i);
-        }
-        for i in 0_i32..4 {
-            assert_eq!(i, simd_extract(s, i as u32));
-        }
+        s = simd_insert(s, 3, 3);
+        assert_eq!(3, simd_extract(s, 3));
     }
 
     let mut t = T::<4>([0; 4]);
     unsafe {
-        for i in 0_i32..4 {
-            t = simd_insert(t, i as u32, i);
-        }
-        for i in 0_i32..4 {
-            assert_eq!(i, simd_extract(t, i as u32));
-        }
+        t = simd_insert(t, 3, 3);
+        assert_eq!(3, simd_extract(t, 3));
     }
 }

From e19f89b5ffaffb680ba72e1918cd74ae101cff51 Mon Sep 17 00:00:00 2001
From: Ralf Jung <post@ralfj.de>
Date: Tue, 20 Feb 2024 08:37:47 +0100
Subject: [PATCH 3/3] delete a test that no longer makes sense

---
 .../simd-intrinsic-generic-extract-insert.rs  | 47 -------------------
 1 file changed, 47 deletions(-)
 delete mode 100644 tests/codegen/simd-intrinsic/simd-intrinsic-generic-extract-insert.rs

diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-extract-insert.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-extract-insert.rs
deleted file mode 100644
index a5d2509d000..00000000000
--- a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-extract-insert.rs
+++ /dev/null
@@ -1,47 +0,0 @@
-// compile-flags: -C no-prepopulate-passes
-
-#![crate_type = "lib"]
-
-#![feature(repr_simd, platform_intrinsics, min_const_generics)]
-#![allow(non_camel_case_types)]
-
-#[repr(simd)]
-#[derive(Copy, Clone)]
-pub struct M(pub f32, pub f32, pub f32, pub f32);
-
-#[repr(simd)]
-#[derive(Copy, Clone)]
-pub struct S<const N: usize>([f32; N]);
-
-extern "platform-intrinsic" {
-    fn simd_extract<T, U>(x: T, idx: u32) -> U;
-    fn simd_insert<T, U>(x: T, idx: u32, b: U) -> T;
-}
-
-// CHECK-LABEL: @extract_m
-#[no_mangle]
-pub unsafe fn extract_m(v: M, i: u32) -> f32  {
-    // CHECK: extractelement <4 x float> %{{v|1|2}}, i32 %i
-    simd_extract(v, i)
-}
-
-// CHECK-LABEL: @extract_s
-#[no_mangle]
-pub unsafe fn extract_s(v: S<4>, i: u32) -> f32  {
-    // CHECK: extractelement <4 x float> %{{v|1|2}}, i32 %i
-    simd_extract(v, i)
-}
-
-// CHECK-LABEL: @insert_m
-#[no_mangle]
-pub unsafe fn insert_m(v: M, i: u32, j: f32) -> M  {
-    // CHECK: insertelement <4 x float> %{{v|0|1}}, float %j, i32 %i
-    simd_insert(v, i, j)
-}
-
-// CHECK-LABEL: @insert_s
-#[no_mangle]
-pub unsafe fn insert_s(v: S<4>, i: u32, j: f32) -> S<4>  {
-    // CHECK: insertelement <4 x float> %{{v|0|1}}, float %j, i32 %i
-    simd_insert(v, i, j)
-}