Skip to content

Commit d0a5bbb

Browse files
author
Lukas Markeffsky
committed
document and test all LayoutError variants
1 parent 3b022d8 commit d0a5bbb

File tree

5 files changed

+102
-1
lines changed

5 files changed

+102
-1
lines changed

Diff for: compiler/rustc_middle/src/ty/layout.rs

+21
Original file line numberDiff line numberDiff line change
@@ -229,11 +229,32 @@ impl fmt::Display for ValidityRequirement {
229229

230230
#[derive(Copy, Clone, Debug, HashStable, TyEncodable, TyDecodable)]
231231
pub enum LayoutError<'tcx> {
232+
/// A type doesn't have a sensible layout.
233+
///
234+
/// This variant is used for layout errors that don't necessarily cause
235+
/// compile errors.
236+
///
237+
/// For example, this can happen if a struct contains an unsized type in a
238+
/// non-tail field, but has an unsatisfiable bound like `str: Sized`.
232239
Unknown(Ty<'tcx>),
240+
/// The size of a type exceeds [`TargetDataLayout::obj_size_bound`].
233241
SizeOverflow(Ty<'tcx>),
242+
/// The layout can vary due to a generic parameter.
243+
///
244+
/// Unlike `Unknown`, this variant is a "soft" error and indicates that the layout
245+
/// may become computable after further instantiating the generic parameter(s).
234246
TooGeneric(Ty<'tcx>),
247+
/// An alias failed to normalize.
248+
///
249+
/// This variant is necessary, because, due to trait solver incompleteness, it is
250+
/// possible than an alias that was rigid during analysis fails to normalize after
251+
/// revealing opaque types.
252+
///
253+
/// See `tests/ui/layout/normalization-failure.rs` for an example.
235254
NormalizationFailure(Ty<'tcx>, NormalizationError<'tcx>),
255+
/// A non-layout error is reported elsewhere.
236256
ReferencesError(ErrorGuaranteed),
257+
/// A type has cyclic layout, i.e. the type contains itself without indirection.
237258
Cycle(ErrorGuaranteed),
238259
}
239260

Diff for: tests/ui/layout/debug.rs

+5
Original file line numberDiff line numberDiff line change
@@ -82,3 +82,8 @@ type Impossible = (str, str); //~ ERROR: cannot be known at compilation time
8282
#[rustc_layout(debug)]
8383
union EmptyUnion {} //~ ERROR: has an unknown layout
8484
//~^ ERROR: unions cannot have zero fields
85+
86+
// Test the error message of `LayoutError::TooGeneric`
87+
// (this error is never emitted to users).
88+
#[rustc_layout(debug)]
89+
type TooGeneric<T> = T; //~ ERROR: does not have a fixed size

Diff for: tests/ui/layout/debug.stderr

+7-1
Original file line numberDiff line numberDiff line change
@@ -596,12 +596,18 @@ error: the type has an unknown layout
596596
LL | union EmptyUnion {}
597597
| ^^^^^^^^^^^^^^^^
598598

599+
error: `T` does not have a fixed size
600+
--> $DIR/debug.rs:89:1
601+
|
602+
LL | type TooGeneric<T> = T;
603+
| ^^^^^^^^^^^^^^^^^^
604+
599605
error: `#[rustc_layout]` can only be applied to `struct`/`enum`/`union` declarations and type aliases
600606
--> $DIR/debug.rs:75:5
601607
|
602608
LL | const C: () = ();
603609
| ^^^^^^^^^^^
604610

605-
error: aborting due to 19 previous errors
611+
error: aborting due to 20 previous errors
606612

607613
For more information about this error, try `rustc --explain E0277`.

Diff for: tests/ui/layout/normalization-failure.rs

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
//! This test demonstrates how `LayoutError::NormalizationFailure` can happen and why
2+
//! it is necessary.
3+
//!
4+
//! This code does not cause an immediate normalization error in typeck, because we
5+
//! don't reveal the hidden type returned by `opaque<T>` in the analysis typing mode.
6+
//! Instead, `<{opaque} as Project2>::Assoc2` is a *rigid projection*, because we know
7+
//! that `{opaque}: Project2` holds, due to the opaque type's `impl Project2` bound,
8+
//! but cannot normalize `<{opaque} as Project2>::Assoc2` any further.
9+
//!
10+
//! However, in the post-analysis typing mode, which is used for the layout computation,
11+
//! the opaque's hidden type is revealed to be `PhantomData<T>`, and now we fail to
12+
//! normalize `<PhantomData<T> as Project2>::Assoc2` if there is a `T: Project1` bound
13+
//! in the param env! This happens, because `PhantomData<T>: Project2` only holds if
14+
//! `<T as Project1>::Assoc1 == ()` holds. This would usually be satisfied by the
15+
//! blanket `impl<T> Project1 for T`, but due to the `T: Project1` bound we do not
16+
//! normalize `<T as Project1>::Assoc1` via the impl and treat it as rigid instead.
17+
//! Therefore, `PhantomData<T>: Project2` does NOT hold and normalizing
18+
//! `<PhantomData<T> as Project2>::Assoc2` fails.
19+
//!
20+
//! Note that this layout error can only happen when computing the layout in a generic
21+
//! context, which is not required for codegen, but may happen for lints, MIR optimizations,
22+
//! and the transmute check.
23+
24+
use std::marker::PhantomData;
25+
26+
trait Project1 {
27+
type Assoc1;
28+
}
29+
30+
impl<T> Project1 for T {
31+
type Assoc1 = ();
32+
}
33+
34+
trait Project2 {
35+
type Assoc2;
36+
fn get(self) -> Self::Assoc2;
37+
}
38+
39+
impl<T: Project1<Assoc1 = ()>> Project2 for PhantomData<T> {
40+
type Assoc2 = ();
41+
fn get(self) -> Self::Assoc2 {}
42+
}
43+
44+
fn opaque<T>() -> impl Project2 {
45+
PhantomData::<T>
46+
}
47+
48+
fn check<T: Project1>() {
49+
unsafe {
50+
std::mem::transmute::<_, ()>(opaque::<T>().get());
51+
//~^ ERROR: cannot transmute
52+
//~| NOTE: (unable to determine layout for `<impl Project2 as Project2>::Assoc2` because `<impl Project2 as Project2>::Assoc2` cannot be normalized)
53+
//~| NOTE: (0 bits)
54+
}
55+
}
56+
57+
fn main() {}

Diff for: tests/ui/layout/normalization-failure.stderr

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
2+
--> $DIR/normalization-failure.rs:50:9
3+
|
4+
LL | std::mem::transmute::<_, ()>(opaque::<T>().get());
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6+
|
7+
= note: source type: `<impl Project2 as Project2>::Assoc2` (unable to determine layout for `<impl Project2 as Project2>::Assoc2` because `<impl Project2 as Project2>::Assoc2` cannot be normalized)
8+
= note: target type: `()` (0 bits)
9+
10+
error: aborting due to 1 previous error
11+
12+
For more information about this error, try `rustc --explain E0512`.

0 commit comments

Comments
 (0)