Rollup merge of #137218 - lukas-code:layout_of_cleanup, r=compiler-errors
misc `layout_of` cleanup See individual commits for details. r? `@oli-obk` but feel free to reassign
This commit is contained in:
commit
bafff1b3af
8 changed files with 175 additions and 105 deletions
|
@ -37,9 +37,6 @@ middle_autodiff_unsafe_inner_const_ref = reading from a `Duplicated` const {$ty}
|
||||||
middle_bounds_check =
|
middle_bounds_check =
|
||||||
index out of bounds: the length is {$len} but the index is {$index}
|
index out of bounds: the length is {$len} but the index is {$index}
|
||||||
|
|
||||||
middle_cannot_be_normalized =
|
|
||||||
unable to determine layout for `{$ty}` because `{$failure_ty}` cannot be normalized
|
|
||||||
|
|
||||||
middle_conflict_types =
|
middle_conflict_types =
|
||||||
this expression supplies two conflicting concrete types for the same opaque type
|
this expression supplies two conflicting concrete types for the same opaque type
|
||||||
|
|
||||||
|
@ -52,9 +49,6 @@ middle_const_eval_non_int =
|
||||||
middle_const_not_used_in_type_alias =
|
middle_const_not_used_in_type_alias =
|
||||||
const parameter `{$ct}` is part of concrete type but not used in parameter list for the `impl Trait` type alias
|
const parameter `{$ct}` is part of concrete type but not used in parameter list for the `impl Trait` type alias
|
||||||
|
|
||||||
middle_cycle =
|
|
||||||
a cycle occurred during layout computation
|
|
||||||
|
|
||||||
middle_deprecated = use of deprecated {$kind} `{$path}`{$has_note ->
|
middle_deprecated = use of deprecated {$kind} `{$path}`{$has_note ->
|
||||||
[true] : {$note}
|
[true] : {$note}
|
||||||
*[other] {""}
|
*[other] {""}
|
||||||
|
@ -78,9 +72,23 @@ middle_erroneous_constant = erroneous constant encountered
|
||||||
middle_failed_writing_file =
|
middle_failed_writing_file =
|
||||||
failed to write file {$path}: {$error}"
|
failed to write file {$path}: {$error}"
|
||||||
|
|
||||||
|
middle_layout_cycle =
|
||||||
|
a cycle occurred during layout computation
|
||||||
|
|
||||||
|
middle_layout_normalization_failure =
|
||||||
|
unable to determine layout for `{$ty}` because `{$failure_ty}` cannot be normalized
|
||||||
|
|
||||||
middle_layout_references_error =
|
middle_layout_references_error =
|
||||||
the type has an unknown layout
|
the type has an unknown layout
|
||||||
|
|
||||||
|
middle_layout_size_overflow =
|
||||||
|
values of the type `{$ty}` are too big for the target architecture
|
||||||
|
|
||||||
|
middle_layout_too_generic = the type `{$ty}` does not have a fixed layout
|
||||||
|
|
||||||
|
middle_layout_unknown =
|
||||||
|
the type `{$ty}` has an unknown layout
|
||||||
|
|
||||||
middle_opaque_hidden_type_mismatch =
|
middle_opaque_hidden_type_mismatch =
|
||||||
concrete type differs from previous defining opaque type use
|
concrete type differs from previous defining opaque type use
|
||||||
.label = expected `{$self_ty}`, got `{$other_ty}`
|
.label = expected `{$self_ty}`, got `{$other_ty}`
|
||||||
|
@ -98,16 +106,8 @@ middle_strict_coherence_needs_negative_coherence =
|
||||||
to use `strict_coherence` on this trait, the `with_negative_coherence` feature must be enabled
|
to use `strict_coherence` on this trait, the `with_negative_coherence` feature must be enabled
|
||||||
.label = due to this attribute
|
.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_type_length_limit = reached the type-length limit while instantiating `{$shrunk}`
|
||||||
|
|
||||||
middle_unknown_layout =
|
|
||||||
the type `{$ty}` has an unknown layout
|
|
||||||
|
|
||||||
middle_unsupported_union = we don't support unions yet: '{$ty_name}'
|
middle_unsupported_union = we don't support unions yet: '{$ty_name}'
|
||||||
|
|
||||||
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}'
|
middle_written_to_path = the full type name has been written to '{$path}'
|
||||||
|
|
|
@ -132,19 +132,19 @@ impl fmt::Debug for CustomSubdiagnostic<'_> {
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
pub enum LayoutError<'tcx> {
|
pub enum LayoutError<'tcx> {
|
||||||
#[diag(middle_unknown_layout)]
|
#[diag(middle_layout_unknown)]
|
||||||
Unknown { ty: Ty<'tcx> },
|
Unknown { ty: Ty<'tcx> },
|
||||||
|
|
||||||
#[diag(middle_too_generic)]
|
#[diag(middle_layout_too_generic)]
|
||||||
TooGeneric { ty: Ty<'tcx> },
|
TooGeneric { ty: Ty<'tcx> },
|
||||||
|
|
||||||
#[diag(middle_values_too_big)]
|
#[diag(middle_layout_size_overflow)]
|
||||||
Overflow { ty: Ty<'tcx> },
|
Overflow { ty: Ty<'tcx> },
|
||||||
|
|
||||||
#[diag(middle_cannot_be_normalized)]
|
#[diag(middle_layout_normalization_failure)]
|
||||||
NormalizationFailure { ty: Ty<'tcx>, failure_ty: String },
|
NormalizationFailure { ty: Ty<'tcx>, failure_ty: String },
|
||||||
|
|
||||||
#[diag(middle_cycle)]
|
#[diag(middle_layout_cycle)]
|
||||||
Cycle,
|
Cycle,
|
||||||
|
|
||||||
#[diag(middle_layout_references_error)]
|
#[diag(middle_layout_references_error)]
|
||||||
|
|
|
@ -229,11 +229,32 @@ impl fmt::Display for ValidityRequirement {
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, HashStable, TyEncodable, TyDecodable)]
|
#[derive(Copy, Clone, Debug, HashStable, TyEncodable, TyDecodable)]
|
||||||
pub enum LayoutError<'tcx> {
|
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>),
|
Unknown(Ty<'tcx>),
|
||||||
|
/// The size of a type exceeds [`TargetDataLayout::obj_size_bound`].
|
||||||
SizeOverflow(Ty<'tcx>),
|
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>),
|
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>),
|
NormalizationFailure(Ty<'tcx>, NormalizationError<'tcx>),
|
||||||
|
/// A non-layout error is reported elsewhere.
|
||||||
ReferencesError(ErrorGuaranteed),
|
ReferencesError(ErrorGuaranteed),
|
||||||
|
/// A type has cyclic layout, i.e. the type contains itself without indirection.
|
||||||
Cycle(ErrorGuaranteed),
|
Cycle(ErrorGuaranteed),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -243,11 +264,11 @@ impl<'tcx> LayoutError<'tcx> {
|
||||||
|
|
||||||
use crate::fluent_generated::*;
|
use crate::fluent_generated::*;
|
||||||
match self {
|
match self {
|
||||||
Unknown(_) => middle_unknown_layout,
|
Unknown(_) => middle_layout_unknown,
|
||||||
SizeOverflow(_) => middle_values_too_big,
|
SizeOverflow(_) => middle_layout_size_overflow,
|
||||||
TooGeneric(_) => middle_too_generic,
|
TooGeneric(_) => middle_layout_too_generic,
|
||||||
NormalizationFailure(_, _) => middle_cannot_be_normalized,
|
NormalizationFailure(_, _) => middle_layout_normalization_failure,
|
||||||
Cycle(_) => middle_cycle,
|
Cycle(_) => middle_layout_cycle,
|
||||||
ReferencesError(_) => middle_layout_references_error,
|
ReferencesError(_) => middle_layout_references_error,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -276,7 +297,7 @@ impl<'tcx> fmt::Display for LayoutError<'tcx> {
|
||||||
match *self {
|
match *self {
|
||||||
LayoutError::Unknown(ty) => write!(f, "the type `{ty}` has an unknown layout"),
|
LayoutError::Unknown(ty) => write!(f, "the type `{ty}` has an unknown layout"),
|
||||||
LayoutError::TooGeneric(ty) => {
|
LayoutError::TooGeneric(ty) => {
|
||||||
write!(f, "`{ty}` does not have a fixed size")
|
write!(f, "the type `{ty}` does not have a fixed layout")
|
||||||
}
|
}
|
||||||
LayoutError::SizeOverflow(ty) => {
|
LayoutError::SizeOverflow(ty) => {
|
||||||
write!(f, "values of the type `{ty}` are too big for the target architecture")
|
write!(f, "values of the type `{ty}` are too big for the target architecture")
|
||||||
|
|
|
@ -134,42 +134,32 @@ fn univariant_uninterned<'tcx>(
|
||||||
cx: &LayoutCx<'tcx>,
|
cx: &LayoutCx<'tcx>,
|
||||||
ty: Ty<'tcx>,
|
ty: Ty<'tcx>,
|
||||||
fields: &IndexSlice<FieldIdx, TyAndLayout<'tcx>>,
|
fields: &IndexSlice<FieldIdx, TyAndLayout<'tcx>>,
|
||||||
repr: &ReprOptions,
|
|
||||||
kind: StructKind,
|
kind: StructKind,
|
||||||
) -> Result<LayoutData<FieldIdx, VariantIdx>, &'tcx LayoutError<'tcx>> {
|
) -> Result<LayoutData<FieldIdx, VariantIdx>, &'tcx LayoutError<'tcx>> {
|
||||||
let pack = repr.pack;
|
let repr = ReprOptions::default();
|
||||||
if pack.is_some() && repr.align.is_some() {
|
cx.calc.univariant(fields, &repr, kind).map_err(|err| map_error(cx, ty, err))
|
||||||
cx.tcx().dcx().bug("struct cannot be packed and aligned");
|
|
||||||
}
|
|
||||||
|
|
||||||
cx.calc.univariant(fields, repr, kind).map_err(|err| map_error(cx, ty, err))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extract_const_value<'tcx>(
|
fn extract_const_value<'tcx>(
|
||||||
const_: ty::Const<'tcx>,
|
|
||||||
ty: Ty<'tcx>,
|
|
||||||
cx: &LayoutCx<'tcx>,
|
cx: &LayoutCx<'tcx>,
|
||||||
|
ty: Ty<'tcx>,
|
||||||
|
ct: ty::Const<'tcx>,
|
||||||
) -> Result<ty::Value<'tcx>, &'tcx LayoutError<'tcx>> {
|
) -> Result<ty::Value<'tcx>, &'tcx LayoutError<'tcx>> {
|
||||||
match const_.kind() {
|
match ct.kind() {
|
||||||
ty::ConstKind::Value(cv) => Ok(cv),
|
ty::ConstKind::Value(cv) => Ok(cv),
|
||||||
ty::ConstKind::Error(guar) => {
|
ty::ConstKind::Param(_) | ty::ConstKind::Expr(_) | ty::ConstKind::Unevaluated(_) => {
|
||||||
return Err(error(cx, LayoutError::ReferencesError(guar)));
|
if !ct.has_param() {
|
||||||
}
|
bug!("failed to normalize const, but it is not generic: {ct:?}");
|
||||||
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)));
|
Err(error(cx, LayoutError::TooGeneric(ty)))
|
||||||
}
|
}
|
||||||
ty::ConstKind::Unevaluated(_) => {
|
ty::ConstKind::Infer(_)
|
||||||
if !const_.has_param() {
|
| ty::ConstKind::Bound(..)
|
||||||
return Err(error(cx, LayoutError::Unknown(ty)));
|
| ty::ConstKind::Placeholder(_)
|
||||||
} else {
|
| ty::ConstKind::Error(_) => {
|
||||||
return Err(error(cx, LayoutError::TooGeneric(ty)));
|
// `ty::ConstKind::Error` is handled at the top of `layout_of_uncached`
|
||||||
}
|
// (via `ty.error_reported()`).
|
||||||
}
|
bug!("layout_of: unexpected const: {ct:?}");
|
||||||
ty::ConstKind::Infer(_) | ty::ConstKind::Bound(..) | ty::ConstKind::Placeholder(_) => {
|
|
||||||
bug!("unexpected type: {ty:?}");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -194,10 +184,9 @@ fn layout_of_uncached<'tcx>(
|
||||||
};
|
};
|
||||||
let scalar = |value: Primitive| tcx.mk_layout(LayoutData::scalar(cx, scalar_unit(value)));
|
let scalar = |value: Primitive| tcx.mk_layout(LayoutData::scalar(cx, scalar_unit(value)));
|
||||||
|
|
||||||
let univariant =
|
let univariant = |fields: &IndexSlice<FieldIdx, TyAndLayout<'tcx>>, kind| {
|
||||||
|fields: &IndexSlice<FieldIdx, TyAndLayout<'tcx>>, repr: &ReprOptions, kind| {
|
Ok(tcx.mk_layout(univariant_uninterned(cx, ty, fields, kind)?))
|
||||||
Ok(tcx.mk_layout(univariant_uninterned(cx, ty, fields, repr, kind)?))
|
};
|
||||||
};
|
|
||||||
debug_assert!(!ty.has_non_region_infer());
|
debug_assert!(!ty.has_non_region_infer());
|
||||||
|
|
||||||
Ok(match *ty.kind() {
|
Ok(match *ty.kind() {
|
||||||
|
@ -210,12 +199,12 @@ fn layout_of_uncached<'tcx>(
|
||||||
&mut layout.backend_repr
|
&mut layout.backend_repr
|
||||||
{
|
{
|
||||||
if let Some(start) = start {
|
if let Some(start) = start {
|
||||||
scalar.valid_range_mut().start = extract_const_value(start, ty, cx)?
|
scalar.valid_range_mut().start = extract_const_value(cx, ty, start)?
|
||||||
.try_to_bits(tcx, cx.typing_env)
|
.try_to_bits(tcx, cx.typing_env)
|
||||||
.ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?;
|
.ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?;
|
||||||
}
|
}
|
||||||
if let Some(end) = end {
|
if let Some(end) = end {
|
||||||
let mut end = extract_const_value(end, ty, cx)?
|
let mut end = extract_const_value(cx, ty, end)?
|
||||||
.try_to_bits(tcx, cx.typing_env)
|
.try_to_bits(tcx, cx.typing_env)
|
||||||
.ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?;
|
.ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?;
|
||||||
if !include_end {
|
if !include_end {
|
||||||
|
@ -274,16 +263,11 @@ fn layout_of_uncached<'tcx>(
|
||||||
data_ptr.valid_range_mut().start = 1;
|
data_ptr.valid_range_mut().start = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
let pointee = tcx.normalize_erasing_regions(cx.typing_env, pointee);
|
|
||||||
if pointee.is_sized(tcx, cx.typing_env) {
|
if pointee.is_sized(tcx, cx.typing_env) {
|
||||||
return Ok(tcx.mk_layout(LayoutData::scalar(cx, data_ptr)));
|
return Ok(tcx.mk_layout(LayoutData::scalar(cx, data_ptr)));
|
||||||
}
|
}
|
||||||
|
|
||||||
let metadata = if let Some(metadata_def_id) = tcx.lang_items().metadata_type()
|
let metadata = if let Some(metadata_def_id) = tcx.lang_items().metadata_type() {
|
||||||
// Projection eagerly bails out when the pointee references errors,
|
|
||||||
// fall back to structurally deducing metadata.
|
|
||||||
&& !pointee.references_error()
|
|
||||||
{
|
|
||||||
let pointee_metadata = Ty::new_projection(tcx, metadata_def_id, [pointee]);
|
let pointee_metadata = Ty::new_projection(tcx, metadata_def_id, [pointee]);
|
||||||
let metadata_ty =
|
let metadata_ty =
|
||||||
match tcx.try_normalize_erasing_regions(cx.typing_env, pointee_metadata) {
|
match tcx.try_normalize_erasing_regions(cx.typing_env, pointee_metadata) {
|
||||||
|
@ -354,7 +338,7 @@ fn layout_of_uncached<'tcx>(
|
||||||
|
|
||||||
// Arrays and slices.
|
// Arrays and slices.
|
||||||
ty::Array(element, count) => {
|
ty::Array(element, count) => {
|
||||||
let count = extract_const_value(count, ty, cx)?
|
let count = extract_const_value(cx, ty, count)?
|
||||||
.try_to_target_usize(tcx)
|
.try_to_target_usize(tcx)
|
||||||
.ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?;
|
.ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?;
|
||||||
|
|
||||||
|
@ -415,17 +399,10 @@ fn layout_of_uncached<'tcx>(
|
||||||
}),
|
}),
|
||||||
|
|
||||||
// Odd unit types.
|
// Odd unit types.
|
||||||
ty::FnDef(..) => {
|
ty::FnDef(..) => univariant(IndexSlice::empty(), StructKind::AlwaysSized)?,
|
||||||
univariant(IndexSlice::empty(), &ReprOptions::default(), StructKind::AlwaysSized)?
|
|
||||||
}
|
|
||||||
ty::Dynamic(_, _, ty::Dyn) | ty::Foreign(..) => {
|
ty::Dynamic(_, _, ty::Dyn) | ty::Foreign(..) => {
|
||||||
let mut unit = univariant_uninterned(
|
let mut unit =
|
||||||
cx,
|
univariant_uninterned(cx, ty, IndexSlice::empty(), StructKind::AlwaysSized)?;
|
||||||
ty,
|
|
||||||
IndexSlice::empty(),
|
|
||||||
&ReprOptions::default(),
|
|
||||||
StructKind::AlwaysSized,
|
|
||||||
)?;
|
|
||||||
match unit.backend_repr {
|
match unit.backend_repr {
|
||||||
BackendRepr::Memory { ref mut sized } => *sized = false,
|
BackendRepr::Memory { ref mut sized } => *sized = false,
|
||||||
_ => bug!(),
|
_ => bug!(),
|
||||||
|
@ -439,7 +416,6 @@ fn layout_of_uncached<'tcx>(
|
||||||
let tys = args.as_closure().upvar_tys();
|
let tys = args.as_closure().upvar_tys();
|
||||||
univariant(
|
univariant(
|
||||||
&tys.iter().map(|ty| cx.layout_of(ty)).try_collect::<IndexVec<_, _>>()?,
|
&tys.iter().map(|ty| cx.layout_of(ty)).try_collect::<IndexVec<_, _>>()?,
|
||||||
&ReprOptions::default(),
|
|
||||||
StructKind::AlwaysSized,
|
StructKind::AlwaysSized,
|
||||||
)?
|
)?
|
||||||
}
|
}
|
||||||
|
@ -448,7 +424,6 @@ fn layout_of_uncached<'tcx>(
|
||||||
let tys = args.as_coroutine_closure().upvar_tys();
|
let tys = args.as_coroutine_closure().upvar_tys();
|
||||||
univariant(
|
univariant(
|
||||||
&tys.iter().map(|ty| cx.layout_of(ty)).try_collect::<IndexVec<_, _>>()?,
|
&tys.iter().map(|ty| cx.layout_of(ty)).try_collect::<IndexVec<_, _>>()?,
|
||||||
&ReprOptions::default(),
|
|
||||||
StructKind::AlwaysSized,
|
StructKind::AlwaysSized,
|
||||||
)?
|
)?
|
||||||
}
|
}
|
||||||
|
@ -457,11 +432,7 @@ fn layout_of_uncached<'tcx>(
|
||||||
let kind =
|
let kind =
|
||||||
if tys.len() == 0 { StructKind::AlwaysSized } else { StructKind::MaybeUnsized };
|
if tys.len() == 0 { StructKind::AlwaysSized } else { StructKind::MaybeUnsized };
|
||||||
|
|
||||||
univariant(
|
univariant(&tys.iter().map(|k| cx.layout_of(k)).try_collect::<IndexVec<_, _>>()?, kind)?
|
||||||
&tys.iter().map(|k| cx.layout_of(k)).try_collect::<IndexVec<_, _>>()?,
|
|
||||||
&ReprOptions::default(),
|
|
||||||
kind,
|
|
||||||
)?
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SIMD vector types.
|
// SIMD vector types.
|
||||||
|
@ -719,25 +690,30 @@ fn layout_of_uncached<'tcx>(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Types with no meaningful known layout.
|
// 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)));
|
|
||||||
}
|
|
||||||
|
|
||||||
ty::Bound(..) | ty::CoroutineWitness(..) | ty::Infer(_) | ty::Error(_) => {
|
|
||||||
bug!("Layout::compute: unexpected type `{}`", ty)
|
|
||||||
}
|
|
||||||
|
|
||||||
ty::Param(_) => {
|
ty::Param(_) => {
|
||||||
return Err(error(cx, LayoutError::TooGeneric(ty)));
|
return Err(error(cx, LayoutError::TooGeneric(ty)));
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::Placeholder(..) => {
|
ty::Alias(..) => {
|
||||||
return Err(error(cx, LayoutError::Unknown(ty)));
|
// NOTE(eddyb) `layout_of` query should've normalized these away,
|
||||||
|
// if that was possible, so there's no reason to try again here.
|
||||||
|
let err = if ty.has_param() {
|
||||||
|
LayoutError::TooGeneric(ty)
|
||||||
|
} else {
|
||||||
|
// This is only reachable with unsatisfiable predicates. For example, if we have
|
||||||
|
// `u8: Iterator`, then we can't compute the layout of `<u8 as Iterator>::Item`.
|
||||||
|
LayoutError::Unknown(ty)
|
||||||
|
};
|
||||||
|
return Err(error(cx, err));
|
||||||
|
}
|
||||||
|
|
||||||
|
ty::Placeholder(..)
|
||||||
|
| ty::Bound(..)
|
||||||
|
| ty::CoroutineWitness(..)
|
||||||
|
| ty::Infer(_)
|
||||||
|
| ty::Error(_) => {
|
||||||
|
// `ty::Error` is handled at the top of this function.
|
||||||
|
bug!("layout_of: unexpected type `{ty}`")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -911,13 +887,7 @@ fn coroutine_layout<'tcx>(
|
||||||
.chain(iter::once(Ok(tag_layout)))
|
.chain(iter::once(Ok(tag_layout)))
|
||||||
.chain(promoted_layouts)
|
.chain(promoted_layouts)
|
||||||
.try_collect::<IndexVec<_, _>>()?;
|
.try_collect::<IndexVec<_, _>>()?;
|
||||||
let prefix = univariant_uninterned(
|
let prefix = univariant_uninterned(cx, ty, &prefix_layouts, StructKind::AlwaysSized)?;
|
||||||
cx,
|
|
||||||
ty,
|
|
||||||
&prefix_layouts,
|
|
||||||
&ReprOptions::default(),
|
|
||||||
StructKind::AlwaysSized,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let (prefix_size, prefix_align) = (prefix.size, prefix.align);
|
let (prefix_size, prefix_align) = (prefix.size, prefix.align);
|
||||||
|
|
||||||
|
@ -982,7 +952,6 @@ fn coroutine_layout<'tcx>(
|
||||||
cx,
|
cx,
|
||||||
ty,
|
ty,
|
||||||
&variant_only_tys.map(|ty| cx.layout_of(ty)).try_collect::<IndexVec<_, _>>()?,
|
&variant_only_tys.map(|ty| cx.layout_of(ty)).try_collect::<IndexVec<_, _>>()?,
|
||||||
&ReprOptions::default(),
|
|
||||||
StructKind::Prefixed(prefix_size, prefix_align.abi),
|
StructKind::Prefixed(prefix_size, prefix_align.abi),
|
||||||
)?;
|
)?;
|
||||||
variant.variants = Variants::Single { index };
|
variant.variants = Variants::Single { index };
|
||||||
|
|
|
@ -82,3 +82,8 @@ type Impossible = (str, str); //~ ERROR: cannot be known at compilation time
|
||||||
#[rustc_layout(debug)]
|
#[rustc_layout(debug)]
|
||||||
union EmptyUnion {} //~ ERROR: has an unknown layout
|
union EmptyUnion {} //~ ERROR: has an unknown layout
|
||||||
//~^ ERROR: unions cannot have zero fields
|
//~^ 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 layout
|
||||||
|
|
|
@ -596,12 +596,18 @@ error: the type has an unknown layout
|
||||||
LL | union EmptyUnion {}
|
LL | union EmptyUnion {}
|
||||||
| ^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: the type `T` does not have a fixed layout
|
||||||
|
--> $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
|
error: `#[rustc_layout]` can only be applied to `struct`/`enum`/`union` declarations and type aliases
|
||||||
--> $DIR/debug.rs:75:5
|
--> $DIR/debug.rs:75:5
|
||||||
|
|
|
|
||||||
LL | const C: () = ();
|
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`.
|
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