Avoid ICEing miri on layout query cycles

This commit is contained in:
Oli Scherer 2023-05-02 16:14:20 +00:00
parent 7b99493492
commit 7bc6d598f9
6 changed files with 119 additions and 44 deletions

View File

@ -32,6 +32,9 @@ middle_values_too_big =
middle_cannot_be_normalized = middle_cannot_be_normalized =
unable to determine layout for `{$ty}` because `{$failure_ty}` 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 = middle_strict_coherence_needs_negative_coherence =
to use `strict_coherence` on this trait, the `with_negative_coherence` feature must be enabled to use `strict_coherence` on this trait, the `with_negative_coherence` feature must be enabled
.label = due to this attribute .label = due to this attribute

View File

@ -210,6 +210,7 @@ pub enum LayoutError<'tcx> {
Unknown(Ty<'tcx>), Unknown(Ty<'tcx>),
SizeOverflow(Ty<'tcx>), SizeOverflow(Ty<'tcx>),
NormalizationFailure(Ty<'tcx>, NormalizationError<'tcx>), NormalizationFailure(Ty<'tcx>, NormalizationError<'tcx>),
Cycle,
} }
impl IntoDiagnostic<'_, !> for LayoutError<'_> { impl IntoDiagnostic<'_, !> for LayoutError<'_> {
@ -230,6 +231,9 @@ impl IntoDiagnostic<'_, !> for LayoutError<'_> {
diag.set_arg("failure_ty", e.get_type_for_failure()); diag.set_arg("failure_ty", e.get_type_for_failure());
diag.set_primary_message(fluent::middle_cannot_be_normalized); diag.set_primary_message(fluent::middle_cannot_be_normalized);
} }
LayoutError::Cycle => {
diag.set_primary_message(fluent::middle_cycle);
}
} }
diag diag
} }
@ -250,6 +254,7 @@ impl<'tcx> fmt::Display for LayoutError<'tcx> {
t, t,
e.get_type_for_failure() e.get_type_for_failure()
), ),
LayoutError::Cycle => write!(f, "a cycle occurred during layout computation"),
} }
} }
} }

View File

@ -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 // item_and_field_ids should form a cycle where each field contains the
// type in the next element in the list // type in the next element in the list
pub fn recursive_type_error( pub fn recursive_type_error(

View File

@ -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> {# #} Layout<a href="#layout" class="anchor">§</a> {# #}
</h2> {# #} </h2> {# #}
<div class="docblock"> {# #} <div class="docblock"> {# #}
{% match type_layout_size %} {% match type_layout_size %}
{% when Ok(type_layout_size) %} {% when Ok(type_layout_size) %}
<div class="warning"> {# #} <div class="warning"> {# #}
<p> {# #} <p> {# #}
<strong>Note:</strong> Most layout information is <strong>completely {#+ #} <strong>Note:</strong> Most layout information is <strong>completely {#+ #}
unstable</strong> and may even differ between compilations. {#+ #} unstable</strong> and may even differ between compilations. {#+ #}
The only exception is types with certain <code>repr(...)</code> {#+ #} The only exception is types with certain <code>repr(...)</code> {#+ #}
attributes. Please see the Rust References {#+ #} attributes. Please see the Rust References {#+ #}
<a href="https://doc.rust-lang.org/reference/type-layout.html">“Type Layout”</a> {#+ #} <a href="https://doc.rust-lang.org/reference/type-layout.html">“Type Layout”</a> {#+ #}
chapter for details on type layout guarantees. {# #} chapter for details on type layout guarantees. {# #}
</p> {# #} </p> {# #}
</div> {# #} </div> {# #}
<p><strong>Size:</strong> {{ type_layout_size|safe }}</p> {# #} <p><strong>Size:</strong> {{ type_layout_size|safe }}</p> {# #}
{% if !variants.is_empty() %} {% if !variants.is_empty() %}
<p> {# #} <p> {# #}
<strong>Size for each variant:</strong> {# #} <strong>Size for each variant:</strong> {# #}
</p> {# #} </p> {# #}
<ul> {# #} <ul> {# #}
{% for (name, layout_size) in variants %} {% for (name, layout_size) in variants %}
<li> {# #} <li> {# #}
<code>{{ name }}</code>: {#+ #} <code>{{ name }}</code>: {#+ #}
{{ layout_size|safe }} {{ layout_size|safe }}
</li> {# #} </li> {# #}
{% endfor %} {% endfor %}
</ul> {# #} </ul> {# #}
{% endif %} {% endif %}
{# This kind of layout error can occur with valid code, e.g. if you try to {# 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>`. #} get the layout of a generic type such as `Vec<T>`. #}
{% when Err(LayoutError::Unknown(_)) %} {% when Err(LayoutError::Unknown(_)) %}
<p> {# #} <p> {# #}
<strong>Note:</strong> Unable to compute type layout, {#+ #} <strong>Note:</strong> Unable to compute type layout, {#+ #}
possibly due to this type having generic parameters. {#+ #} possibly due to this type having generic parameters. {#+ #}
Layout can only be computed for concrete, fully-instantiated types. {# #} Layout can only be computed for concrete, fully-instantiated types. {# #}
</p> {# #} </p> {# #}
{# This kind of error probably can't happen with valid code, but we don't {# 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 want to panic and prevent the docs from building, so we just let the
user know that we couldn't compute the layout. #} user know that we couldn't compute the layout. #}
{% when Err(LayoutError::SizeOverflow(_)) %} {% when Err(LayoutError::SizeOverflow(_)) %}
<p> {# #} <p> {# #}
<strong>Note:</strong> Encountered an error during type layout; {#+ #} <strong>Note:</strong> Encountered an error during type layout; {#+ #}
the type was too big. {# #} the type was too big. {# #}
</p> {# #} </p> {# #}
{% when Err(LayoutError::NormalizationFailure(_, _)) %} {% when Err(LayoutError::NormalizationFailure(_, _)) %}
<p> {# #} <p> {# #}
<strong>Note:</strong> Encountered an error during type layout; {#+ #} <strong>Note:</strong> Encountered an error during type layout; {#+ #}
the type failed to be normalized. {# #} the type failed to be normalized. {# #}
</p> {# #} </p> {# #}
{% endmatch %} {% 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> {# #} </div> {# #}

View File

@ -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<()>>());
}

View File

@ -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`.