document and test all LayoutError variants
This commit is contained in:
parent
3b022d8cee
commit
d0a5bbbb8e
5 changed files with 102 additions and 1 deletions
|
|
@ -229,11 +229,32 @@ impl fmt::Display for ValidityRequirement {
|
|||
|
||||
#[derive(Copy, Clone, Debug, HashStable, TyEncodable, TyDecodable)]
|
||||
pub enum LayoutError<'tcx> {
|
||||
/// A type doesn't have a sensible layout.
|
||||
///
|
||||
/// This variant is used for layout errors that don't necessarily cause
|
||||
/// compile errors.
|
||||
///
|
||||
/// For example, this can happen if a struct contains an unsized type in a
|
||||
/// non-tail field, but has an unsatisfiable bound like `str: Sized`.
|
||||
Unknown(Ty<'tcx>),
|
||||
/// The size of a type exceeds [`TargetDataLayout::obj_size_bound`].
|
||||
SizeOverflow(Ty<'tcx>),
|
||||
/// The layout can vary due to a generic parameter.
|
||||
///
|
||||
/// Unlike `Unknown`, this variant is a "soft" error and indicates that the layout
|
||||
/// may become computable after further instantiating the generic parameter(s).
|
||||
TooGeneric(Ty<'tcx>),
|
||||
/// An alias failed to normalize.
|
||||
///
|
||||
/// This variant is necessary, because, due to trait solver incompleteness, it is
|
||||
/// possible than an alias that was rigid during analysis fails to normalize after
|
||||
/// revealing opaque types.
|
||||
///
|
||||
/// See `tests/ui/layout/normalization-failure.rs` for an example.
|
||||
NormalizationFailure(Ty<'tcx>, NormalizationError<'tcx>),
|
||||
/// A non-layout error is reported elsewhere.
|
||||
ReferencesError(ErrorGuaranteed),
|
||||
/// A type has cyclic layout, i.e. the type contains itself without indirection.
|
||||
Cycle(ErrorGuaranteed),
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -82,3 +82,8 @@ type Impossible = (str, str); //~ ERROR: cannot be known at compilation time
|
|||
#[rustc_layout(debug)]
|
||||
union EmptyUnion {} //~ ERROR: has an unknown layout
|
||||
//~^ ERROR: unions cannot have zero fields
|
||||
|
||||
// Test the error message of `LayoutError::TooGeneric`
|
||||
// (this error is never emitted to users).
|
||||
#[rustc_layout(debug)]
|
||||
type TooGeneric<T> = T; //~ ERROR: does not have a fixed size
|
||||
|
|
|
|||
|
|
@ -596,12 +596,18 @@ error: the type has an unknown layout
|
|||
LL | union EmptyUnion {}
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
||||
error: `T` does not have a fixed size
|
||||
--> $DIR/debug.rs:89:1
|
||||
|
|
||||
LL | type TooGeneric<T> = T;
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: `#[rustc_layout]` can only be applied to `struct`/`enum`/`union` declarations and type aliases
|
||||
--> $DIR/debug.rs:75:5
|
||||
|
|
||||
LL | const C: () = ();
|
||||
| ^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 19 previous errors
|
||||
error: aborting due to 20 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
||||
|
|
|
|||
57
tests/ui/layout/normalization-failure.rs
Normal file
57
tests/ui/layout/normalization-failure.rs
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
//! This test demonstrates how `LayoutError::NormalizationFailure` can happen and why
|
||||
//! it is necessary.
|
||||
//!
|
||||
//! This code does not cause an immediate normalization error in typeck, because we
|
||||
//! don't reveal the hidden type returned by `opaque<T>` in the analysis typing mode.
|
||||
//! Instead, `<{opaque} as Project2>::Assoc2` is a *rigid projection*, because we know
|
||||
//! that `{opaque}: Project2` holds, due to the opaque type's `impl Project2` bound,
|
||||
//! but cannot normalize `<{opaque} as Project2>::Assoc2` any further.
|
||||
//!
|
||||
//! However, in the post-analysis typing mode, which is used for the layout computation,
|
||||
//! the opaque's hidden type is revealed to be `PhantomData<T>`, and now we fail to
|
||||
//! normalize `<PhantomData<T> as Project2>::Assoc2` if there is a `T: Project1` bound
|
||||
//! in the param env! This happens, because `PhantomData<T>: Project2` only holds if
|
||||
//! `<T as Project1>::Assoc1 == ()` holds. This would usually be satisfied by the
|
||||
//! blanket `impl<T> Project1 for T`, but due to the `T: Project1` bound we do not
|
||||
//! normalize `<T as Project1>::Assoc1` via the impl and treat it as rigid instead.
|
||||
//! Therefore, `PhantomData<T>: Project2` does NOT hold and normalizing
|
||||
//! `<PhantomData<T> as Project2>::Assoc2` fails.
|
||||
//!
|
||||
//! Note that this layout error can only happen when computing the layout in a generic
|
||||
//! context, which is not required for codegen, but may happen for lints, MIR optimizations,
|
||||
//! and the transmute check.
|
||||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
trait Project1 {
|
||||
type Assoc1;
|
||||
}
|
||||
|
||||
impl<T> Project1 for T {
|
||||
type Assoc1 = ();
|
||||
}
|
||||
|
||||
trait Project2 {
|
||||
type Assoc2;
|
||||
fn get(self) -> Self::Assoc2;
|
||||
}
|
||||
|
||||
impl<T: Project1<Assoc1 = ()>> Project2 for PhantomData<T> {
|
||||
type Assoc2 = ();
|
||||
fn get(self) -> Self::Assoc2 {}
|
||||
}
|
||||
|
||||
fn opaque<T>() -> impl Project2 {
|
||||
PhantomData::<T>
|
||||
}
|
||||
|
||||
fn check<T: Project1>() {
|
||||
unsafe {
|
||||
std::mem::transmute::<_, ()>(opaque::<T>().get());
|
||||
//~^ ERROR: cannot transmute
|
||||
//~| NOTE: (unable to determine layout for `<impl Project2 as Project2>::Assoc2` because `<impl Project2 as Project2>::Assoc2` cannot be normalized)
|
||||
//~| NOTE: (0 bits)
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
12
tests/ui/layout/normalization-failure.stderr
Normal file
12
tests/ui/layout/normalization-failure.stderr
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
|
||||
--> $DIR/normalization-failure.rs:50:9
|
||||
|
|
||||
LL | std::mem::transmute::<_, ()>(opaque::<T>().get());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= 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)
|
||||
= note: target type: `()` (0 bits)
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0512`.
|
||||
Loading…
Add table
Add a link
Reference in a new issue