about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDylan DPC <99973273+Dylan-DPC@users.noreply.github.com>2023-05-04 00:17:27 +0530
committerGitHub <noreply@github.com>2023-05-04 00:17:27 +0530
commite87fcf979fc5ff36386c642d779f2c071cf30fe8 (patch)
tree10c28bb928677239f9ed65d2ef54785fe39bc51e
parent887dffc44795f30c32e8776a9a1850f82da81942 (diff)
parent7bc6d598f94744751a249ed18885592a6f077bcd (diff)
downloadrust-e87fcf979fc5ff36386c642d779f2c071cf30fe8.tar.gz
rust-e87fcf979fc5ff36386c642d779f2c071cf30fe8.zip
Rollup merge of #111097 - oli-obk:🚲_layout, r=compiler-errors
Avoid ICEing miri on layout query cycles

Miri has special logic for catching panics during interpretation. Raising a fatal error in rustc uses unwinding to abort compilation. Thus miri ends up catching that fatal error and thinks it saw an ICE. While we should probably change that to ignore `Fatal` payloads, I think it's also neat to continue compilation after a layout query cycle 😆

Query cycles now (in addition to reporting an error just like before), return `Err(Cycle)` instead of raising a fatal error. This allows the interpreter to wind down via the regular error paths.

r? `@RalfJung` for a first round, feel free to reroll for the compiler team once the miri side looks good
-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`.