Skip to content

Commit 07b995f

Browse files
author
Lukas Markeffsky
committed
assert that unexpectedly unsized fields are sized in the param env
1 parent 6974501 commit 07b995f

File tree

4 files changed

+80
-67
lines changed

4 files changed

+80
-67
lines changed

compiler/rustc_abi/src/layout.rs

Lines changed: 50 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,14 @@ enum NicheBias {
3636
}
3737

3838
#[derive(Copy, Clone, Debug)]
39-
pub enum LayoutCalculatorError {
39+
pub enum LayoutCalculatorError<'a, F> {
4040
/// An unsized type was found in a location where a sized type was expected.
4141
///
4242
/// This is not always a compile error, for example if there is a `[T]: Sized`
4343
/// bound in a where clause.
44-
UnexpectedUnsized,
44+
///
45+
/// Contains the field that was unexpectedly unsized.
46+
UnexpectedUnsized(&'a F),
4547

4648
/// A type was too large for the target platform.
4749
SizeOverflow,
@@ -50,8 +52,8 @@ pub enum LayoutCalculatorError {
5052
EmptyUnion,
5153
}
5254

53-
type LayoutCalculatorResult<FieldIdx, VariantIdx> =
54-
Result<LayoutS<FieldIdx, VariantIdx>, LayoutCalculatorError>;
55+
type LayoutCalculatorResult<'a, FieldIdx, VariantIdx, F> =
56+
Result<LayoutS<FieldIdx, VariantIdx>, LayoutCalculatorError<'a, F>>;
5557

5658
#[derive(Clone, Copy, Debug)]
5759
pub struct LayoutCalculator<Cx> {
@@ -97,16 +99,17 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
9799
}
98100

99101
pub fn univariant<
100-
'a,
102+
'fields,
103+
'layout: 'fields,
101104
FieldIdx: Idx,
102105
VariantIdx: Idx,
103-
F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug,
106+
F: Deref<Target = &'layout LayoutS<FieldIdx, VariantIdx>> + fmt::Debug,
104107
>(
105108
&self,
106-
fields: &IndexSlice<FieldIdx, F>,
109+
fields: &'fields IndexSlice<FieldIdx, F>,
107110
repr: &ReprOptions,
108111
kind: StructKind,
109-
) -> LayoutCalculatorResult<FieldIdx, VariantIdx> {
112+
) -> LayoutCalculatorResult<'fields, FieldIdx, VariantIdx, F> {
110113
let dl = self.cx.data_layout();
111114
let layout = self.univariant_biased(fields, repr, kind, NicheBias::Start);
112115
// Enums prefer niches close to the beginning or the end of the variants so that other
@@ -188,22 +191,23 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
188191
}
189192

190193
pub fn layout_of_struct_or_enum<
191-
'a,
194+
'fields,
195+
'layout: 'fields,
192196
FieldIdx: Idx,
193197
VariantIdx: Idx,
194-
F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug,
198+
F: Deref<Target = &'layout LayoutS<FieldIdx, VariantIdx>> + fmt::Debug,
195199
>(
196200
&self,
197201
repr: &ReprOptions,
198-
variants: &IndexSlice<VariantIdx, IndexVec<FieldIdx, F>>,
202+
variants: &'fields IndexSlice<VariantIdx, IndexVec<FieldIdx, F>>,
199203
is_enum: bool,
200204
is_unsafe_cell: bool,
201205
scalar_valid_range: (Bound<u128>, Bound<u128>),
202206
discr_range_of_repr: impl Fn(i128, i128) -> (Integer, bool),
203207
discriminants: impl Iterator<Item = (VariantIdx, i128)>,
204208
dont_niche_optimize_enum: bool,
205209
always_sized: bool,
206-
) -> LayoutCalculatorResult<FieldIdx, VariantIdx> {
210+
) -> LayoutCalculatorResult<'fields, FieldIdx, VariantIdx, F> {
207211
let (present_first, present_second) = {
208212
let mut present_variants = variants
209213
.iter_enumerated()
@@ -251,15 +255,16 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
251255
}
252256

253257
pub fn layout_of_union<
254-
'a,
258+
'fields,
259+
'layout: 'fields,
255260
FieldIdx: Idx,
256261
VariantIdx: Idx,
257-
F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug,
262+
F: Deref<Target = &'layout LayoutS<FieldIdx, VariantIdx>> + fmt::Debug + Clone,
258263
>(
259264
&self,
260265
repr: &ReprOptions,
261-
variants: &IndexSlice<VariantIdx, IndexVec<FieldIdx, F>>,
262-
) -> LayoutCalculatorResult<FieldIdx, VariantIdx> {
266+
variants: &'fields IndexSlice<VariantIdx, IndexVec<FieldIdx, F>>,
267+
) -> LayoutCalculatorResult<'fields, FieldIdx, VariantIdx, F> {
263268
let dl = self.cx.data_layout();
264269
let mut align = if repr.pack.is_some() { dl.i8_align } else { dl.aggregate_align };
265270
let mut max_repr_align = repr.align;
@@ -279,7 +284,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
279284
let only_variant = &variants[only_variant_idx];
280285
for field in only_variant {
281286
if field.is_unsized() {
282-
return Err(LayoutCalculatorError::UnexpectedUnsized);
287+
return Err(LayoutCalculatorError::UnexpectedUnsized(field));
283288
}
284289

285290
align = align.max(field.align);
@@ -359,19 +364,22 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
359364
}
360365

361366
/// single-variant enums are just structs, if you think about it
362-
fn layout_of_struct<'a, FieldIdx: Idx, VariantIdx: Idx, F>(
367+
fn layout_of_struct<
368+
'fields,
369+
'layout: 'fields,
370+
FieldIdx: Idx,
371+
VariantIdx: Idx,
372+
F: Deref<Target = &'layout LayoutS<FieldIdx, VariantIdx>> + fmt::Debug,
373+
>(
363374
&self,
364375
repr: &ReprOptions,
365-
variants: &IndexSlice<VariantIdx, IndexVec<FieldIdx, F>>,
376+
variants: &'fields IndexSlice<VariantIdx, IndexVec<FieldIdx, F>>,
366377
is_enum: bool,
367378
is_unsafe_cell: bool,
368379
scalar_valid_range: (Bound<u128>, Bound<u128>),
369380
always_sized: bool,
370381
present_first: VariantIdx,
371-
) -> LayoutCalculatorResult<FieldIdx, VariantIdx>
372-
where
373-
F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug,
374-
{
382+
) -> LayoutCalculatorResult<'fields, FieldIdx, VariantIdx, F> {
375383
// Struct, or univariant enum equivalent to a struct.
376384
// (Typechecking will reject discriminant-sizing attrs.)
377385

@@ -457,17 +465,20 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
457465
Ok(st)
458466
}
459467

