about summary refs log tree commit diff
diff options
context:
space:
mode:
authorLukas Markeffsky <@>2024-09-16 21:04:20 +0200
committerLukas Markeffsky <@>2024-09-17 00:06:56 +0200
commit3db930a463e32daa5052065cedf2d52472b67076 (patch)
tree91a005d0779a1f0989c61af432b99cf79de7ba98
parent697450151c0b674eae406a4d1e0854e9386ac7ea (diff)
downloadrust-3db930a463e32daa5052065cedf2d52472b67076.tar.gz
rust-3db930a463e32daa5052065cedf2d52472b67076.zip
assert that unexpectedly unsized fields are sized in the param env
-rw-r--r--compiler/rustc_abi/src/layout.rs61
-rw-r--r--compiler/rustc_index/src/slice.rs2
-rw-r--r--compiler/rustc_ty_utils/src/layout.rs52
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/layout.rs6
4 files changed, 64 insertions, 57 deletions
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<F> {
     /// 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<FieldIdx, VariantIdx> =
-    Result<LayoutS<FieldIdx, VariantIdx>, LayoutCalculatorError>;
+type LayoutCalculatorResult<FieldIdx, VariantIdx, F> =
+    Result<LayoutS<FieldIdx, VariantIdx>, LayoutCalculatorError<F>>;
 
 #[derive(Clone, Copy, Debug)]
 pub struct LayoutCalculator<Cx> {
@@ -100,13 +102,13 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
         'a,
         FieldIdx: Idx,
         VariantIdx: Idx,
-        F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug,
+        F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug + Copy,
     >(
         &self,
         fields: &IndexSlice<FieldIdx, F>,
         repr: &ReprOptions,
         kind: StructKind,
-    ) -> LayoutCalculatorResult<FieldIdx, VariantIdx> {
+    ) -> LayoutCalculatorResult<FieldIdx, VariantIdx, F> {
         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<Cx: HasDataLayout> LayoutCalculator<Cx> {
         'a,
         FieldIdx: Idx,
         VariantIdx: Idx,
-        F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug,
+        F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug + Copy,
     >(
         &self,
         repr: &ReprOptions,
@@ -203,7 +205,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
         discriminants: impl Iterator<Item = (VariantIdx, i128)>,
         dont_niche_optimize_enum: bool,
         always_sized: bool,
-    ) -> LayoutCalculatorResult<FieldIdx, VariantIdx> {
+    ) -> LayoutCalculatorResult<FieldIdx, VariantIdx, F> {
         let (present_first, present_second) = {
             let mut present_variants = variants
                 .iter_enumerated()
@@ -254,12 +256,12 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
         'a,
         FieldIdx: Idx,
         VariantIdx: Idx,
-        F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug,
+        F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug + Copy,
     >(
         &self,
         repr: &ReprOptions,
         variants: &IndexSlice<VariantIdx, IndexVec<FieldIdx, F>>,
-    ) -> LayoutCalculatorResult<FieldIdx, VariantIdx> {
+    ) -> LayoutCalculatorResult<FieldIdx, VariantIdx, F> {
         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<Cx: HasDataLayout> LayoutCalculator<Cx> {
         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<Cx: HasDataLayout> LayoutCalculator<Cx> {
     }
 
     /// 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<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug + Copy,
+    >(
         &self,
         repr: &ReprOptions,
         variants: &IndexSlice<VariantIdx, IndexVec<FieldIdx, F>>,
@@ -368,10 +375,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
         scalar_valid_range: (Bound<u128>, Bound<u128>),
         always_sized: bool,
         present_first: VariantIdx,
-    ) -> LayoutCalculatorResult<FieldIdx, VariantIdx>
-    where
-        F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug,
-    {
+    ) -> LayoutCalculatorResult<FieldIdx, VariantIdx, F> {
         // Struct, or univariant enum equivalent to a struct.
         // (Typechecking will reject discriminant-sizing attrs.)
 
@@ -457,17 +461,19 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
         Ok(st)
     }
 
-    fn layout_of_enum<'a, FieldIdx: Idx, VariantIdx: Idx, F>(
+    fn layout_of_enum<
+        'a,
+        FieldIdx: Idx,
+        VariantIdx: Idx,
+        F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug + Copy,
+    >(
         &self,
         repr: &ReprOptions,
         variants: &IndexSlice<VariantIdx, IndexVec<FieldIdx, F>>,
         discr_range_of_repr: impl Fn(i128, i128) -> (Integer, bool),
         discriminants: impl Iterator<Item = (VariantIdx, i128)>,
         dont_niche_optimize_enum: bool,
-    ) -> LayoutCalculatorResult<FieldIdx, VariantIdx>
-    where
-        F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug,
-    {
+    ) -> LayoutCalculatorResult<FieldIdx, VariantIdx, F> {
         // 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<Cx: HasDataLayout> LayoutCalculator<Cx> {
         'a,
         FieldIdx: Idx,
         VariantIdx: Idx,
-        F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug,
+        F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug + Copy,
     >(
         &self,
         fields: &IndexSlice<FieldIdx, F>,
         repr: &ReprOptions,
         kind: StructKind,
         niche_bias: NicheBias,
-    ) -> LayoutCalculatorResult<FieldIdx, VariantIdx> {
+    ) -> LayoutCalculatorResult<FieldIdx, VariantIdx, F> {
         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<Cx: HasDataLayout> LayoutCalculator<Cx> {
         // 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<Cx: HasDataLayout> LayoutCalculator<Cx> {
         }
         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<Cx: HasDataLayout> LayoutCalculator<Cx> {
             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<I: Idx, T> {
 
 impl<I: Idx, T> IndexSlice<I, T> {
     #[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<TyAndLayout<'tcx>>,
 ) -> &'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<FieldIdx, Layout<'_>>,
+    fields: &IndexSlice<FieldIdx, TyAndLayout<'tcx>>,
     repr: &ReprOptions,
     kind: StructKind,
 ) -> Result<LayoutS<FieldIdx, VariantIdx>, &'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<FieldIdx, Layout<'_>>, repr: &ReprOptions, kind| {
-        Ok(tcx.mk_layout(univariant_uninterned(cx, ty, fields, repr, kind)?))
-    };
+    let univariant =
+        |fields: &IndexSlice<FieldIdx, TyAndLayout<'tcx>>, 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::<IndexVec<_, _>>()?,
+                &tys.iter().map(|ty| cx.layout_of(ty)).try_collect::<IndexVec<_, _>>()?,
                 &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::<IndexVec<_, _>>()?,
+                &tys.iter().map(|ty| cx.layout_of(ty)).try_collect::<IndexVec<_, _>>()?,
                 &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::<IndexVec<_, _>>()?,
+                &tys.iter().map(|k| cx.layout_of(k)).try_collect::<IndexVec<_, _>>()?,
                 &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::<IndexVec<_, _>>()
                 })
                 .try_collect::<IndexVec<VariantIdx, _>>()?;
@@ -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::<IndexVec<_, _>>()?;
@@ -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::<IndexVec<_, _>>()?,
+                &variant_only_tys.map(|ty| cx.layout_of(ty)).try_collect::<IndexVec<_, _>>()?,
                 &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<LayoutCalculatorError> for LayoutError {
-    fn from(err: LayoutCalculatorError) -> Self {
+impl<F> From<LayoutCalculatorError<F>> for LayoutError {
+    fn from(err: LayoutCalculatorError<F>) -> Self {
         match err {
-            LayoutCalculatorError::UnexpectedUnsized | LayoutCalculatorError::EmptyUnion => {
+            LayoutCalculatorError::UnexpectedUnsized(_) | LayoutCalculatorError::EmptyUnion => {
                 LayoutError::Unknown
             }
             LayoutCalculatorError::SizeOverflow => LayoutError::SizeOverflow,