about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_middle/messages.ftl3
-rw-r--r--compiler/rustc_middle/src/ty/layout.rs5
-rw-r--r--compiler/rustc_middle/src/values.rs6
-rw-r--r--src/librustdoc/html/templates/type_layout.html93
-rw-r--r--src/tools/miri/tests/fail/layout_cycle.rs28
-rw-r--r--src/tools/miri/tests/fail/layout_cycle.stderr28
6 files changed, 119 insertions, 44 deletions
diff --git a/compiler/rustc_middle/messages.ftl b/compiler/rustc_middle/messages.ftl
index bd9d89deee1..c6bbf2ef0cd 100644
--- a/compiler/rustc_middle/messages.ftl
+++ b/compiler/rustc_middle/messages.ftl
@@ -32,6 +32,9 @@ middle_values_too_big =
 middle_cannot_be_normalized =
     unable to determine layout for `{$ty}` because `{$failure_ty}` cannot be normalized
 
+middle_cycle =
+    a cycle occurred during layout computation
+
 middle_strict_coherence_needs_negative_coherence =
     to use `strict_coherence` on this trait, the `with_negative_coherence` feature must be enabled
     .label = due to this attribute
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index 6e6b7c39ecb..f2a2e67cf82 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -210,6 +210,7 @@ pub enum LayoutError<'tcx> {
     Unknown(Ty<'tcx>),
     SizeOverflow(Ty<'tcx>),
     NormalizationFailure(Ty<'tcx>, NormalizationError<'tcx>),
+    Cycle,
 }
 
 impl IntoDiagnostic<'_, !> for LayoutError<'_> {
@@ -230,6 +231,9 @@ impl IntoDiagnostic<'_, !> for LayoutError<'_> {
                 diag.set_arg("failure_ty", e.get_type_for_failure());
                 diag.set_primary_message(fluent::middle_cannot_be_normalized);
             }
+            LayoutError::Cycle => {
+                diag.set_primary_message(fluent::middle_cycle);
+            }
         }
         diag
     }
@@ -250,6 +254,7 @@ impl<'tcx> fmt::Display for LayoutError<'tcx> {
                 t,
                 e.get_type_for_failure()
             ),
+            LayoutError::Cycle => write!(f, "a cycle occurred during layout computation"),
         }
     }
 }
diff --git a/compiler/rustc_middle/src/values.rs b/compiler/rustc_middle/src/values.rs
index 5c38c0acc7f..c62c33d4dfc 100644
--- a/compiler/rustc_middle/src/values.rs
+++ b/compiler/rustc_middle/src/values.rs
@@ -106,6 +106,12 @@ impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::EarlyBinder<ty::Binder<'_, ty::F
     }
 }
 
