diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs index 4bc578c7985..e8257544498 100644 --- a/compiler/rustc_abi/src/layout.rs +++ b/compiler/rustc_abi/src/layout.rs @@ -36,12 +36,14 @@ enum NicheBias { } #[derive(Copy, Clone, Debug)] -pub enum LayoutCalculatorError { +pub enum LayoutCalculatorError { /// An unsized type was found in a location where a sized type was expected. /// /// This is not always a compile error, for example if there is a `[T]: Sized` /// bound in a where clause. - UnexpectedUnsized, + /// + /// Contains the field that was unexpectedly unsized. + UnexpectedUnsized(F), /// A type was too large for the target platform. SizeOverflow, @@ -50,8 +52,8 @@ pub enum LayoutCalculatorError { EmptyUnion, } -type LayoutCalculatorResult = - Result, LayoutCalculatorError>; +type LayoutCalculatorResult = + Result, LayoutCalculatorError>; #[derive(Clone, Copy, Debug)] pub struct LayoutCalculator { @@ -100,13 +102,13 @@ impl LayoutCalculator { 'a, FieldIdx: Idx, VariantIdx: Idx, - F: Deref> + fmt::Debug, + F: Deref> + fmt::Debug + Copy, >( &self, fields: &IndexSlice, repr: &ReprOptions, kind: StructKind, - ) -> LayoutCalculatorResult { + ) -> LayoutCalculatorResult { let dl = self.cx.data_layout(); let layout = self.univariant_biased(fields, repr, kind, NicheBias::Start); // Enums prefer niches close to the beginning or the end of the variants so that other @@ -191,7 +193,7 @@ impl LayoutCalculator { 'a, FieldIdx: Idx, VariantIdx: Idx, - F: Deref> + fmt::Debug, + F: Deref> + fmt::Debug + Copy, >( &self, repr: &ReprOptions, @@ -203,7 +205,7 @@ impl LayoutCalculator { discriminants: impl Iterator, dont_niche_optimize_enum: bool, always_sized: bool, - ) -> LayoutCalculatorResult { + ) -> LayoutCalculatorResult { let (present_first, present_second) = { let mut present_variants = variants .iter_enumerated() @@ -254,12 +256,12 @@ impl LayoutCalculator { 'a, FieldIdx: Idx, VariantIdx: Idx, - F: Deref> + fmt::Debug, + F: Deref> + fmt::Debug + Copy, >( &self, repr: &ReprOptions, variants: &IndexSlice>, - ) -> LayoutCalculatorResult { + ) -> LayoutCalculatorResult { let dl = self.cx.data_layout(); let mut align = if repr.pack.is_some() { dl.i8_align } else { dl.aggregate_align }; let mut max_repr_align = repr.align; @@ -279,7 +281,7 @@ impl LayoutCalculator { let only_variant = &variants[only_variant_idx]; for field in only_variant { if field.is_unsized() { - return Err(LayoutCalculatorError::UnexpectedUnsized); + return Err(LayoutCalculatorError::UnexpectedUnsized(*field)); } align = align.max(field.align); @@ -359,7 +361,12 @@ impl LayoutCalculator { } /// single-variant enums are just structs, if you think about it - fn layout_of_struct<'a, FieldIdx: Idx, VariantIdx: Idx, F>( + fn layout_of_struct< + 'a, + FieldIdx: Idx, + VariantIdx: Idx, + F: Deref> + fmt::Debug + Copy, + >( &self, repr: &ReprOptions, variants: &IndexSlice>, @@ -368,10 +375,7 @@ impl LayoutCalculator { scalar_valid_range: (Bound, Bound), always_sized: bool, present_first: VariantIdx, - ) -> LayoutCalculatorResult - where - F: Deref> + fmt::Debug, - { + ) -> LayoutCalculatorResult { // Struct, or univariant enum equivalent to a struct. // (Typechecking will reject discriminant-sizing attrs.) @@ -457,17 +461,19 @@ impl LayoutCalculator { Ok(st) } - fn layout_of_enum<'a, FieldIdx: Idx, VariantIdx: Idx, F>( + fn layout_of_enum< + 'a, + FieldIdx: Idx, + VariantIdx: Idx, + F: Deref> + fmt::Debug + Copy, + >( &self, repr: &ReprOptions, variants: &IndexSlice>, discr_range_of_repr: impl Fn(i128, i128) -> (Integer, bool), discriminants: impl Iterator, dont_niche_optimize_enum: bool, - ) -> LayoutCalculatorResult - where - F: Deref> + fmt::Debug, - { + ) -> LayoutCalculatorResult { // Until we've decided whether to use the tagged or // niche filling LayoutS, we don't want to intern the // variant layouts, so we can't store them in the @@ -972,14 +978,14 @@ impl LayoutCalculator { 'a, FieldIdx: Idx, VariantIdx: Idx, - F: Deref> + fmt::Debug, + F: Deref> + fmt::Debug + Copy, >( &self, fields: &IndexSlice, repr: &ReprOptions, kind: StructKind, niche_bias: NicheBias, - ) -> LayoutCalculatorResult { + ) -> LayoutCalculatorResult { let dl = self.cx.data_layout(); let pack = repr.pack; let mut align = if pack.is_some() { dl.i8_align } else { dl.aggregate_align }; @@ -1124,7 +1130,7 @@ impl LayoutCalculator { // field 5 with offset 0 puts 0 in offsets[5]. // At the bottom of this function, we invert `inverse_memory_index` to // produce `memory_index` (see `invert_mapping`). - let mut sized = true; + let mut unsized_field = None::<&F>; let mut offsets = IndexVec::from_elem(Size::ZERO, fields); let mut offset = Size::ZERO; let mut largest_niche = None; @@ -1137,12 +1143,12 @@ impl LayoutCalculator { } for &i in &inverse_memory_index { let field = &fields[i]; - if !sized { - return Err(LayoutCalculatorError::UnexpectedUnsized); + if let Some(unsized_field) = unsized_field { + return Err(LayoutCalculatorError::UnexpectedUnsized(*unsized_field)); } if field.is_unsized() { - sized = false; + unsized_field = Some(field); } // Invariant: offset < dl.obj_size_bound() <= 1<<61 @@ -1206,6 +1212,7 @@ impl LayoutCalculator { return Err(LayoutCalculatorError::SizeOverflow); } let mut layout_of_single_non_zst_field = None; + let sized = unsized_field.is_none(); let mut abi = Abi::Aggregate { sized }; let optimize_abi = !repr.inhibit_newtype_abi_optimization(); diff --git a/compiler/rustc_index/src/slice.rs b/compiler/rustc_index/src/slice.rs index 3205ca3f40b..956d32c9a69 100644 --- a/compiler/rustc_index/src/slice.rs +++ b/compiler/rustc_index/src/slice.rs @@ -20,7 +20,7 @@ pub struct IndexSlice { impl IndexSlice { #[inline] - pub const fn empty() -> &'static Self { + pub const fn empty<'a>() -> &'a Self { Self::from_raw(&[]) } diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index 50b6d8a0c3f..1d4c732242b 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -86,19 +86,21 @@ fn error<'tcx>(cx: &LayoutCx<'tcx>, err: LayoutError<'tcx>) -> &'tcx LayoutError fn map_error<'tcx>( cx: &LayoutCx<'tcx>, ty: Ty<'tcx>, - err: LayoutCalculatorError, + err: LayoutCalculatorError>, ) -> &'tcx LayoutError<'tcx> { let err = match err { LayoutCalculatorError::SizeOverflow => { // This is sometimes not a compile error in `check` builds. + // See `tests/ui/limits/huge-enum.rs` for an example. LayoutError::SizeOverflow(ty) } - LayoutCalculatorError::UnexpectedUnsized => { - // This is sometimes not a compile error if there are trivially false where - // clauses, but it is always a compiler error in the empty environment. - if cx.param_env.caller_bounds().is_empty() { + LayoutCalculatorError::UnexpectedUnsized(field) => { + // 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.param_env) { cx.tcx().dcx().delayed_bug(format!( - "encountered unexpected unsized field in layout of {ty:?}" + "encountered unexpected unsized field in layout of {ty:?}: {field:#?}" )); } LayoutError::Unknown(ty) @@ -115,7 +117,7 @@ fn map_error<'tcx>( fn univariant_uninterned<'tcx>( cx: &LayoutCx<'tcx>, ty: Ty<'tcx>, - fields: &IndexSlice>, + fields: &IndexSlice>, repr: &ReprOptions, kind: StructKind, ) -> Result, &'tcx LayoutError<'tcx>> { @@ -148,9 +150,10 @@ fn layout_of_uncached<'tcx>( }; let scalar = |value: Primitive| tcx.mk_layout(LayoutS::scalar(cx, scalar_unit(value))); - let univariant = |fields: &IndexSlice>, repr: &ReprOptions, kind| { - Ok(tcx.mk_layout(univariant_uninterned(cx, ty, fields, repr, kind)?)) - }; + let univariant = + |fields: &IndexSlice>, repr: &ReprOptions, kind| { + Ok(tcx.mk_layout(univariant_uninterned(cx, ty, fields, repr, kind)?)) + }; debug_assert!(!ty.has_non_region_infer()); Ok(match *ty.kind() { @@ -388,9 +391,7 @@ fn layout_of_uncached<'tcx>( ty::Closure(_, args) => { let tys = args.as_closure().upvar_tys(); univariant( - &tys.iter() - .map(|ty| Ok(cx.layout_of(ty)?.layout)) - .try_collect::>()?, + &tys.iter().map(|ty| cx.layout_of(ty)).try_collect::>()?, &ReprOptions::default(), StructKind::AlwaysSized, )? @@ -399,9 +400,7 @@ fn layout_of_uncached<'tcx>( ty::CoroutineClosure(_, args) => { let tys = args.as_coroutine_closure().upvar_tys(); univariant( - &tys.iter() - .map(|ty| Ok(cx.layout_of(ty)?.layout)) - .try_collect::>()?, + &tys.iter().map(|ty| cx.layout_of(ty)).try_collect::>()?, &ReprOptions::default(), StructKind::AlwaysSized, )? @@ -412,7 +411,7 @@ fn layout_of_uncached<'tcx>( if tys.len() == 0 { StructKind::AlwaysSized } else { StructKind::MaybeUnsized }; univariant( - &tys.iter().map(|k| Ok(cx.layout_of(k)?.layout)).try_collect::>()?, + &tys.iter().map(|k| cx.layout_of(k)).try_collect::>()?, &ReprOptions::default(), kind, )? @@ -552,7 +551,7 @@ fn layout_of_uncached<'tcx>( .map(|v| { v.fields .iter() - .map(|field| Ok(cx.layout_of(field.ty(tcx, args))?.layout)) + .map(|field| cx.layout_of(field.ty(tcx, args))) .try_collect::>() }) .try_collect::>()?; @@ -651,7 +650,7 @@ fn layout_of_uncached<'tcx>( { let mut variants = variants; let tail_replacement = cx.layout_of(Ty::new_slice(tcx, tcx.types.u8)).unwrap(); - *variants[FIRST_VARIANT].raw.last_mut().unwrap() = tail_replacement.layout; + *variants[FIRST_VARIANT].raw.last_mut().unwrap() = tail_replacement; let Ok(unsized_layout) = cx.calc.layout_of_struct_or_enum( &def.repr(), @@ -859,21 +858,24 @@ fn coroutine_layout<'tcx>( let max_discr = (info.variant_fields.len() - 1) as u128; let discr_int = Integer::fit_unsigned(max_discr); let tag = Scalar::Initialized { - value: Primitive::Int(discr_int, false), + value: Primitive::Int(discr_int, /* signed = */ false), valid_range: WrappingRange { start: 0, end: max_discr }, }; - let tag_layout = tcx.mk_layout(LayoutS::scalar(cx, tag)); + let tag_layout = TyAndLayout { + ty: discr_int.to_ty(tcx, /* signed = */ false), + layout: tcx.mk_layout(LayoutS::scalar(cx, tag)), + }; let promoted_layouts = ineligible_locals.iter().map(|local| { let field_ty = instantiate_field(info.field_tys[local].ty); let uninit_ty = Ty::new_maybe_uninit(tcx, field_ty); - Ok(cx.spanned_layout_of(uninit_ty, info.field_tys[local].source_info.span)?.layout) + cx.spanned_layout_of(uninit_ty, info.field_tys[local].source_info.span) }); let prefix_layouts = args .as_coroutine() .prefix_tys() .iter() - .map(|ty| Ok(cx.layout_of(ty)?.layout)) + .map(|ty| cx.layout_of(ty)) .chain(iter::once(Ok(tag_layout))) .chain(promoted_layouts) .try_collect::>()?; @@ -947,9 +949,7 @@ fn coroutine_layout<'tcx>( let mut variant = univariant_uninterned( cx, ty, - &variant_only_tys - .map(|ty| Ok(cx.layout_of(ty)?.layout)) - .try_collect::>()?, + &variant_only_tys.map(|ty| cx.layout_of(ty)).try_collect::>()?, &ReprOptions::default(), StructKind::Prefixed(prefix_size, prefix_align.abi), )?; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs index cc1f19c6b17..25362d23d55 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs @@ -106,10 +106,10 @@ impl fmt::Display for LayoutError { } } -impl From for LayoutError { - fn from(err: LayoutCalculatorError) -> Self { +impl From> for LayoutError { + fn from(err: LayoutCalculatorError) -> Self { match err { - LayoutCalculatorError::UnexpectedUnsized | LayoutCalculatorError::EmptyUnion => { + LayoutCalculatorError::UnexpectedUnsized(_) | LayoutCalculatorError::EmptyUnion => { LayoutError::Unknown } LayoutCalculatorError::SizeOverflow => LayoutError::SizeOverflow,