From 12804230a25d4f996f4738de20c161d95df4933b Mon Sep 17 00:00:00 2001
From: LeSeulArtichaut <leseulartichaut@gmail.com>
Date: Fri, 30 Jul 2021 19:04:16 +0200
Subject: [PATCH 1/9] Properly find owner of closure in THIR unsafeck

Co-authored-by: FabianWolff <fabian.wolff@alumni.ethz.ch>
---
 compiler/rustc_mir_build/src/check_unsafety.rs | 11 ++++-------
 src/test/ui/unsafe/issue-87414-query-cycle.rs  | 15 +++++++++++++++
 2 files changed, 19 insertions(+), 7 deletions(-)
 create mode 100644 src/test/ui/unsafe/issue-87414-query-cycle.rs

diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs
index 21534290d12..d27ce6ec81a 100644
--- a/compiler/rustc_mir_build/src/check_unsafety.rs
+++ b/compiler/rustc_mir_build/src/check_unsafety.rs
@@ -599,13 +599,10 @@ pub fn check_unsafety<'tcx>(tcx: TyCtxt<'tcx>, def: ty::WithOptConstParam<LocalD
 
     // Closures are handled by their owner, if it has a body
     if tcx.is_closure(def.did.to_def_id()) {
-        let owner = tcx.hir().local_def_id_to_hir_id(def.did).owner;
-        let owner_hir_id = tcx.hir().local_def_id_to_hir_id(owner);
-
-        if tcx.hir().maybe_body_owned_by(owner_hir_id).is_some() {
-            tcx.ensure().thir_check_unsafety(owner);
-            return;
-        }
+        let hir = tcx.hir();
+        let owner = hir.enclosing_body_owner(hir.local_def_id_to_hir_id(def.did));
+        tcx.ensure().thir_check_unsafety(hir.local_def_id(owner));
+        return;
     }
 
     let (thir, expr) = tcx.thir_body(def);
diff --git a/src/test/ui/unsafe/issue-87414-query-cycle.rs b/src/test/ui/unsafe/issue-87414-query-cycle.rs
new file mode 100644
index 00000000000..99e40ba4b4c
--- /dev/null
+++ b/src/test/ui/unsafe/issue-87414-query-cycle.rs
@@ -0,0 +1,15 @@
+// Regression test for #87414.
+
+// check-pass
+// compile-flags: -Zthir-unsafeck
+
+fn bad<T>() -> Box<dyn Iterator<Item = [(); { |x: u32| { x }; 4 }]>> { todo!() }
+
+fn foo() -> [(); { |x: u32| { x }; 4 }] { todo!() }
+fn bar() { let _: [(); { |x: u32| { x }; 4 }]; }
+
+// This one should not cause any errors either:
+unsafe fn unsf() {}
+fn bad2<T>() -> Box<dyn Iterator<Item = [(); { unsafe { || { unsf() } }; 4 }]>> { todo!() }
+
+fn main() {}

From d2d851949bab4c96b54d11126a0efd1826557d3f Mon Sep 17 00:00:00 2001
From: Yuki Okushi <yuki.okushi@huawei.com>
Date: Sat, 31 Jul 2021 06:09:54 +0900
Subject: [PATCH 2/9] Fix a parser ICE on invalid `fn` body

---
 compiler/rustc_parse/src/parser/item.rs |  4 +---
 src/test/ui/parser/issue-87635.rs       |  9 +++++++++
 src/test/ui/parser/issue-87635.stderr   | 19 +++++++++++++++++++
 3 files changed, 29 insertions(+), 3 deletions(-)
 create mode 100644 src/test/ui/parser/issue-87635.rs
 create mode 100644 src/test/ui/parser/issue-87635.stderr

diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index 2ce63d011f4..1e4bc49cb39 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -1715,13 +1715,11 @@ impl<'a> Parser<'a> {
                     // the AST for typechecking.
                     err.span_label(ident.span, "while parsing this `fn`");
                     err.emit();
-                    (Vec::new(), None)
                 } else {
                     return Err(err);
                 }
-            } else {
-                unreachable!()
             }
+            (Vec::new(), None)
         };
         attrs.extend(inner_attrs);
         Ok(body)
