Skip to content

Commit e87fcf9

Browse files
authored
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
2 parents 887dffc + 7bc6d59 commit e87fcf9

File tree

6 files changed

+119
-44
lines changed

6 files changed

+119
-44
lines changed

compiler/rustc_middle/messages.ftl

+3
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ middle_values_too_big =
3232
middle_cannot_be_normalized =
3333
unable to determine layout for `{$ty}` because `{$failure_ty}` cannot be normalized
3434
35+
middle_cycle =
36+
a cycle occurred during layout computation
37+
3538
middle_strict_coherence_needs_negative_coherence =
3639
to use `strict_coherence` on this trait, the `with_negative_coherence` feature must be enabled
3740
.label = due to this attribute

compiler/rustc_middle/src/ty/layout.rs

+5
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@ pub enum LayoutError<'tcx> {
210210
Unknown(Ty<'tcx>),
211211
SizeOverflow(Ty<'tcx>),
212212
NormalizationFailure(Ty<'tcx>, NormalizationError<'tcx>),
213+
Cycle,
213214
}
214215

215216
impl IntoDiagnostic<'_, !> for LayoutError<'_> {
@@ -230,6 +231,9 @@ impl IntoDiagnostic<'_, !> for LayoutError<'_> {
230231
diag.set_arg("failure_ty", e.get_type_for_failure());
231232
diag.set_primary_message(fluent::middle_cannot_be_normalized);
232233
}
234+
LayoutError::Cycle => {
235+
diag.set_primary_message(fluent::middle_cycle);
236+
}
233237
}
234238
diag
235239
}
@@ -250,6 +254,7 @@ impl<'tcx> fmt::Display for LayoutError<'tcx> {
250254
t,
251255
e.get_type_for_failure()
252256
),
257+
LayoutError::Cycle => write!(f, "a cycle occurred during layout computation"),
253258
}
254259
}
255260
}

compiler/rustc_middle/src/values.rs

+6
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,12 @@ impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::EarlyBinder<ty::Binder<'_, ty::F
106106
}
107107
}
108108

