Skip to content

Commit 3db930a

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

File tree

4 files changed

+64
-57
lines changed

4 files changed

+64
-57
lines changed

Diff for: compiler/rustc_abi/src/layout.rs

+34-27
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<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(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<FieldIdx, VariantIdx, F> =
56+
Result<LayoutS<FieldIdx, VariantIdx>, LayoutCalculatorError<F>>;
5557

5658
#[derive(Clone, Copy, Debug)]
5759
pub struct LayoutCalculator<Cx> {
@@ -100,13 +102,13 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
100102
'a,
101103
FieldIdx: Idx,
102104
VariantIdx: Idx,
103-
F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug,
105+
F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug + Copy,
104106
>(
105107
&self,
106108
fields: &IndexSlice<FieldIdx, F>,
107109
repr: &ReprOptions,
108110
kind: StructKind,
109-
) -> LayoutCalculatorResult<FieldIdx, VariantIdx> {
111+
) -> LayoutCalculatorResult<FieldIdx, VariantIdx, F> {
110112
let dl = self.cx.data_layout();
111113
let layout = self.univariant_biased(fields, repr, kind, NicheBias::Start);
112114
// 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> {
191193
'a,
192194
FieldIdx: Idx,
193195
VariantIdx: Idx,
194-
F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug,
196+
F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug + Copy,
195197
>(
196198
&self,
197199
repr: &ReprOptions,
@@ -203,7 +205,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
203205
discriminants: impl Iterator<Item = (VariantIdx, i128)>,
204206
dont_niche_optimize_enum: bool,
205207
always_sized: bool,
206-
) -> LayoutCalculatorResult<FieldIdx, VariantIdx> {
208+
) -> LayoutCalculatorResult<FieldIdx, VariantIdx, F> {
207209
let (present_first, present_second) = {
208210
let mut present_variants = variants
209211
.iter_enumerated()
@@ -254,12 +256,12 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
254256
'a,
255257
FieldIdx: Idx,
256258
VariantIdx: Idx,
257-
F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug,
259+
F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug + Copy,
258260
>(
259261
&self,
260262
repr: &ReprOptions,
261263
variants: &IndexSlice<VariantIdx, IndexVec<FieldIdx, F>>,
262-
) -> LayoutCalculatorResult<FieldIdx, VariantIdx> {
264+
) -> LayoutCalculatorResult<FieldIdx, VariantIdx, F> {
263265
let dl = self.cx.data_layout();
264266
let mut align = if repr.pack.is_some() { dl.i8_align } else { dl.aggregate_align };
265267
let mut max_repr_align = repr.align;
@@ -279,7 +281,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
279281
let only_variant = &variants[only_variant_idx];
280282
for field in only_variant {
281283
if field.is_unsized() {
282-
return Err(LayoutCalculatorError::UnexpectedUnsized);
284+
return Err(LayoutCalculatorError::UnexpectedUnsized(*field));
283285
}
284286

285287
align = align.max(field.align);
@@ -359,7 +361,12 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
359361
}
360362

361363
/// single-variant enums are just structs, if you think about it
362-
fn layout_of_struct<'a, FieldIdx: Idx, VariantIdx: Idx, F>(
364+
fn layout_of_struct<
365+
'a,
366+
FieldIdx: Idx,
367+
VariantIdx: Idx,
368+
F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug + Copy,
369+
>(
363370
&self,
364371
repr: &ReprOptions,
365372
variants: &IndexSlice<VariantIdx, IndexVec<FieldIdx, F>>,
@@ -368,10 +375,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
368375
scalar_valid_range: (Bound<u128>, Bound<u128>),
369376
always_sized: bool,
370377
present_first: VariantIdx,
371-
) -> LayoutCalculatorResult<FieldIdx, VariantIdx>
372-
where
373-
F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug,
374-
{
378+
) -> LayoutCalculatorResult<FieldIdx, VariantIdx, F> {
375379
// Struct, or univariant enum equivalent to a struct.
376380
// (Typechecking will reject discriminant-sizing attrs.)
377381

@@ -457,17 +461,19 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
457461
Ok(st)
458462
}
459463

460-
fn layout_of_enum<'a, FieldIdx: Idx, VariantIdx: Idx, F>(
464+
fn layout_of_enum<
465+
'a,
466+
FieldIdx: Idx,
467+
VariantIdx: Idx,
468+
F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug + Copy,
469+
>(
461470
&self,
462471
repr: &ReprOptions,
463472
variants: &IndexSlice<VariantIdx, IndexVec<FieldIdx, F>>,
464473
discr_range_of_repr: impl Fn(i128, i128) -> (Integer, bool),
465474
discriminants: impl Iterator<Item = (VariantIdx, i128)>,
466475
dont_niche_optimize_enum: bool,
467-
) -> LayoutCalculatorResult<FieldIdx, VariantIdx>
468-
where
469-
F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug,
470-
{
476+
) -> LayoutCalculatorResult<FieldIdx, VariantIdx, F> {
471477
// Until we've decided whether to use the tagged or
472478
// niche filling LayoutS, we don't want to intern the
473479
// variant layouts, so we can't store them in the
@@ -972,14 +978,14 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
972978
'a,
973979
FieldIdx: Idx,
974980
VariantIdx: Idx,
975-
F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug,
981+
F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug + Copy,
976982
>(
977983
&self,
978984
fields: &IndexSlice<FieldIdx, F>,
979985
repr: &ReprOptions,
980986
kind: StructKind,
981987
niche_bias: NicheBias,
982-
) -> LayoutCalculatorResult<FieldIdx, VariantIdx> {
988+
) -> LayoutCalculatorResult<FieldIdx, VariantIdx, F> {
983989
let dl = self.cx.data_layout();
984990
let pack = repr.pack;
985991
let mut align = if pack.is_some() { dl.i8_align } else { dl.aggregate_align };
@@ -1124,7 +1130,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
11241130
// field 5 with offset 0 puts 0 in offsets[5].
11251131
// At the bottom of this function, we invert `inverse_memory_index` to
11261132
// produce `memory_index` (see `invert_mapping`).
1127-
let mut sized = true;
1133+
let mut unsized_field = None::<&F>;
11281134
let mut offsets = IndexVec::from_elem(Size::ZERO, fields);
11291135
let mut offset = Size::ZERO;
11301136
let mut largest_niche = None;
@@ -1137,12 +1143,12 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
11371143
}
11381144
for &i in &inverse_memory_index {
11391145
let field = &fields[i];
1140-
if !sized {
1141-
return Err(LayoutCalculatorError::UnexpectedUnsized);
1146+
if let Some(unsized_field) = unsized_field {
1147+
return Err(LayoutCalculatorError::UnexpectedUnsized(*unsized_field));
11421148
}
11431149

11441150
if field.is_unsized() {
1145-
sized = false;
1151+
unsized_field = Some(field);
11461152
}
11471153

11481154
// Invariant: offset < dl.obj_size_bound() <= 1<<61
@@ -1206,6 +1212,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
12061212
return Err(LayoutCalculatorError::SizeOverflow);
12071213
}
12081214
let mut layout_of_single_non_zst_field = None;
1215+
let sized = unsized_field.is_none();
12091216
let mut abi = Abi::Aggregate { sized };
12101217

12111218
let optimize_abi = !repr.inhibit_newtype_abi_optimization();

Diff for: compiler/rustc_index/src/slice.rs

+1-1
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

Diff for: compiler/rustc_ty_utils/src/layout.rs

+26-26
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
)?;

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

+3-3
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<F> From<LayoutCalculatorError<F>> for LayoutError {
110+
fn from(err: LayoutCalculatorError<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)