diff --git a/src/test/ui/parser/issue-87635.rs b/src/test/ui/parser/issue-87635.rs
new file mode 100644
index 00000000000..da74c1877b1
--- /dev/null
+++ b/src/test/ui/parser/issue-87635.rs
@@ -0,0 +1,9 @@
+struct Foo {}
+
+impl Foo {
+    pub fn bar()
+    //~^ ERROR: expected `;`, found `}`
+    //~| ERROR: associated function in `impl` without body
+}
+
+fn main() {}
diff --git a/src/test/ui/parser/issue-87635.stderr b/src/test/ui/parser/issue-87635.stderr
new file mode 100644
index 00000000000..920a9f937dd
--- /dev/null
+++ b/src/test/ui/parser/issue-87635.stderr
@@ -0,0 +1,19 @@
+error: expected `;`, found `}`
+  --> $DIR/issue-87635.rs:4:17
+   |
+LL |     pub fn bar()
+   |                 ^ help: add `;` here
+...
+LL | }
+   | - unexpected token
+
+error: associated function in `impl` without body
+  --> $DIR/issue-87635.rs:4:5
+   |
+LL |     pub fn bar()
+   |     ^^^^^^^^^^^-
+   |                |
+   |                help: provide a definition for the function: `{ <body> }`
+
+error: aborting due to 2 previous errors
+

From e0172b380d8260883ddecc060996ea6f5441c54c Mon Sep 17 00:00:00 2001
From: Michael Howell <michael@notriddle.com>
Date: Sun, 1 Aug 2021 14:37:38 -0700
Subject: [PATCH 3/9] Write docs for SyncOnceCell From and Default impl

---
 library/std/src/lazy.rs | 30 ++++++++++++++++++++++++++++++
 1 file changed, 30 insertions(+)

diff --git a/library/std/src/lazy.rs b/library/std/src/lazy.rs
index ca86e569bc1..132733a0525 100644
--- a/library/std/src/lazy.rs
+++ b/library/std/src/lazy.rs
@@ -87,6 +87,19 @@ impl<T: UnwindSafe> UnwindSafe for SyncOnceCell<T> {}
 
 #[unstable(feature = "once_cell", issue = "74465")]
 impl<T> Default for SyncOnceCell<T> {
+    /// Creates a new empty cell.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// #![feature(once_cell)]
+    ///
+    /// use std::lazy::SyncOnceCell;
+    ///
+    /// fn main() {
+    ///     assert_eq!(SyncOnceCell::<()>::new(), SyncOnceCell::default());
+    /// }
+    /// ```
     fn default() -> SyncOnceCell<T> {
         SyncOnceCell::new()
     }
@@ -118,6 +131,23 @@ impl<T: Clone> Clone for SyncOnceCell<T> {
 
 #[unstable(feature = "once_cell", issue = "74465")]
 impl<T> From<T> for SyncOnceCell<T> {
+    /// Create a new cell with its contents set to `value`.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// #![feature(once_cell)]
+    ///
+    /// use std::lazy::SyncOnceCell;
+    ///
+    /// # fn main() -> Result<(), i32> {
+    /// let a = SyncOnceCell::from(3);
+    /// let b = SyncOnceCell::new();
+    /// b.set(3)?;
+    /// assert_eq!(a, b);
+    /// Ok(())
+    /// # }
+    /// ```
     fn from(value: T) -> Self {
         let cell = Self::new();
         match cell.set(value) {

From a43c464acf648e69e57e31203859797f50e53ec7 Mon Sep 17 00:00:00 2001
From: Jan-Erik Rediger <janerik@fnordig.de>
Date: Mon, 2 Aug 2021 10:28:33 +0200
Subject: [PATCH 4/9] Add `aarch64-apple-ios-sim` as a possible target to the
 manifest

This should allow rustup and similar to actually make use of this new
target now.
---
 src/tools/build-manifest/src/main.rs | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs
index 1e19b7b21d8..ab63a9e2dfa 100644
--- a/src/tools/build-manifest/src/main.rs
+++ b/src/tools/build-manifest/src/main.rs
@@ -54,6 +54,7 @@ static HOSTS: &[&str] = &[
 static TARGETS: &[&str] = &[
     "aarch64-apple-darwin",
     "aarch64-apple-ios",
+    "aarch64-apple-ios-sim",
     "aarch64-fuchsia",
     "aarch64-linux-android",
     "aarch64-pc-windows-msvc",

From a5cdff3bd42e82f58de45dd49d468a6d4c54b54b Mon Sep 17 00:00:00 2001
From: The8472 <git@infinite-source.de>
Date: Mon, 2 Aug 2021 20:28:31 +0200
Subject: [PATCH 5/9] Add convenience for handling ipv4-mapped addresses by
 canonicalizing them

This simplifies checking common properties in an address-family-agnostic
way since since #86335 commits to not checking IPv4 semantics
of IPv4-mapped addresses in the `Ipv6Addr` property methods.
---
 library/std/src/net/ip.rs | 45 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 45 insertions(+)

diff --git a/library/std/src/net/ip.rs b/library/std/src/net/ip.rs
index 88309875978..2108c62b4cd 100644
--- a/library/std/src/net/ip.rs
+++ b/library/std/src/net/ip.rs
@@ -291,6 +291,29 @@ impl IpAddr {
     pub const fn is_ipv6(&self) -> bool {
         matches!(self, IpAddr::V6(_))
     }
+
+    /// Converts this address to an `IpAddr::V4` if it is a IPv4-mapped IPv6 addresses, otherwise it
+    /// return `self` as-is.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(ip)]
+    /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
+    ///
+    /// assert_eq!(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)).to_canonical().is_loopback(), true);
+    /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1)).is_loopback(), false);
+    /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1)).to_canonical().is_loopback(), true);
+    /// ```
+    #[inline]
+    #[rustc_const_unstable(feature = "const_ip", issue = "76205")]
+    #[unstable(feature = "ip", issue = "27709")]
+    pub const fn to_canonical(&self) -> IpAddr {
+        match self {
+            &v4 @ IpAddr::V4(_) => v4,
+            IpAddr::V6(v6) => v6.to_canonical(),
+        }
+    }
 }
 
 impl Ipv4Addr {
@@ -1532,6 +1555,28 @@ impl Ipv6Addr {
         }
     }
 
+    /// Converts this address to an `IpAddr::V4` if it is a IPv4-mapped addresses, otherwise it
+    /// returns self wrapped in a `IpAddr::V6`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(ip)]
+    /// use std::net::Ipv6Addr;
+    ///
+    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1).is_loopback(), false);
+    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1).to_canonical().is_loopback(), true);
+    /// ```
+    #[inline]
+    #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
+    #[unstable(feature = "ip", issue = "27709")]
+    pub const fn to_canonical(&self) -> IpAddr {
+        if let Some(mapped) = self.to_ipv4_mapped() {
+            return IpAddr::V4(mapped);
+        }
+        IpAddr::V6(*self)
+    }
+
     /// Returns the sixteen eight-bit integers the IPv6 address consists of.
     ///
     /// ```