+impl<'tcx, T> Value<TyCtxt<'tcx>, DepKind> for Result<T, ty::layout::LayoutError<'_>> {
+    fn from_cycle_error(_tcx: TyCtxt<'tcx>, _cycle: &[QueryInfo<DepKind>]) -> Self {
+        Err(ty::layout::LayoutError::Cycle)
+    }
+}
+
 // item_and_field_ids should form a cycle where each field contains the
 // type in the next element in the list
 pub fn recursive_type_error(
diff --git a/src/librustdoc/html/templates/type_layout.html b/src/librustdoc/html/templates/type_layout.html
index 58b220c7428..20e09a54805 100644
--- a/src/librustdoc/html/templates/type_layout.html
+++ b/src/librustdoc/html/templates/type_layout.html
@@ -1,53 +1,58 @@
-<h2 id="layout" class="small-section-header">  {# #}
+<h2 id="layout" class="small-section-header"> {# #}
     Layout<a href="#layout" class="anchor">§</a> {# #}
 </h2> {# #}
 <div class="docblock"> {# #}
     {% match type_layout_size %}
-        {% when Ok(type_layout_size) %}
-            <div class="warning"> {# #}
-                <p> {# #}
-                    <strong>Note:</strong> Most layout information is <strong>completely {#+ #}
-                    unstable</strong> and may even differ between compilations. {#+ #}
-                    The only exception is types with certain <code>repr(...)</code> {#+ #}
-                    attributes. Please see the Rust Reference’s {#+ #}
-                    <a href="https://doc.rust-lang.org/reference/type-layout.html">“Type Layout”</a> {#+ #}
-                    chapter for details on type layout guarantees. {# #}
-                </p> {# #}
-            </div> {# #}
-            <p><strong>Size:</strong> {{ type_layout_size|safe }}</p> {# #}
-            {% if !variants.is_empty() %}
-                <p> {# #}
-                    <strong>Size for each variant:</strong> {# #}
-                </p> {# #}
-                <ul> {# #}
-                    {% for (name, layout_size) in variants %}
-                        <li> {# #}
-                            <code>{{ name }}</code>: {#+ #}
-                            {{ layout_size|safe }}
-                        </li> {# #}
-                    {% endfor %}
-                </ul> {# #}
-            {% endif %}
-        {# This kind of layout error can occur with valid code, e.g. if you try to
-           get the layout of a generic type such as `Vec<T>`. #}
+    {% when Ok(type_layout_size) %}
+    <div class="warning"> {# #}
+        <p> {# #}
+            <strong>Note:</strong> Most layout information is <strong>completely {#+ #}
+                unstable</strong> and may even differ between compilations. {#+ #}
+            The only exception is types with certain <code>repr(...)</code> {#+ #}
+            attributes. Please see the Rust Reference’s {#+ #}
+            <a href="https://doc.rust-lang.org/reference/type-layout.html">“Type Layout”</a> {#+ #}
+            chapter for details on type layout guarantees. {# #}
+        </p> {# #}
+    </div> {# #}
+    <p><strong>Size:</strong> {{ type_layout_size|safe }}</p> {# #}
+    {% if !variants.is_empty() %}
+    <p> {# #}
+        <strong>Size for each variant:</strong> {# #}
+    </p> {# #}
+    <ul> {# #}
+        {% for (name, layout_size) in variants %}
+        <li> {# #}
+            <code>{{ name }}</code>: {#+ #}
+            {{ layout_size|safe }}
+        </li> {# #}
+        {% endfor %}
+    </ul> {# #}
+    {% endif %}
+    {# This kind of layout error can occur with valid code, e.g. if you try to
+    get the layout of a generic type such as `Vec<T>`. #}
         {% when Err(LayoutError::Unknown(_)) %}
-            <p> {# #}
-                <strong>Note:</strong> Unable to compute type layout, {#+ #}
-                possibly due to this type having generic parameters. {#+ #}
-                Layout can only be computed for concrete, fully-instantiated types. {# #}
-            </p> {# #}
+        <p> {# #}
+            <strong>Note:</strong> Unable to compute type layout, {#+ #}
+            possibly due to this type having generic parameters. {#+ #}
+            Layout can only be computed for concrete, fully-instantiated types. {# #}
+        </p> {# #}
         {# This kind of error probably can't happen with valid code, but we don't
-           want to panic and prevent the docs from building, so we just let the
-           user know that we couldn't compute the layout. #}
+        want to panic and prevent the docs from building, so we just let the
+        user know that we couldn't compute the layout. #}
         {% when Err(LayoutError::SizeOverflow(_)) %}
-            <p> {# #}
-                <strong>Note:</strong> Encountered an error during type layout; {#+ #}
-                the type was too big. {# #}
-            </p> {# #}
+        <p> {# #}
+            <strong>Note:</strong> Encountered an error during type layout; {#+ #}
+            the type was too big. {# #}
+        </p> {# #}
         {% when Err(LayoutError::NormalizationFailure(_, _)) %}
-            <p> {# #}
-                <strong>Note:</strong> Encountered an error during type layout; {#+ #}
-                the type failed to be normalized. {# #}
-            </p> {# #}
-    {% endmatch %}
+        <p> {# #}
+            <strong>Note:</strong> Encountered an error during type layout; {#+ #}
+            the type failed to be normalized. {# #}
+        </p> {# #}
+        {% when Err(LayoutError::Cycle) %}
+        <p> {# #}
+            <strong>Note:</strong> Encountered an error during type layout; {#+ #}
+            the type's layout depended on the type's layout itself. {# #}
+        </p> {# #}
+        {% endmatch %}
 </div> {# #}
diff --git a/src/tools/miri/tests/fail/layout_cycle.rs b/src/tools/miri/tests/fail/layout_cycle.rs
new file mode 100644
index 00000000000..d050310bd80
--- /dev/null
+++ b/src/tools/miri/tests/fail/layout_cycle.rs
@@ -0,0 +1,28 @@
+//@error-pattern: a cycle occurred during layout computation
+//~^ ERROR: cycle detected when computing layout of
+
+use std::mem;
+
+pub struct S<T: Tr> {
+    pub f: <T as Tr>::I,
+}
+
+pub trait Tr {
+    type I: Tr;
+}
+
+impl<T: Tr> Tr for S<T> {
+    type I = S<S<T>>;
+}
+
+impl Tr for () {
+    type I = ();
+}
+
+fn foo<T: Tr>() -> usize {
+    mem::size_of::<S<T>>()
+}
+
+fn main() {
+    println!("{}", foo::<S<()>>());
+}
diff --git a/src/tools/miri/tests/fail/layout_cycle.stderr b/src/tools/miri/tests/fail/layout_cycle.stderr
new file mode 100644
index 00000000000..62b7d5fb77d
--- /dev/null
+++ b/src/tools/miri/tests/fail/layout_cycle.stderr
@@ -0,0 +1,28 @@
+error[E0391]: cycle detected when computing layout of `S<S<()>>`
+   |
+   = note: ...which requires computing layout of `<S<()> as Tr>::I`...
+   = note: ...which again requires computing layout of `S<S<()>>`, completing the cycle
+
+error: post-monomorphization error: a cycle occurred during layout computation
+  --> RUSTLIB/core/src/mem/mod.rs:LL:CC
+   |
+LL |     intrinsics::size_of::<T>()
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ a cycle occurred during layout computation
+   |
+   = note: inside `std::mem::size_of::<S<S<()>>>` at RUSTLIB/core/src/mem/mod.rs:LL:CC
+note: inside `foo::<S<()>>`
+  --> $DIR/layout_cycle.rs:LL:CC
+   |
+LL |     mem::size_of::<S<T>>()
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+note: inside `main`
+  --> $DIR/layout_cycle.rs:LL:CC
+   |
+LL |     println!("{}", foo::<S<()>>());
+   |                    ^^^^^^^^^^^^^^
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0391`.