From d0b99e3efe62b5acc107da9c84331eae6cbe5a0d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= <me@fmease.dev>
Date: Tue, 17 Oct 2023 03:06:52 +0200
Subject: [PATCH] Make `#[repr(Rust)]` and `#[repr(C)]` incompatible with one
 another

---
 compiler/rustc_passes/src/check_attr.rs       | 13 +++++--
 compiler/rustc_passes/src/errors.rs           |  9 ++++-
 tests/ui/repr/explicit-rust-repr-conflicts.rs | 23 +++++++++++
 .../repr/explicit-rust-repr-conflicts.stderr  | 39 +++++++++++++++++++
 4 files changed, 80 insertions(+), 4 deletions(-)
 create mode 100644 tests/ui/repr/explicit-rust-repr-conflicts.rs
 create mode 100644 tests/ui/repr/explicit-rust-repr-conflicts.stderr

diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 9a7564cb213..d92923e78ff 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -1767,6 +1767,7 @@ impl CheckAttrVisitor<'_> {
             .collect();
 
         let mut int_reprs = 0;
+        let mut is_explicit_rust = false;
         let mut is_c = false;
         let mut is_simd = false;
         let mut is_transparent = false;
@@ -1778,7 +1779,9 @@ impl CheckAttrVisitor<'_> {
             }
 
             match hint.name_or_empty() {
-                sym::Rust => {}
+                sym::Rust => {
+                    is_explicit_rust = true;
+                }
                 sym::C => {
                     is_c = true;
                     match target {
@@ -1888,12 +1891,16 @@ impl CheckAttrVisitor<'_> {
 
         // Error on repr(transparent, <anything else>).
         if is_transparent && hints.len() > 1 {
-            let hint_spans: Vec<_> = hint_spans.clone().collect();
+            let hint_spans = hint_spans.clone().collect();
             self.tcx.sess.emit_err(errors::TransparentIncompatible {
                 hint_spans,
                 target: target.to_string(),
             });
         }
+        if is_explicit_rust && (int_reprs > 0 || is_c || is_simd) {
+            let hint_spans = hint_spans.clone().collect();
+            self.tcx.sess.emit_err(errors::ReprConflicting { hint_spans });
+        }
         // Warn on repr(u8, u16), repr(C, simd), and c-like-enum-repr(C, u8)
         if (int_reprs > 1)
             || (is_simd && is_c)
@@ -1910,7 +1917,7 @@ impl CheckAttrVisitor<'_> {
                 CONFLICTING_REPR_HINTS,
                 hir_id,
                 hint_spans.collect::<Vec<Span>>(),
-                errors::ReprConflicting,
+                errors::ReprConflictingLint,
             );
         }
     }
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index bcf5abbfe7d..f4a6bf017d6 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -558,9 +558,16 @@ pub struct ReprIdent {
     pub span: Span,
 }
 
+#[derive(Diagnostic)]
+#[diag(passes_repr_conflicting, code = "E0566")]
+pub struct ReprConflicting {
+    #[primary_span]
+    pub hint_spans: Vec<Span>,
+}
+
 #[derive(LintDiagnostic)]
 #[diag(passes_repr_conflicting, code = "E0566")]
-pub struct ReprConflicting;
+pub struct ReprConflictingLint;
 
 #[derive(Diagnostic)]
 #[diag(passes_used_static)]
diff --git a/tests/ui/repr/explicit-rust-repr-conflicts.rs b/tests/ui/repr/explicit-rust-repr-conflicts.rs
new file mode 100644
index 00000000000..22dd12d316a
--- /dev/null
+++ b/tests/ui/repr/explicit-rust-repr-conflicts.rs
@@ -0,0 +1,23 @@
+#[repr(C, Rust)] //~ ERROR conflicting representation hints
+struct S {
+    a: i32,
+}
+
+
+#[repr(Rust)] //~ ERROR conflicting representation hints
+#[repr(C)]
+struct T {
+    a: i32,
+}
+
+#[repr(Rust, u64)] //~ ERROR conflicting representation hints
+enum U {
+    V,
+}
+
+#[repr(Rust, simd)]
+//~^ ERROR conflicting representation hints
+//~| ERROR SIMD types are experimental and possibly buggy
+struct F32x4(f32, f32, f32, f32);
+
+fn main() {}
diff --git a/tests/ui/repr/explicit-rust-repr-conflicts.stderr b/tests/ui/repr/explicit-rust-repr-conflicts.stderr
new file mode 100644
index 00000000000..7126da574b6
--- /dev/null
+++ b/tests/ui/repr/explicit-rust-repr-conflicts.stderr
@@ -0,0 +1,39 @@
+error[E0658]: SIMD types are experimental and possibly buggy
+  --> $DIR/explicit-rust-repr-conflicts.rs:18:1
+   |
+LL | #[repr(Rust, simd)]
+   | ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #27731 <https://github.com/rust-lang/rust/issues/27731> for more information
+   = help: add `#![feature(repr_simd)]` to the crate attributes to enable
+
+error[E0566]: conflicting representation hints
+  --> $DIR/explicit-rust-repr-conflicts.rs:1:8
+   |
+LL | #[repr(C, Rust)]
+   |        ^  ^^^^
+
+error[E0566]: conflicting representation hints
+  --> $DIR/explicit-rust-repr-conflicts.rs:7:8
+   |
+LL | #[repr(Rust)]
+   |        ^^^^
+LL | #[repr(C)]
+   |        ^
+
+error[E0566]: conflicting representation hints
+  --> $DIR/explicit-rust-repr-conflicts.rs:13:8
+   |
+LL | #[repr(Rust, u64)]
+   |        ^^^^  ^^^
+
+error[E0566]: conflicting representation hints
+  --> $DIR/explicit-rust-repr-conflicts.rs:18:8
+   |
+LL | #[repr(Rust, simd)]
+   |        ^^^^  ^^^^
+
+error: aborting due to 5 previous errors
+
+Some errors have detailed explanations: E0566, E0658.
+For more information about an error, try `rustc --explain E0566`.