From 379433a0259eb63dc2a271bb792266d586aab945 Mon Sep 17 00:00:00 2001
From: noproto <noproto@users.noreply.github.com>
Date: Mon, 2 Aug 2021 20:51:32 -0400
Subject: [PATCH 6/9] Correct typo

---
 src/doc/unstable-book/src/library-features/asm.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/doc/unstable-book/src/library-features/asm.md b/src/doc/unstable-book/src/library-features/asm.md
index e950891ef92..eb08b5ad1e5 100644
--- a/src/doc/unstable-book/src/library-features/asm.md
+++ b/src/doc/unstable-book/src/library-features/asm.md
@@ -402,7 +402,7 @@ assert_eq!(a, 5);
 
 This will decrement the `{0}` register value from 10 to 3, then add 2 and store it in `a`.
 
-This example show a few thing:
+This example shows a few thing:
 
 First that the same number can be used as a label multiple times in the same inline block.
 

From c2a809c2c5a3416f719ad998af61367fcc69ff16 Mon Sep 17 00:00:00 2001
From: noproto <noproto@users.noreply.github.com>
Date: Mon, 2 Aug 2021 20:55:25 -0400
Subject: [PATCH 7/9] Another one

---
 src/doc/unstable-book/src/library-features/asm.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/doc/unstable-book/src/library-features/asm.md b/src/doc/unstable-book/src/library-features/asm.md
index eb08b5ad1e5..8ff600d5334 100644
--- a/src/doc/unstable-book/src/library-features/asm.md
+++ b/src/doc/unstable-book/src/library-features/asm.md
@@ -402,7 +402,7 @@ assert_eq!(a, 5);
 
 This will decrement the `{0}` register value from 10 to 3, then add 2 and store it in `a`.
 
