about summary refs log tree commit diff
path: root/tests/ui
diff options
context:
space:
mode:
authorLukas Markeffsky <@>2025-02-16 00:03:10 +0100
committerLukas Markeffsky <@>2025-02-18 13:22:45 +0100
commitd0a5bbbb8e394095848e078a3fff72beaad14209 (patch)
tree682a9f928c78bb0939173bb52163d29dd726bbcd /tests/ui
parent3b022d8ceea570db9730be34d964f0cc663a567f (diff)
downloadrust-d0a5bbbb8e394095848e078a3fff72beaad14209.tar.gz
rust-d0a5bbbb8e394095848e078a3fff72beaad14209.zip
document and test all `LayoutError` variants
Diffstat (limited to 'tests/ui')
-rw-r--r--tests/ui/layout/debug.rs5
-rw-r--r--tests/ui/layout/debug.stderr8
-rw-r--r--tests/ui/layout/normalization-failure.rs57
-rw-r--r--tests/ui/layout/normalization-failure.stderr12
4 files changed, 81 insertions, 1 deletions
diff --git a/tests/ui/layout/debug.rs b/tests/ui/layout/debug.rs
index 81dc7285254..c0adf9ec677 100644
--- a/tests/ui/layout/debug.rs
+++ b/tests/ui/layout/debug.rs
@@ -82,3 +82,8 @@ type Impossible = (str, str); //~ ERROR: cannot be known at compilation time
 #[rustc_layout(debug)]
 union EmptyUnion {} //~ ERROR: has an unknown layout
 //~^ ERROR: unions cannot have zero fields
+
+// Test the error message of `LayoutError::TooGeneric`
+// (this error is never emitted to users).
+#[rustc_layout(debug)]
+type TooGeneric<T> = T; //~ ERROR: does not have a fixed size
diff --git a/tests/ui/layout/debug.stderr b/tests/ui/layout/debug.stderr
index 319c0de26a9..d64dee4e27f 100644
--- a/tests/ui/layout/debug.stderr
+++ b/tests/ui/layout/debug.stderr
@@ -596,12 +596,18 @@ error: the type has an unknown layout
 LL | union EmptyUnion {}
    | ^^^^^^^^^^^^^^^^
 
+error: `T` does not have a fixed size
+  --> $DIR/debug.rs:89:1
+   |
+LL | type TooGeneric<T> = T;
+   | ^^^^^^^^^^^^^^^^^^
+
 error: `#[rustc_layout]` can only be applied to `struct`/`enum`/`union` declarations and type aliases
   --> $DIR/debug.rs:75:5
    |
 LL |     const C: () = ();
    |     ^^^^^^^^^^^
 
-error: aborting due to 19 previous errors
+error: aborting due to 20 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/layout/normalization-failure.rs b/tests/ui/layout/normalization-failure.rs
new file mode 100644
index 00000000000..c0f8710c03c
--- /dev/null
+++ b/tests/ui/layout/normalization-failure.rs
@@ -0,0 +1,57 @@
+//! This test demonstrates how `LayoutError::NormalizationFailure` can happen and why
+//! it is necessary.
+//!
+//! This code does not cause an immediate normalization error in typeck, because we
+//! don't reveal the hidden type returned by `opaque<T>` in the analysis typing mode.
+//! Instead, `<{opaque} as Project2>::Assoc2` is a *rigid projection*, because we know
+//! that `{opaque}: Project2` holds, due to the opaque type's `impl Project2` bound,
+//! but cannot normalize `<{opaque} as Project2>::Assoc2` any further.
+//!
+//! However, in the post-analysis typing mode, which is used for the layout computation,
+//! the opaque's hidden type is revealed to be `PhantomData<T>`, and now we fail to
+//! normalize `<PhantomData<T> as Project2>::Assoc2` if there is a `T: Project1` bound
+//! in the param env! This happens, because `PhantomData<T>: Project2` only holds if
+//! `<T as Project1>::Assoc1 == ()` holds. This would usually be satisfied by the
+//! blanket `impl<T> Project1 for T`, but due to the `T: Project1` bound we do not
+//! normalize `<T as Project1>::Assoc1` via the impl and treat it as rigid instead.
+//! Therefore, `PhantomData<T>: Project2` does NOT hold and normalizing
+//! `<PhantomData<T> as Project2>::Assoc2` fails.
+//!
+//! Note that this layout error can only happen when computing the layout in a generic
+//! context, which is not required for codegen, but may happen for lints, MIR optimizations,
+//! and the transmute check.
+
+use std::marker::PhantomData;
+
+trait Project1 {
+    type Assoc1;
+}
+
+impl<T> Project1 for T {
+    type Assoc1 = ();
+}
+
+trait Project2 {
+    type Assoc2;
+    fn get(self) -> Self::Assoc2;
+}
+
+impl<T: Project1<Assoc1 = ()>> Project2 for PhantomData<T> {
+    type Assoc2 = ();
+    fn get(self) -> Self::Assoc2 {}
+}
+
+fn opaque<T>() -> impl Project2 {
+    PhantomData::<T>
+}
+
+fn check<T: Project1>() {
+    unsafe {
+        std::mem::transmute::<_, ()>(opaque::<T>().get());
+        //~^ ERROR: cannot transmute
+        //~| NOTE: (unable to determine layout for `<impl Project2 as Project2>::Assoc2` because `<impl Project2 as Project2>::Assoc2` cannot be normalized)
+        //~| NOTE: (0 bits)
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/layout/normalization-failure.stderr b/tests/ui/layout/normalization-failure.stderr
new file mode 100644
index 00000000000..5fe38d4403a
--- /dev/null
+++ b/tests/ui/layout/normalization-failure.stderr
@@ -0,0 +1,12 @@
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> $DIR/normalization-failure.rs:50:9
+   |
+LL |         std::mem::transmute::<_, ()>(opaque::<T>().get());
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `<impl Project2 as Project2>::Assoc2` (unable to determine layout for `<impl Project2 as Project2>::Assoc2` because `<impl Project2 as Project2>::Assoc2` cannot be normalized)
+   = note: target type: `()` (0 bits)
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0512`.