From 7bc6d598f94744751a249ed18885592a6f077bcd Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 2 May 2023 16:14:20 +0000 Subject: [PATCH] Avoid ICEing miri on layout query cycles --- compiler/rustc_middle/messages.ftl | 3 + compiler/rustc_middle/src/ty/layout.rs | 5 + compiler/rustc_middle/src/values.rs | 6 ++ .../html/templates/type_layout.html | 93 ++++++++++--------- src/tools/miri/tests/fail/layout_cycle.rs | 28 ++++++ src/tools/miri/tests/fail/layout_cycle.stderr | 28 ++++++ 6 files changed, 119 insertions(+), 44 deletions(-) create mode 100644 src/tools/miri/tests/fail/layout_cycle.rs create mode 100644 src/tools/miri/tests/fail/layout_cycle.stderr 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, DepKind> for ty::EarlyBinder Value, DepKind> for Result> { + fn from_cycle_error(_tcx: TyCtxt<'tcx>, _cycle: &[QueryInfo]) -> 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 @@ -

{# #} +

{# #} Layout§ {# #}

{# #}
{# #} {% match type_layout_size %} - {% when Ok(type_layout_size) %} -
{# #} -

{# #} - Note: Most layout information is completely {#+ #} - unstable and may even differ between compilations. {#+ #} - The only exception is types with certain repr(...) {#+ #} - attributes. Please see the Rust Reference’s {#+ #} - “Type Layout” {#+ #} - chapter for details on type layout guarantees. {# #} -

{# #} -
{# #} -

Size: {{ type_layout_size|safe }}

{# #} - {% if !variants.is_empty() %} -

{# #} - Size for each variant: {# #} -

{# #} -
    {# #} - {% for (name, layout_size) in variants %} -
  • {# #} - {{ name }}: {#+ #} - {{ layout_size|safe }} -
  • {# #} - {% endfor %} -
{# #} - {% 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`. #} + {% when Ok(type_layout_size) %} +
{# #} +

{# #} + Note: Most layout information is completely {#+ #} + unstable and may even differ between compilations. {#+ #} + The only exception is types with certain repr(...) {#+ #} + attributes. Please see the Rust Reference’s {#+ #} + “Type Layout” {#+ #} + chapter for details on type layout guarantees. {# #} +

{# #} +
{# #} +

Size: {{ type_layout_size|safe }}

{# #} + {% if !variants.is_empty() %} +

{# #} + Size for each variant: {# #} +

{# #} +
    {# #} + {% for (name, layout_size) in variants %} +
  • {# #} + {{ name }}: {#+ #} + {{ layout_size|safe }} +
  • {# #} + {% endfor %} +
{# #} + {% 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`. #} {% when Err(LayoutError::Unknown(_)) %} -

{# #} - Note: Unable to compute type layout, {#+ #} - possibly due to this type having generic parameters. {#+ #} - Layout can only be computed for concrete, fully-instantiated types. {# #} -

{# #} +

{# #} + Note: Unable to compute type layout, {#+ #} + possibly due to this type having generic parameters. {#+ #} + Layout can only be computed for concrete, fully-instantiated types. {# #} +

{# #} {# 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(_)) %} -

{# #} - Note: Encountered an error during type layout; {#+ #} - the type was too big. {# #} -

{# #} +

{# #} + Note: Encountered an error during type layout; {#+ #} + the type was too big. {# #} +

{# #} {% when Err(LayoutError::NormalizationFailure(_, _)) %} -

{# #} - Note: Encountered an error during type layout; {#+ #} - the type failed to be normalized. {# #} -

{# #} - {% endmatch %} +

{# #} + Note: Encountered an error during type layout; {#+ #} + the type failed to be normalized. {# #} +

{# #} + {% when Err(LayoutError::Cycle) %} +

{# #} + Note: Encountered an error during type layout; {#+ #} + the type's layout depended on the type's layout itself. {# #} +

{# #} + {% endmatch %}
{# #} 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 { + pub f: ::I, +} + +pub trait Tr { + type I: Tr; +} + +impl Tr for S { + type I = S>; +} + +impl Tr for () { + type I = (); +} + +fn foo() -> usize { + mem::size_of::>() +} + +fn main() { + println!("{}", foo::>()); +} 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>` + | + = note: ...which requires computing layout of ` as Tr>::I`... + = note: ...which again requires computing layout of `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::() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ a cycle occurred during layout computation + | + = note: inside `std::mem::size_of::>>` at RUSTLIB/core/src/mem/mod.rs:LL:CC +note: inside `foo::>` + --> $DIR/layout_cycle.rs:LL:CC + | +LL | mem::size_of::>() + | ^^^^^^^^^^^^^^^^^^^^^^ +note: inside `main` + --> $DIR/layout_cycle.rs:LL:CC + | +LL | println!("{}", foo::>()); + | ^^^^^^^^^^^^^^ + +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`.