109+
impl<'tcx, T> Value<TyCtxt<'tcx>, DepKind> for Result<T, ty::layout::LayoutError<'_>> {
110+
fn from_cycle_error(_tcx: TyCtxt<'tcx>, _cycle: &[QueryInfo<DepKind>]) -> Self {
111+
Err(ty::layout::LayoutError::Cycle)
112+
}
113+
}
114+
109115
// item_and_field_ids should form a cycle where each field contains the
110116
// type in the next element in the list
111117
pub fn recursive_type_error(
+49-44
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,58 @@
1-
<h2 id="layout" class="small-section-header"> {# #}
1+
<h2 id="layout" class="small-section-header"> {# #}
22
Layout<a href="#layout" class="anchor">§</a> {# #}
33
</h2> {# #}
44
<div class="docblock"> {# #}
55
{% match type_layout_size %}
6-
{% when Ok(type_layout_size) %}
7-
<div class="warning"> {# #}
8-
<p> {# #}
9-
<strong>Note:</strong> Most layout information is <strong>completely {#+ #}
10-
unstable</strong> and may even differ between compilations. {#+ #}
11-
The only exception is types with certain <code>repr(...)</code> {#+ #}
12-
attributes. Please see the Rust Reference’s {#+ #}
13-
<a href="https://doc.rust-lang.org/reference/type-layout.html">“Type Layout”</a> {#+ #}
14-
chapter for details on type layout guarantees. {# #}
15-
</p> {# #}
16-
</div> {# #}
17-
<p><strong>Size:</strong> {{ type_layout_size|safe }}</p> {# #}
18-
{% if !variants.is_empty() %}
19-
<p> {# #}
20-
<strong>Size for each variant:</strong> {# #}
21-
</p> {# #}
22-
<ul> {# #}
23-
{% for (name, layout_size) in variants %}
24-
<li> {# #}
25-
<code>{{ name }}</code>: {#+ #}
26-
{{ layout_size|safe }}
27-
</li> {# #}
28-
{% endfor %}
29-
</ul> {# #}
30-
{% endif %}
31-
{# This kind of layout error can occur with valid code, e.g. if you try to
32-
get the layout of a generic type such as `Vec<T>`. #}
6+
{% when Ok(type_layout_size) %}
7+
<div class="warning"> {# #}
8+
<p> {# #}
9+
<strong>Note:</strong> Most layout information is <strong>completely {#+ #}
10+
unstable</strong> and may even differ between compilations. {#+ #}
11+
The only exception is types with certain <code>repr(...)</code> {#+ #}
12+
attributes. Please see the Rust Reference’s {#+ #}
13+
<a href="https://doc.rust-lang.org/reference/type-layout.html">“Type Layout”</a> {#+ #}
14+
chapter for details on type layout guarantees. {# #}
15+
</p> {# #}
16+
</div> {# #}
17+
<p><strong>Size:</strong> {{ type_layout_size|safe }}</p> {# #}
18+
{% if !variants.is_empty() %}
19+
<p> {# #}
20+
<strong>Size for each variant:</strong> {# #}
21+
</p> {# #}
22+
<ul> {# #}
23+
{% for (name, layout_size) in variants %}
24+
<li> {# #}
25+
<code>{{ name }}</code>: {#+ #}
26+
{{ layout_size|safe }}
27+
</li> {# #}
28+
{% endfor %}
29+
</ul> {# #}
30+
{% endif %}
31+
{# This kind of layout error can occur with valid code, e.g. if you try to
32+
get the layout of a generic type such as `Vec<T>`. #}
3333
{% when Err(LayoutError::Unknown(_)) %}
34-
<p> {# #}
35-
<strong>Note:</strong> Unable to compute type layout, {#+ #}
36-
possibly due to this type having generic parameters. {#+ #}
37-
Layout can only be computed for concrete, fully-instantiated types. {# #}
38-
</p> {# #}
34+
<p> {# #}
35+
<strong>Note:</strong> Unable to compute type layout, {#+ #}
36+
possibly due to this type having generic parameters. {#+ #}
37+
Layout can only be computed for concrete, fully-instantiated types. {# #}
38+
</p> {# #}
3939
{# This kind of error probably can't happen with valid code, but we don't
40-
want to panic and prevent the docs from building, so we just let the
41-
user know that we couldn't compute the layout. #}
40+
want to panic and prevent the docs from building, so we just let the
41+
user know that we couldn't compute the layout. #}
4242
{% when Err(LayoutError::SizeOverflow(_)) %}
43-
<p> {# #}
44-
<strong>Note:</strong> Encountered an error during type layout; {#+ #}
45-
the type was too big. {# #}
46-
</p> {# #}
43+
<p> {# #}
44+
<strong>Note:</strong> Encountered an error during type layout; {#+ #}
45+
the type was too big. {# #}
46+
</p> {# #}
4747
{% when Err(LayoutError::NormalizationFailure(_, _)) %}
48-
<p> {# #}
49-
<strong>Note:</strong> Encountered an error during type layout; {#+ #}
50-
the type failed to be normalized. {# #}
51-
</p> {# #}
52-
{% endmatch %}
48+
<p> {# #}
49+
<strong>Note:</strong> Encountered an error during type layout; {#+ #}
50+
the type failed to be normalized. {# #}
51+
</p> {# #}
52+
{% when Err(LayoutError::Cycle) %}
53+
<p> {# #}
54+
<strong>Note:</strong> Encountered an error during type layout; {#+ #}
55+
the type's layout depended on the type's layout itself. {# #}
56+
</p> {# #}
57+
{% endmatch %}
5358
</div> {# #}
+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
//@error-pattern: a cycle occurred during layout computation
2+
//~^ ERROR: cycle detected when computing layout of
3+
4+
use std::mem;
5+
6+
pub struct S<T: Tr> {
7+
pub f: <T as Tr>::I,
8+
}
9+
10+
pub trait Tr {
11+
type I: Tr;
12+
}
13+
14+
impl<T: Tr> Tr for S<T> {
15+
type I = S<S<T>>;
16+
}
17+
18+
impl Tr for () {
19+
type I = ();
20+
}
21+
22+
fn foo<T: Tr>() -> usize {
23+
mem::size_of::<S<T>>()
24+
}
25+
26+
fn main() {
27+
println!("{}", foo::<S<()>>());
28+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
error[E0391]: cycle detected when computing layout of `S<S<()>>`
2+
|
3+
= note: ...which requires computing layout of `<S<()> as Tr>::I`...
4+
= note: ...which again requires computing layout of `S<S<()>>`, completing the cycle
5+
6+
error: post-monomorphization error: a cycle occurred during layout computation
7+
--> RUSTLIB/core/src/mem/mod.rs:LL:CC
8+
|
9+
LL | intrinsics::size_of::<T>()
10+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ a cycle occurred during layout computation
11+
|
12+
= note: inside `std::mem::size_of::<S<S<()>>>` at RUSTLIB/core/src/mem/mod.rs:LL:CC
13+
note: inside `foo::<S<()>>`
14+
--> $DIR/layout_cycle.rs:LL:CC
15+
|
16+
LL | mem::size_of::<S<T>>()
17+
| ^^^^^^^^^^^^^^^^^^^^^^
18+
note: inside `main`
19+
--> $DIR/layout_cycle.rs:LL:CC
20+
|
21+
LL | println!("{}", foo::<S<()>>());
22+
| ^^^^^^^^^^^^^^
23+
24+
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
25+
26+
error: aborting due to 2 previous errors
27+
28+
For more information about this error, try `rustc --explain E0391`.

0 commit comments

Comments
 (0)