460-
fn layout_of_enum<'a, FieldIdx: Idx, VariantIdx: Idx, F>(
468+
fn layout_of_enum<
469+
'fields,
470+
'layout: 'fields,
471+
FieldIdx: Idx,
472+
VariantIdx: Idx,
473+
F: Deref<Target = &'layout LayoutS<FieldIdx, VariantIdx>> + fmt::Debug,
474+
>(
461475
&self,
462476
repr: &ReprOptions,
463-
variants: &IndexSlice<VariantIdx, IndexVec<FieldIdx, F>>,
477+
variants: &'fields IndexSlice<VariantIdx, IndexVec<FieldIdx, F>>,
464478
discr_range_of_repr: impl Fn(i128, i128) -> (Integer, bool),
465479
discriminants: impl Iterator<Item = (VariantIdx, i128)>,
466480
dont_niche_optimize_enum: bool,
467-
) -> LayoutCalculatorResult<FieldIdx, VariantIdx>
468-
where
469-
F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug,
470-
{
481+
) -> LayoutCalculatorResult<'fields, FieldIdx, VariantIdx, F> {
471482
// Until we've decided whether to use the tagged or
472483
// niche filling LayoutS, we don't want to intern the
473484
// variant layouts, so we can't store them in the
@@ -969,17 +980,18 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
969980
}
970981

