Skip to content

Add TooGeneric variant to LayoutError and emit Unknown #135158

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion compiler/rustc_const_eval/src/const_eval/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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))) => {
Expand Down
8 changes: 6 additions & 2 deletions compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
}
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_typeck/src/intrinsicck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_middle/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -100,11 +100,14 @@ 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 =
the type `{$ty}` has an 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}'
3 changes: 3 additions & 0 deletions compiler/rustc_middle/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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> },

Expand Down
14 changes: 10 additions & 4 deletions compiler/rustc_middle/src/ty/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand All @@ -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,
Expand All @@ -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() }
}
Expand All @@ -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")
}
Expand Down Expand Up @@ -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(_),
Expand Down Expand Up @@ -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),
}
}

Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_transmute/src/layout/tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
69 changes: 50 additions & 19 deletions compiler/rustc_ty_utils/src/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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>,
Expand Down Expand Up @@ -182,12 +209,13 @@ fn layout_of_uncached<'tcx>(
&mut layout.backend_repr
{
if let Some(start) = start {
scalar.valid_range_mut().start = start
.try_to_bits(tcx, cx.typing_env)
.ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?;
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 {
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)));
Expand All @@ -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)));
}
})
Expand Down
16 changes: 11 additions & 5 deletions src/librustdoc/html/templates/type_layout.html
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,11 @@ <h2 id="layout" class="section-header"> {# #}
{% 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
Expand All @@ -44,6 +42,14 @@ <h2 id="layout" class="section-header"> {# #}
<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; {#+ #}
Expand Down
11 changes: 0 additions & 11 deletions tests/crashes/135020.rs

This file was deleted.

9 changes: 8 additions & 1 deletion tests/rustdoc/type-layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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;
2 changes: 1 addition & 1 deletion tests/ui/enum-discriminant/eval-error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ union Foo {

enum Bar {
Boo = {
let _: Option<Foo> = None;
let _: Option<Foo> = None; //~ ERROR evaluation of constant value failed
0
},
}
Expand Down
12 changes: 9 additions & 3 deletions tests/ui/enum-discriminant/eval-error.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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

error: aborting due to 5 previous errors

Some errors have detailed explanations: E0277, E0517, E0740.
For more information about an error, try `rustc --explain E0277`.
Some errors have detailed explanations: E0080, E0277, E0517, E0740.
For more information about an error, try `rustc --explain E0080`.
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ impl<T, const L: u8> VirtualWrapper<T, L> {
impl<T: MyTrait + 'static, const L: u8> MyTrait for VirtualWrapper<T, L> {
fn virtualize(&self) -> &dyn MyTrait {
unsafe { virtualize_my_trait(L, self) }
// unsafe { virtualize_my_trait(L, &self.0) } // <-- this code fixes the problem
// unsafe { virtualize_my_trait(L, &self.0) } // <-- this code fixes the problem
}
}

Expand Down
1 change: 1 addition & 0 deletions tests/ui/layout/base-layout-is-sized-ice-123078.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
14 changes: 12 additions & 2 deletions tests/ui/layout/base-layout-is-sized-ice-123078.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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)

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0277`.
Some errors have detailed explanations: E0277, E0512.
For more information about an error, try `rustc --explain E0277`.
1 change: 1 addition & 0 deletions tests/ui/layout/invalid-unsized-const-eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@ struct LazyLock {
}

static EMPTY_SET: LazyLock = todo!();
//~^ ERROR could not evaluate static initializer

fn main() {}
11 changes: 9 additions & 2 deletions tests/ui/layout/invalid-unsized-const-eval.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0277`.
Some errors have detailed explanations: E0080, E0277.
For more information about an error, try `rustc --explain E0080`.
Loading
Loading