-This example shows a few thing:
+This example shows a few things:
 
 First that the same number can be used as a label multiple times in the same inline block.
 

From 157e0a0e8f68ab997b320a2d61c2d8ad20d5ce86 Mon Sep 17 00:00:00 2001
From: Nathaniel McCallum <nathaniel@congru.us>
Date: Mon, 2 Aug 2021 15:03:43 -0400
Subject: [PATCH 8/9] Validate that naked functions are never inlined

Reject all uses of the inline attribute on naked functions.

rust-lang/rfcs#2774
rust-lang/rfcs#2972
---
 compiler/rustc_lint_defs/src/builtin.rs      |  3 ++
 compiler/rustc_passes/src/naked_functions.rs | 12 ++++-
 src/test/ui/asm/naked-functions.rs           | 43 +++++++++++++++
 src/test/ui/asm/naked-functions.stderr       | 56 +++++++++++++++++++-
 4 files changed, 112 insertions(+), 2 deletions(-)

diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index 7195c41eae9..b1948ae072b 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -2720,6 +2720,9 @@ declare_lint! {
     /// The asm block must not contain any operands other than `const` and
     /// `sym`. Additionally, naked function should specify a non-Rust ABI.
     ///
+    /// Naked functions cannot be inlined. All forms of the `inline` attribute
+    /// are prohibited.
+    ///
     /// While other definitions of naked functions were previously accepted,
     /// they are unsupported and might not work reliably. This is a
     /// [future-incompatible] lint that will transition into hard error in
diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs
index 89bc2e1a987..e05ec205b65 100644
--- a/compiler/rustc_passes/src/naked_functions.rs
+++ b/compiler/rustc_passes/src/naked_functions.rs
@@ -1,6 +1,6 @@
 //! Checks validity of naked functions.
 
-use rustc_ast::InlineAsmOptions;
+use rustc_ast::{Attribute, InlineAsmOptions};
 use rustc_hir as hir;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::intravisit::{ErasedMap, FnKind, NestedVisitorMap, Visitor};
@@ -70,10 +70,20 @@ impl<'tcx> Visitor<'tcx> for CheckNakedFunctions<'tcx> {
             check_no_patterns(self.tcx, body.params);
             check_no_parameters_use(self.tcx, body);
             check_asm(self.tcx, hir_id, body, span);
+            check_inline(self.tcx, hir_id, attrs);
         }
     }
 }
 
