Add TooGeneric variant to LayoutError and emit Unknown one

- `check-pass` test for a MRE of #135020
- fail test for #135138
- switch to `TooGeneric` for checking CMSE fn signatures
- switch to `TooGeneric` for compute `SizeSkeleton` (for transmute)
- fix broken tests
This commit is contained in:
FedericoBruzzone 2025-01-06 11:39:07 +01:00
parent 15c6f7e1a3
commit cef97bce7b
29 changed files with 233 additions and 58 deletions

View file

@ -140,7 +140,7 @@ where
// Don't emit a new diagnostic for these errors, they are already reported elsewhere or
// should remain silent.
err_inval!(AlreadyReported(info)) => ErrorHandled::Reported(info, span),
err_inval!(Layout(LayoutError::Unknown(_))) | err_inval!(TooGeneric) => {
err_inval!(Layout(LayoutError::TooGeneric(_))) | err_inval!(TooGeneric) => {
ErrorHandled::TooGeneric(span)
}
err_inval!(Layout(LayoutError::ReferencesError(guar))) => {

View file

@ -201,7 +201,7 @@ fn should_emit_generic_error<'tcx>(abi: ExternAbi, layout_err: &'tcx LayoutError
use LayoutError::*;
match layout_err {
Unknown(ty) => {
TooGeneric(ty) => {
match abi {
ExternAbi::CCmseNonSecureCall => {
// prevent double reporting of this error
@ -211,7 +211,11 @@ fn should_emit_generic_error<'tcx>(abi: ExternAbi, layout_err: &'tcx LayoutError
_ => bug!("invalid ABI: {abi}"),
}
}
SizeOverflow(..) | NormalizationFailure(..) | ReferencesError(..) | Cycle(..) => {
Unknown(..)
| SizeOverflow(..)
| NormalizationFailure(..)
| ReferencesError(..)
| Cycle(..) => {
false // not our job to report these
}
}

View file

@ -122,7 +122,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
format!("generic size {size}")
}
}
Err(LayoutError::Unknown(bad)) => {
Err(LayoutError::TooGeneric(bad)) => {
if *bad == ty {
"this type does not have a fixed size".to_owned()
} else {

View file

@ -100,6 +100,8 @@ 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
middle_too_generic = `{$ty}` does not have a fixed size
middle_type_length_limit = reached the type-length limit while instantiating `{$shrunk}`
middle_unknown_layout =
@ -107,4 +109,5 @@ middle_unknown_layout =
middle_values_too_big =
values of the type `{$ty}` are too big for the target architecture
middle_written_to_path = the full type name has been written to '{$path}'

View file

@ -129,6 +129,9 @@ pub enum LayoutError<'tcx> {
#[diag(middle_unknown_layout)]
Unknown { ty: Ty<'tcx> },
#[diag(middle_too_generic)]
TooGeneric { ty: Ty<'tcx> },
#[diag(middle_values_too_big)]
Overflow { ty: Ty<'tcx> },

View file

@ -231,6 +231,7 @@ impl fmt::Display for ValidityRequirement {
pub enum LayoutError<'tcx> {
Unknown(Ty<'tcx>),
SizeOverflow(Ty<'tcx>),
TooGeneric(Ty<'tcx>),
NormalizationFailure(Ty<'tcx>, NormalizationError<'tcx>),
ReferencesError(ErrorGuaranteed),
Cycle(ErrorGuaranteed),
@ -244,6 +245,7 @@ impl<'tcx> LayoutError<'tcx> {
match self {
Unknown(_) => middle_unknown_layout,
SizeOverflow(_) => middle_values_too_big,
TooGeneric(_) => middle_too_generic,
NormalizationFailure(_, _) => middle_cannot_be_normalized,
Cycle(_) => middle_cycle,
ReferencesError(_) => middle_layout_references_error,
@ -257,6 +259,7 @@ impl<'tcx> LayoutError<'tcx> {
match self {
Unknown(ty) => E::Unknown { ty },
SizeOverflow(ty) => E::Overflow { ty },
TooGeneric(ty) => E::TooGeneric { ty },
NormalizationFailure(ty, e) => {
E::NormalizationFailure { ty, failure_ty: e.get_type_for_failure() }
}
@ -272,6 +275,9 @@ impl<'tcx> fmt::Display for LayoutError<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
LayoutError::Unknown(ty) => write!(f, "the type `{ty}` has an unknown layout"),
LayoutError::TooGeneric(ty) => {
write!(f, "`{ty}` does not have a fixed size")
}
LayoutError::SizeOverflow(ty) => {
write!(f, "values of the type `{ty}` are too big for the target architecture")
}
@ -350,10 +356,11 @@ impl<'tcx> SizeSkeleton<'tcx> {
return Err(tcx.arena.alloc(LayoutError::Unknown(ty)));
}
}
Err(err @ LayoutError::Unknown(_)) => err,
Err(err @ LayoutError::TooGeneric(_)) => err,
// We can't extract SizeSkeleton info from other layout errors
Err(
e @ LayoutError::Cycle(_)
| e @ LayoutError::Unknown(_)
| e @ LayoutError::SizeOverflow(_)
| e @ LayoutError::NormalizationFailure(..)
| e @ LayoutError::ReferencesError(_),
@ -413,10 +420,9 @@ impl<'tcx> SizeSkeleton<'tcx> {
// Alignment is unchanged by arrays.
return Ok(SizeSkeleton::Known(Size::from_bytes(size), a));
}
Err(tcx.arena.alloc(LayoutError::Unknown(ty)))
Err(err)
}
SizeSkeleton::Pointer { .. } => Err(err),
SizeSkeleton::Generic(_) => Err(tcx.arena.alloc(LayoutError::Unknown(ty))),
SizeSkeleton::Pointer { .. } | SizeSkeleton::Generic(_) => Err(err),
}
}

View file

@ -197,6 +197,7 @@ pub(crate) mod rustc {
match err {
LayoutError::Unknown(..)
| LayoutError::ReferencesError(..)
| LayoutError::TooGeneric(..)
| LayoutError::NormalizationFailure(..) => Self::UnknownLayout,
LayoutError::SizeOverflow(..) => Self::SizeOverflow,
LayoutError::Cycle(err) => Self::TypeError(*err),

View file

@ -104,14 +104,12 @@ fn map_error<'tcx>(
// This is sometimes not a compile error if there are trivially false where clauses.
// See `tests/ui/layout/trivial-bounds-sized.rs` for an example.
assert!(field.layout.is_unsized(), "invalid layout error {err:#?}");
if !field.ty.is_sized(cx.tcx(), cx.typing_env) {
let guar = cx.tcx().dcx().delayed_bug(format!(
if cx.typing_env.param_env.caller_bounds().is_empty() {
cx.tcx().dcx().delayed_bug(format!(
"encountered unexpected unsized field in layout of {ty:?}: {field:#?}"
));
LayoutError::ReferencesError(guar)
} else {
LayoutError::Unknown(ty)
}
LayoutError::Unknown(ty)
}
LayoutCalculatorError::EmptyUnion => {
// This is always a compile error.
@ -146,6 +144,35 @@ fn univariant_uninterned<'tcx>(
cx.calc.univariant(fields, repr, kind).map_err(|err| map_error(cx, ty, err))
}
fn validate_const_with_value<'tcx>(
const_: ty::Const<'tcx>,
ty: Ty<'tcx>,
cx: &LayoutCx<'tcx>,
) -> Result<ty::Const<'tcx>, &'tcx LayoutError<'tcx>> {
match const_.kind() {
ty::ConstKind::Value(..) => Ok(const_),
ty::ConstKind::Error(guar) => {
return Err(error(cx, LayoutError::ReferencesError(guar)));
}
ty::ConstKind::Param(_) | ty::ConstKind::Expr(_) => {
if !const_.has_param() {
bug!("no generic type found in the type: {ty:?}");
}
return Err(error(cx, LayoutError::TooGeneric(ty)));
}
ty::ConstKind::Unevaluated(_) => {
if !const_.has_param() {
return Err(error(cx, LayoutError::Unknown(ty)));
} else {
return Err(error(cx, LayoutError::TooGeneric(ty)));
}
}
ty::ConstKind::Infer(_) | ty::ConstKind::Bound(..) | ty::ConstKind::Placeholder(_) => {
bug!("unexpected type: {ty:?}");
}
}
}
fn layout_of_uncached<'tcx>(
cx: &LayoutCx<'tcx>,
ty: Ty<'tcx>,
@ -182,12 +209,13 @@ fn layout_of_uncached<'tcx>(
&mut layout.backend_repr
{
if let Some(start) = start {
scalar.valid_range_mut().start = start
scalar.valid_range_mut().start =
validate_const_with_value(start, ty, cx)?
.try_to_bits(tcx, cx.typing_env)
.ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?;
}
if let Some(end) = end {
let mut end = end
let mut end = validate_const_with_value(end, ty, cx)?
.try_to_bits(tcx, cx.typing_env)
.ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?;
if !include_end {
@ -319,17 +347,13 @@ fn layout_of_uncached<'tcx>(
}
// Arrays and slices.
ty::Array(element, mut count) => {
if count.has_aliases() {
count = tcx.normalize_erasing_regions(cx.typing_env, count);
if count.has_aliases() {
return Err(error(cx, LayoutError::Unknown(ty)));
}
}
let count = count
ty::Array(element, count) => {
let count = validate_const_with_value(count, ty, cx)?
.to_valtree()
.0
.try_to_target_usize(tcx)
.ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?;
let element = cx.layout_of(element)?;
let size = element
.size
@ -687,6 +711,9 @@ fn layout_of_uncached<'tcx>(
// Types with no meaningful known layout.
ty::Alias(..) => {
if ty.has_param() {
return Err(error(cx, LayoutError::TooGeneric(ty)));
}
// NOTE(eddyb) `layout_of` query should've normalized these away,
// if that was possible, so there's no reason to try again here.
return Err(error(cx, LayoutError::Unknown(ty)));
@ -696,7 +723,11 @@ fn layout_of_uncached<'tcx>(
bug!("Layout::compute: unexpected type `{}`", ty)
}
ty::Placeholder(..) | ty::Param(_) => {
ty::Param(_) => {
return Err(error(cx, LayoutError::TooGeneric(ty)));
}
ty::Placeholder(..) => {
return Err(error(cx, LayoutError::Unknown(ty)));
}
})

View file

@ -28,13 +28,11 @@
{% endfor %}
</ul>
{% 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<T>`. #}
{# This kind of layout error can occur with valid code, for example
if there are trivial bounds: `struct Foo(str, str) where str: Sized;`. #}
{% when Err(LayoutError::Unknown(_)) %}
<p> {# #}
<strong>Note:</strong> Unable to compute type layout, {#+ #}
possibly due to this type having generic parameters. {#+ #}
Layout can only be computed for concrete, fully-instantiated types. {# #}
<strong>Note:</strong> Unable to compute type layout. {# #}
</p>
{# 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
@ -44,6 +42,14 @@
<strong>Note:</strong> Encountered an error during type layout; {#+ #}
the type was too big. {# #}
</p>
{# 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>`. #}
{% when Err(LayoutError::TooGeneric(_)) %}
<p> {# #}
<strong>Note:</strong> Unable to compute type layout, {#+ #}
possibly due to this type having generic parameters. {#+ #}
Layout can only be computed for concrete, fully-instantiated types. {# #}
</p>
{% when Err(LayoutError::ReferencesError(_)) %}
<p> {# #}
<strong>Note:</strong> Encountered an error during type layout; {#+ #}

View file

@ -1,11 +0,0 @@
//@ known-bug: #135020
pub fn problem_thingy(items: &mut impl Iterator<Item = str>) {
let mut peeker = items.peekable();
match peeker.peek() {
Some(_) => (),
None => return (),
}
}
pub fn main() {}

View file

@ -37,7 +37,8 @@ pub struct Y(u8);
pub struct Z;
// We can't compute layout for generic types.
//@ hasraw type_layout/struct.Generic.html 'Unable to compute type layout, possibly due to this type having generic parameters'
//@ hasraw type_layout/struct.Generic.html 'Unable to compute type layout, possibly due to this type having generic parameters.'
//@ hasraw type_layout/struct.Generic.html 'Layout can only be computed for concrete, fully-instantiated types.'
//@ !hasraw - 'Size: '
pub struct Generic<T>(T);
@ -91,3 +92,9 @@ pub enum Uninhabited {}
//@ hasraw type_layout/struct.Uninhabited2.html 'Size: '
//@ hasraw - '8 bytes (<a href="https://doc.rust-lang.org/stable/reference/glossary.html#uninhabited">uninhabited</a>)'
pub struct Uninhabited2(std::convert::Infallible, u64);
pub trait Project { type Assoc; }
// We can't compute layout. A `LayoutError::Unknown` is returned.
//@ hasraw type_layout/struct.Unknown.html 'Unable to compute type layout.'
//@ !hasraw - 'Size: '
pub struct Unknown(<() as Project>::Assoc) where for<'a> (): Project;

View file

@ -6,7 +6,7 @@ union Foo {
enum Bar {
Boo = {
let _: Option<Foo> = None;
let _: Option<Foo> = None; //~ ERROR evaluation of constant value failed
0
},
}

View file

@ -45,7 +45,13 @@ help: wrap the field type in `ManuallyDrop<...>`
LL | a: std::mem::ManuallyDrop<str>,
| +++++++++++++++++++++++ +
error: aborting due to 4 previous errors
error[E0080]: evaluation of constant value failed
--> $DIR/eval-error.rs:9:30
|
LL | let _: Option<Foo> = None;
| ^^^^ the type `Foo` has an unknown layout
Some errors have detailed explanations: E0277, E0517, E0740.
For more information about an error, try `rustc --explain E0277`.
error: aborting due to 5 previous errors
Some errors have detailed explanations: E0080, E0277, E0517, E0740.
For more information about an error, try `rustc --explain E0080`.

View file

@ -8,6 +8,7 @@ struct S {
}
const C: S = unsafe { std::mem::transmute(()) };
//~^ ERROR cannot transmute between types of different sizes, or dependently-sized types
const _: [(); {
C;
0

View file

@ -16,6 +16,16 @@ help: the `Box` type always has a statically known size and allocates its conten
LL | a: Box<[u8]>,
| ++++ +
error: aborting due to 1 previous error
error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
--> $DIR/base-layout-is-sized-ice-123078.rs:10:23
|
LL | const C: S = unsafe { std::mem::transmute(()) };
| ^^^^^^^^^^^^^^^^^^^
|
= note: source type: `()` (0 bits)
= note: target type: `S` (the type `S` has an unknown layout)
For more information about this error, try `rustc --explain E0277`.
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0277, E0512.
For more information about an error, try `rustc --explain E0277`.

View file

@ -10,5 +10,6 @@ struct LazyLock {
}
static EMPTY_SET: LazyLock = todo!();
//~^ ERROR could not evaluate static initializer
fn main() {}

View file

@ -7,6 +7,13 @@ LL | data: (dyn Sync, ()),
= help: the trait `Sized` is not implemented for `(dyn Sync + 'static)`
= note: only the last element of a tuple may have a dynamically sized type
error: aborting due to 1 previous error
error[E0080]: could not evaluate static initializer
--> $DIR/invalid-unsized-const-eval.rs:12:1
|
LL | static EMPTY_SET: LazyLock = todo!();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ the type `(dyn Sync, ())` has an unknown layout
For more information about this error, try `rustc --explain E0277`.
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0080, E0277.
For more information about an error, try `rustc --explain E0080`.

View file

@ -18,6 +18,20 @@ LL | struct MySlice<T>(T);
| |
| this could be changed to `T: ?Sized`...
error: aborting due to 1 previous error
error[E0080]: could not evaluate static initializer
--> $SRC_DIR/core/src/mem/mod.rs:LL:COL
|
= note: the type `MySlice<[bool]>` has an unknown layout
|
note: inside `align_of::<P2>`
--> $SRC_DIR/core/src/mem/mod.rs:LL:COL
note: inside `CHECK`
--> $DIR/invalid-unsized-in-always-sized-tail.rs:15:28
|
LL | static CHECK: () = assert!(align_of::<P2>() == 1);
| ^^^^^^^^^^^^^^^^
For more information about this error, try `rustc --explain E0277`.
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0080, E0277.
For more information about an error, try `rustc --explain E0080`.

View file

@ -6,5 +6,6 @@ struct ArenaSet<U: Deref, V: ?Sized = <U as Deref>::Target>(V, U);
//~^ ERROR the size for values of type `V` cannot be known at compilation time
const DATA: *const ArenaSet<Vec<u8>> = std::ptr::null_mut();
//~^ ERROR evaluation of constant value failed
pub fn main() {}

View file

@ -22,6 +22,13 @@ help: the `Box` type always has a statically known size and allocates its conten
LL | struct ArenaSet<U: Deref, V: ?Sized = <U as Deref>::Target>(Box<V>, U);
| ++++ +
error: aborting due to 1 previous error
error[E0080]: evaluation of constant value failed
--> $DIR/issue-unsized-tail-restatic-ice-122488.rs:8:1
|
LL | const DATA: *const ArenaSet<Vec<u8>> = std::ptr::null_mut();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the type `ArenaSet<Vec<u8>, [u8]>` has an unknown layout
For more information about this error, try `rustc --explain E0277`.
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0080, E0277.
For more information about an error, try `rustc --explain E0080`.

View file

@ -0,0 +1,11 @@
#![feature(trivial_bounds)]
fn return_str()
where
str: Sized,
{
[(); { let _a: Option<str> = None; 0 }];
//~^ ERROR evaluation of constant value failed
}
fn main() {}

View file

@ -0,0 +1,9 @@
error[E0080]: evaluation of constant value failed
--> $DIR/uncomputable-due-to-trivial-bounds-ice-135138.rs:7:16
|
LL | [(); { let _a: Option<str> = None; 0 }];
| ^^ the type `Option<str>` has an unknown layout
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0080`.

View file

@ -0,0 +1,7 @@
//@ check-pass
fn problem_thingy(items: &mut impl Iterator<Item = str>) {
items.peekable();
}
fn main() {}

View file

@ -0,0 +1,14 @@
#![feature(trivial_bounds)]
//@ error-pattern: error[E0080]: evaluation of constant value failed
//@ error-pattern: the type `<() as Project>::Assoc` has an unknown layout
trait Project {
type Assoc;
}
fn foo() where (): Project {
[(); size_of::<<() as Project>::Assoc>()];
}
fn main() {}

View file

@ -0,0 +1,16 @@
error[E0080]: evaluation of constant value failed
--> $SRC_DIR/core/src/mem/mod.rs:LL:COL
|
= note: the type `<() as Project>::Assoc` has an unknown layout
|
note: inside `std::mem::size_of::<<() as Project>::Assoc>`
--> $SRC_DIR/core/src/mem/mod.rs:LL:COL
note: inside `foo::{constant#0}`
--> $DIR/unknown-when-no-type-parameter.rs:11:10
|
LL | [(); size_of::<<() as Project>::Assoc>()];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0080`.

View file

@ -0,0 +1,12 @@
#![feature(ptr_metadata)]
#![feature(trivial_bounds)]
fn return_str()
where
str: std::ptr::Pointee<Metadata = str>,
{
[(); { let _a: Option<&str> = None; 0 }];
//~^ ERROR evaluation of constant value failed
}
fn main() {}

View file

@ -0,0 +1,9 @@
error[E0080]: evaluation of constant value failed
--> $DIR/unknown-when-ptr-metadata-is-DST.rs:8:16
|
LL | [(); { let _a: Option<&str> = None; 0 }];
| ^^ the type `str` has an unknown layout
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0080`.

View file

@ -13,6 +13,6 @@ struct Other {
fn main() {
unsafe {
std::mem::transmute::<Option<()>, Option<&Other>>(None);
//~^ ERROR cannot transmute
//~^ ERROR cannot transmute between types of different sizes, or dependently-sized types
}
}