971982
fn univariant_biased<
972-
'a,
983+
'fields,
984+
'layout: 'fields,
973985
FieldIdx: Idx,
974986
VariantIdx: Idx,
975-
F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug,
987+
F: Deref<Target = &'layout LayoutS<FieldIdx, VariantIdx>> + fmt::Debug,
976988
>(
977989
&self,
978-
fields: &IndexSlice<FieldIdx, F>,
990+
fields: &'fields IndexSlice<FieldIdx, F>,
979991
repr: &ReprOptions,
980992
kind: StructKind,
981993
niche_bias: NicheBias,
982-
) -> LayoutCalculatorResult<FieldIdx, VariantIdx> {
994+
) -> LayoutCalculatorResult<'fields, FieldIdx, VariantIdx, F> {
983995
let dl = self.cx.data_layout();
984996
let pack = repr.pack;
985997
let mut align = if pack.is_some() { dl.i8_align } else { dl.aggregate_align };
@@ -1124,7 +1136,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
11241136
// field 5 with offset 0 puts 0 in offsets[5].
11251137
// At the bottom of this function, we invert `inverse_memory_index` to
11261138
// produce `memory_index` (see `invert_mapping`).
1127-
let mut sized = true;
1139+
let mut unsized_field = None;
11281140
let mut offsets = IndexVec::from_elem(Size::ZERO, fields);
11291141
let mut offset = Size::ZERO;
11301142
let mut largest_niche = None;
@@ -1137,12 +1149,12 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
11371149
}
11381150
for &i in &inverse_memory_index {
11391151
let field = &fields[i];
1140-
if !sized {
1141-
return Err(LayoutCalculatorError::UnexpectedUnsized);
1152+
if let Some(unsized_field) = unsized_field {
1153+
return Err(LayoutCalculatorError::UnexpectedUnsized(unsized_field));
11421154
}
11431155

11441156
if field.is_unsized() {
1145-
sized = false;
1157+
unsized_field = Some(field);
11461158
}
11471159

11481160
// Invariant: offset < dl.obj_size_bound() <= 1<<61
@@ -1206,6 +1218,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
12061218
return Err(LayoutCalculatorError::SizeOverflow);
12071219
}
12081220
let mut layout_of_single_non_zst_field = None;
1221+
let sized = unsized_field.is_none();
12091222
let mut abi = Abi::Aggregate { sized };
12101223

12111224
let optimize_abi = !repr.inhibit_newtype_abi_optimization();

compiler/rustc_index/src/slice.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ pub struct IndexSlice<I: Idx, T> {
2020

2121
impl<I: Idx, T> IndexSlice<I, T> {
2222
#[inline]
23-
pub const fn empty() -> &'static Self {
23+
pub const fn empty<'a>() -> &'a Self {
2424
Self::from_raw(&[])
2525
}
2626

compiler/rustc_ty_utils/src/layout.rs

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -86,19 +86,21 @@ fn error<'tcx>(cx: &LayoutCx<'tcx>, err: LayoutError<'tcx>) -> &'tcx LayoutError
8686
fn map_error<'tcx>(
8787
cx: &LayoutCx<'tcx>,
8888
ty: Ty<'tcx>,
89-
err: LayoutCalculatorError,
89+
err: LayoutCalculatorError<'_, TyAndLayout<'tcx>>,
9090
) -> &'tcx LayoutError<'tcx> {
9191
let err = match err {
9292
LayoutCalculatorError::SizeOverflow => {
9393
// This is sometimes not a compile error in `check` builds.
94+
// See `tests/ui/limits/huge-enum.rs` for an example.
9495
LayoutError::SizeOverflow(ty)
9596
}
96-
LayoutCalculatorError::UnexpectedUnsized => {
97-
// This is sometimes not a compile error if there are trivially false where
98-
// clauses, but it is always a compiler error in the empty environment.
99-
if cx.param_env.caller_bounds().is_empty() {
97+
LayoutCalculatorError::UnexpectedUnsized(field) => {
98+
// This is sometimes not a compile error if there are trivially false where clauses.
99+
// See `tests/ui/layout/trivial-bounds-sized.rs` for an example.
100+
assert!(field.layout.is_unsized(), "invalid layout error {err:#?}");
101+
if !field.ty.is_sized(cx.tcx(), cx.param_env) {
100102
cx.tcx().dcx().delayed_bug(format!(
101-
"encountered unexpected unsized field in layout of {ty:?}"
103+
"encountered unexpected unsized field in layout of {ty:?}: {field:#?}"
102104
));
103105
}
104106
LayoutError::Unknown(ty)
@@ -115,7 +117,7 @@ fn map_error<'tcx>(
115117
fn univariant_uninterned<'tcx>(
116118
cx: &LayoutCx<'tcx>,
117119
ty: Ty<'tcx>,
118-
fields: &IndexSlice<FieldIdx, Layout<'_>>,
120+
fields: &IndexSlice<FieldIdx, TyAndLayout<'tcx>>,
119121
repr: &ReprOptions,
120122
kind: StructKind,
121123
) -> Result<LayoutS<FieldIdx, VariantIdx>, &'tcx LayoutError<'tcx>> {
@@ -148,9 +150,10 @@ fn layout_of_uncached<'tcx>(
148150
};
149151
let scalar = |value: Primitive| tcx.mk_layout(LayoutS::scalar(cx, scalar_unit(value)));
150152

151-
let univariant = |fields: &IndexSlice<FieldIdx, Layout<'_>>, repr: &ReprOptions, kind| {
152-
Ok(tcx.mk_layout(univariant_uninterned(cx, ty, fields, repr, kind)?))
153-
};
153+
let univariant =
154+
|fields: &IndexSlice<FieldIdx, TyAndLayout<'tcx>>, repr: &ReprOptions, kind| {
155+
Ok(tcx.mk_layout(univariant_uninterned(cx, ty, fields, repr, kind)?))
156+
};
154157
debug_assert!(!ty.has_non_region_infer());
155158

156159
Ok(match *ty.kind() {
@@ -388,9 +391,7 @@ fn layout_of_uncached<'tcx>(
388391
ty::Closure(_, args) => {
389392
let tys = args.as_closure().upvar_tys();
390393
univariant(
391-
&tys.iter()
392-
.map(|ty| Ok(cx.layout_of(ty)?.layout))
393-
.try_collect::<IndexVec<_, _>>()?,
394+
&tys.iter().map(|ty| cx.layout_of(ty)).try_collect::<IndexVec<_, _>>()?,
394395
&ReprOptions::default(),
395396
StructKind::AlwaysSized,
396397
)?
@@ -399,9 +400,7 @@ fn layout_of_uncached<'tcx>(
399400
ty::CoroutineClosure(_, args) => {
400401
let tys = args.as_coroutine_closure().upvar_tys();
401402
univariant(
402-
&tys.iter()
403-
.map(|ty| Ok(cx.layout_of(ty)?.layout))
404-
.try_collect::<IndexVec<_, _>>()?,
403+
&tys.iter().map(|ty| cx.layout_of(ty)).try_collect::<IndexVec<_, _>>()?,
405404
&ReprOptions::default(),
406405
StructKind::AlwaysSized,
407406
)?
@@ -412,7 +411,7 @@ fn layout_of_uncached<'tcx>(
412411
if tys.len() == 0 { StructKind::AlwaysSized } else { StructKind::MaybeUnsized };
413412

414413
univariant(
415-
&tys.iter().map(|k| Ok(cx.layout_of(k)?.layout)).try_collect::<IndexVec<_, _>>()?,
414+
&tys.iter().map(|k| cx.layout_of(k)).try_collect::<IndexVec<_, _>>()?,
416415
&ReprOptions::default(),
417416
kind,
418417
)?
@@ -552,7 +551,7 @@ fn layout_of_uncached<'tcx>(
552551
.map(|v| {
553552
v.fields
554553
.iter()
555-
.map(|field| Ok(cx.layout_of(field.ty(tcx, args))?.layout))
554+
.map(|field| cx.layout_of(field.ty(tcx, args)))
556555
.try_collect::<IndexVec<_, _>>()
557556
})
558557
.try_collect::<IndexVec<VariantIdx, _>>()?;
@@ -651,7 +650,7 @@ fn layout_of_uncached<'tcx>(
651650
{
652651
let mut variants = variants;
653652
let tail_replacement = cx.layout_of(Ty::new_slice(tcx, tcx.types.u8)).unwrap();
654-
*variants[FIRST_VARIANT].raw.last_mut().unwrap() = tail_replacement.layout;
653+
*variants[FIRST_VARIANT].raw.last_mut().unwrap() = tail_replacement;
655654

656655
let Ok(unsized_layout) = cx.calc.layout_of_struct_or_enum(
657656
&def.repr(),
@@ -859,21 +858,24 @@ fn coroutine_layout<'tcx>(
859858
let max_discr = (info.variant_fields.len() - 1) as u128;
860859
let discr_int = Integer::fit_unsigned(max_discr);
861860
let tag = Scalar::Initialized {
862-
value: Primitive::Int(discr_int, false),
861+
value: Primitive::Int(discr_int, /* signed = */ false),
863862
valid_range: WrappingRange { start: 0, end: max_discr },
864863
};
865-
let tag_layout = tcx.mk_layout(LayoutS::scalar(cx, tag));
864+
let tag_layout = TyAndLayout {
865+
ty: discr_int.to_ty(tcx, /* signed = */ false),
866+
layout: tcx.mk_layout(LayoutS::scalar(cx, tag)),
867+
};
866868

867869
let promoted_layouts = ineligible_locals.iter().map(|local| {
868870
let field_ty = instantiate_field(info.field_tys[local].ty);
869871
let uninit_ty = Ty::new_maybe_uninit(tcx, field_ty);
870-
Ok(cx.spanned_layout_of(uninit_ty, info.field_tys[local].source_info.span)?.layout)
872+
cx.spanned_layout_of(uninit_ty, info.field_tys[local].source_info.span)
871873
});
872874
let prefix_layouts = args
873875
.as_coroutine()
874876
.prefix_tys()
875877
.iter()
876-
.map(|ty| Ok(cx.layout_of(ty)?.layout))
878+
.map(|ty| cx.layout_of(ty))
877879
.chain(iter::once(Ok(tag_layout)))
878880
.chain(promoted_layouts)
879881
.try_collect::<IndexVec<_, _>>()?;
@@ -947,9 +949,7 @@ fn coroutine_layout<'tcx>(
947949
let mut variant = univariant_uninterned(
948950
cx,
949951
ty,
950-
&variant_only_tys
951-
.map(|ty| Ok(cx.layout_of(ty)?.layout))
952-
.try_collect::<IndexVec<_, _>>()?,
952+
&variant_only_tys.map(|ty| cx.layout_of(ty)).try_collect::<IndexVec<_, _>>()?,
953953
&ReprOptions::default(),
954954
StructKind::Prefixed(prefix_size, prefix_align.abi),
955955
)?;

src/tools/rust-analyzer/crates/hir-ty/src/layout.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -106,10 +106,10 @@ impl fmt::Display for LayoutError {
106106
}
107107
}
108108

109-
impl From<LayoutCalculatorError> for LayoutError {
110-
fn from(err: LayoutCalculatorError) -> Self {
109+
impl<'a, F> From<LayoutCalculatorError<'a, F>> for LayoutError {
110+
fn from(err: LayoutCalculatorError<'a, F>) -> Self {
111111
match err {
112-
LayoutCalculatorError::UnexpectedUnsized | LayoutCalculatorError::EmptyUnion => {
112+
LayoutCalculatorError::UnexpectedUnsized(_) | LayoutCalculatorError::EmptyUnion => {
113113
LayoutError::Unknown
114114
}
115115
LayoutCalculatorError::SizeOverflow => LayoutError::SizeOverflow,

0 commit comments

Comments
 (0)