+/// Check that the function isn't inlined.
+fn check_inline(tcx: TyCtxt<'_>, hir_id: HirId, attrs: &[Attribute]) {
+    for attr in attrs.iter().filter(|attr| attr.has_name(sym::inline)) {
+        tcx.struct_span_lint_hir(UNSUPPORTED_NAKED_FUNCTIONS, hir_id, attr.span, |lint| {
+            lint.build("naked functions cannot be inlined").emit();
+        });
+    }
+}
+
 /// Checks that function uses non-Rust ABI.
 fn check_abi(tcx: TyCtxt<'_>, hir_id: HirId, abi: Abi, fn_ident_span: Span) {
     if abi == Abi::Rust {
diff --git a/src/test/ui/asm/naked-functions.rs b/src/test/ui/asm/naked-functions.rs
index a46ca4544a6..7075995c2cf 100644
--- a/src/test/ui/asm/naked-functions.rs
+++ b/src/test/ui/asm/naked-functions.rs
@@ -167,3 +167,46 @@ pub unsafe extern "C" fn valid_c() {
 pub unsafe extern "C" fn valid_att_syntax() {
     asm!("", options(noreturn, att_syntax));
 }
+
+#[naked]
+pub unsafe extern "C" fn inline_none() {
+    asm!("", options(noreturn));
+}
+
+#[naked]
+#[inline]
+//~^ WARN naked functions cannot be inlined
+//~| WARN this was previously accepted
+pub unsafe extern "C" fn inline_hint() {
+    asm!("", options(noreturn));
+}
+
+#[naked]
+#[inline(always)]
+//~^ WARN naked functions cannot be inlined
+//~| WARN this was previously accepted
+pub unsafe extern "C" fn inline_always() {
+    asm!("", options(noreturn));
+}
+
+#[naked]
+#[inline(never)]
+//~^ WARN naked functions cannot be inlined
+//~| WARN this was previously accepted
+pub unsafe extern "C" fn inline_never() {
+    asm!("", options(noreturn));
+}
+
+#[naked]
+#[inline]
+//~^ WARN naked functions cannot be inlined
+//~| WARN this was previously accepted
+#[inline(always)]
+//~^ WARN naked functions cannot be inlined
+//~| WARN this was previously accepted
+#[inline(never)]
+//~^ WARN naked functions cannot be inlined
+//~| WARN this was previously accepted
+pub unsafe extern "C" fn inline_all() {
+    asm!("", options(noreturn));
+}
diff --git a/src/test/ui/asm/naked-functions.stderr b/src/test/ui/asm/naked-functions.stderr
index 9a82da8d90d..2a186a69ff4 100644
--- a/src/test/ui/asm/naked-functions.stderr
+++ b/src/test/ui/asm/naked-functions.stderr
@@ -296,5 +296,59 @@ LL | pub unsafe extern "Rust" fn rust_abi() {
    = 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 #32408 <https://github.com/rust-lang/rust/issues/32408>
 
-error: aborting due to 8 previous errors; 19 warnings emitted
+warning: naked functions cannot be inlined
+  --> $DIR/naked-functions.rs:177:1
+   |
+LL | #[inline]
+   | ^^^^^^^^^
+   |
+   = 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 #32408 <https://github.com/rust-lang/rust/issues/32408>
+
+warning: naked functions cannot be inlined
+  --> $DIR/naked-functions.rs:185:1
+   |
+LL | #[inline(always)]
+   | ^^^^^^^^^^^^^^^^^
+   |
+   = 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 #32408 <https://github.com/rust-lang/rust/issues/32408>
+
+warning: naked functions cannot be inlined
+  --> $DIR/naked-functions.rs:193:1
+   |
+LL | #[inline(never)]
+   | ^^^^^^^^^^^^^^^^
+   |
+   = 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 #32408 <https://github.com/rust-lang/rust/issues/32408>
+
+warning: naked functions cannot be inlined
+  --> $DIR/naked-functions.rs:201:1
+   |
+LL | #[inline]
+   | ^^^^^^^^^
+   |
+   = 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 #32408 <https://github.com/rust-lang/rust/issues/32408>
+
+warning: naked functions cannot be inlined
+  --> $DIR/naked-functions.rs:204:1
+   |
+LL | #[inline(always)]
+   | ^^^^^^^^^^^^^^^^^
+   |
+   = 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 #32408 <https://github.com/rust-lang/rust/issues/32408>
+
+warning: naked functions cannot be inlined
+  --> $DIR/naked-functions.rs:207:1
+   |
+LL | #[inline(never)]
+   | ^^^^^^^^^^^^^^^^
+   |
+   = 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 #32408 <https://github.com/rust-lang/rust/issues/32408>
+
+error: aborting due to 8 previous errors; 25 warnings emitted
 

From b23de51dcbd8f50094a716c0d99b44fdfa68e474 Mon Sep 17 00:00:00 2001
From: Caleb Zulawski <caleb.zulawski@gmail.com>
Date: Tue, 3 Aug 2021 03:33:09 +0000
Subject: [PATCH 9/9] Allow generic SIMD array element type

---
 compiler/rustc_typeck/src/check/check.rs      |  1 +
 src/test/ui/simd/simd-generics.rs             | 56 ++++++++++++++-----
 ...-generic-monomorphisation-non-primitive.rs | 14 +++++
 ...eric-monomorphisation-non-primitive.stderr |  4 ++
 4 files changed, 61 insertions(+), 14 deletions(-)
 create mode 100644 src/test/ui/simd/simd-type-generic-monomorphisation-non-primitive.rs
 create mode 100644 src/test/ui/simd/simd-type-generic-monomorphisation-non-primitive.stderr

diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs
index b5db3331d04..ba99e0c03d8 100644
--- a/compiler/rustc_typeck/src/check/check.rs
+++ b/compiler/rustc_typeck/src/check/check.rs
@@ -1220,6 +1220,7 @@ pub fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) {
             match e.kind() {
                 ty::Param(_) => (), // pass struct<T>(T, T, T, T) through, let monomorphization catch errors
                 ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::RawPtr(_) => (), // struct(u8, u8, u8, u8) is ok
+                ty::Array(t, _) if matches!(t.kind(), ty::Param(_)) => (), // pass struct<T>([T; N]) through, let monomorphization catch errors
                 ty::Array(t, _clen)
                     if matches!(
                         t.kind(),
diff --git a/src/test/ui/simd/simd-generics.rs b/src/test/ui/simd/simd-generics.rs
index 50a4bfd9f51..fa9d35ee4df 100644
--- a/src/test/ui/simd/simd-generics.rs
+++ b/src/test/ui/simd/simd-generics.rs
@@ -10,7 +10,15 @@ struct f32x4(f32, f32, f32, f32);
 
 #[repr(simd)]
 #[derive(Copy, Clone)]
-struct S<const N: usize>([f32; N]);
+struct A<const N: usize>([f32; N]);
+
+#[repr(simd)]
+#[derive(Copy, Clone)]
+struct B<T>([T; 4]);
+
+#[repr(simd)]
+#[derive(Copy, Clone)]
+struct C<T, const N: usize>([T; N]);
 
 
 extern "platform-intrinsic" {
@@ -29,7 +37,23 @@ impl ops::Add for f32x4 {
     }
 }
 
-impl ops::Add for S<4> {
+impl ops::Add for A<4> {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        unsafe { simd_add(self, rhs) }
+    }
+}
+
+impl ops::Add for B<f32> {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        unsafe { simd_add(self, rhs) }
+    }
+}
+
+impl ops::Add for C<f32, 4> {
     type Output = Self;
 
     fn add(self, rhs: Self) -> Self {
@@ -39,19 +63,23 @@ impl ops::Add for S<4> {
 
 
 pub fn main() {
-    let lr = f32x4(1.0f32, 2.0f32, 3.0f32, 4.0f32);
+    let x = [1.0f32, 2.0f32, 3.0f32, 4.0f32];
+    let y = [2.0f32, 4.0f32, 6.0f32, 8.0f32];
 
     // lame-o
-    let f32x4(x, y, z, w) = add(lr, lr);
-    assert_eq!(x, 2.0f32);
-    assert_eq!(y, 4.0f32);
-    assert_eq!(z, 6.0f32);
-    assert_eq!(w, 8.0f32);
+    let a = f32x4(1.0f32, 2.0f32, 3.0f32, 4.0f32);
+    let f32x4(a0, a1, a2, a3) = add(a, a);
+    assert_eq!(a0, 2.0f32);
+    assert_eq!(a1, 4.0f32);
+    assert_eq!(a2, 6.0f32);
+    assert_eq!(a3, 8.0f32);
 
-    let lr2 = S::<4>([1.0f32, 2.0f32, 3.0f32, 4.0f32]);
-    let [x, y, z, w] = add(lr2, lr2).0;
-    assert_eq!(x, 2.0f32);
-    assert_eq!(y, 4.0f32);
-    assert_eq!(z, 6.0f32);
-    assert_eq!(w, 8.0f32);
+    let a = A(x);
+    assert_eq!(add(a, a).0, y);
+
+    let b = B(x);
+    assert_eq!(add(b, b).0, y);
+
+    let c = C(x);
+    assert_eq!(add(c, c).0, y);
 }
diff --git a/src/test/ui/simd/simd-type-generic-monomorphisation-non-primitive.rs b/src/test/ui/simd/simd-type-generic-monomorphisation-non-primitive.rs
new file mode 100644
index 00000000000..0bc73b15580
--- /dev/null
+++ b/src/test/ui/simd/simd-type-generic-monomorphisation-non-primitive.rs
@@ -0,0 +1,14 @@
+// build-fail
+
+#![feature(repr_simd)]
+
+struct E;
+
+// error-pattern:monomorphising SIMD type `S<E>` with a non-primitive-scalar (integer/float/pointer) element type `E`
+
+#[repr(simd)]
+struct S<T>([T; 4]);
+
+fn main() {
+    let _v: Option<S<E>> = None;
+}
diff --git a/src/test/ui/simd/simd-type-generic-monomorphisation-non-primitive.stderr b/src/test/ui/simd/simd-type-generic-monomorphisation-non-primitive.stderr
new file mode 100644
index 00000000000..9e8f06b824c
--- /dev/null
+++ b/src/test/ui/simd/simd-type-generic-monomorphisation-non-primitive.stderr
@@ -0,0 +1,4 @@
+error: monomorphising SIMD type `S<E>` with a non-primitive-scalar (integer/float/pointer) element type `E`
+
+error: aborting due to previous error
+