Skip to content

Commit c2e4197

Browse files
committed
tighter checks for (some) ScalarPair layouts
1 parent e0d5c19 commit c2e4197

File tree

1 file changed

+102
-16
lines changed

1 file changed

+102
-16
lines changed

compiler/rustc_middle/src/ty/layout.rs

+102-16
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,11 @@ fn sanity_check_layout<'tcx>(cx: &LayoutCx<'tcx, TyCtxt<'tcx>>, layout: &TyAndLa
240240
) -> impl Iterator<Item = (Size, TyAndLayout<'tcx>)> + 'a {
241241
(0..layout.layout.fields().count()).filter_map(|i| {
242242
let field = layout.field(cx, i);
243-
let zst = field.is_zst() && field.align.abi.bytes() == 1;
243+
// Also checking `align == 1` here leads to test failures in
244+
// `layout/zero-sized-array-union.rs`, where a type has a zero-size field with
245+
// alignment 4 that still gets ignored during layout computation (which is okay
246+
// since other fields already force alignment 4).
247+
let zst = field.is_zst();
244248
(!zst).then(|| (layout.fields.offset(i), field))
245249
})
246250
}
@@ -327,38 +331,120 @@ fn sanity_check_layout<'tcx>(cx: &LayoutCx<'tcx, TyCtxt<'tcx>>, layout: &TyAndLa
327331
field.align.abi, align,
328332
"`Scalar` field with bad align in {inner:#?}",
329333
);
334+
assert!(
335+
matches!(field.abi, Abi::Scalar(_)),
336+
"`Scalar` field with bad ABI in {inner:#?}",
337+
);
330338
}
331339
_ => {
332340
panic!("`Scalar` layout for non-primitive non-enum type {}", inner.ty);
333341
}
334342
}
335343
}
336-
Abi::Vector { count, element } => {
337-
// No padding in vectors. Alignment can be strengthened, though.
338-
assert!(
339-
layout.layout.align().abi >= element.align(cx).abi,
340-
"alignment mismatch between ABI and layout in {layout:#?}"
341-
);
342-
let size = element.size(cx) * count;
343-
assert_eq!(
344-
layout.layout.size(),
345-
size.align_to(cx.data_layout().vector_align(size).abi),
346-
"size mismatch between ABI and layout in {layout:#?}"
347-
);
348-
}
349344
Abi::ScalarPair(scalar1, scalar2) => {
350345
// Sanity-check scalar pairs. These are a bit more flexible and support
351346
// padding, but we can at least ensure both fields actually fit into the layout
352347
// and the alignment requirement has not been weakened.
348+
let size1 = scalar1.size(cx);
353349
let align1 = scalar1.align(cx).abi;
350+
let size2 = scalar2.size(cx);
354351
let align2 = scalar2.align(cx).abi;
355352
assert!(
356353
layout.layout.align().abi >= cmp::max(align1, align2),
357354
"alignment mismatch between ABI and layout in {layout:#?}",
358355
);
359-
let field2_offset = scalar1.size(cx).align_to(align2);
356+
let field2_offset = size1.align_to(align2);
357+
assert!(
358+
layout.layout.size() >= field2_offset + size2,
359+
"size mismatch between ABI and layout in {layout:#?}"
360+
);
361+
// Check that the underlying pair of fields matches.
362+
let inner = skip_newtypes(cx, layout);
363+
assert!(
364+
matches!(inner.layout.abi(), Abi::ScalarPair(..)),
365+
"`ScalarPair` type {} is newtype around non-`ScalarPair` type {}",
366+
layout.ty,
367+
inner.ty
368+
);
369+
if matches!(inner.layout.variants(), Variants::Multiple { .. }) {
370+
// FIXME: ScalarPair for enums is enormously complicated and it is very hard
371+
// to check anything about them.
372+
return;
373+
}
374+
match inner.layout.fields() {
375+
FieldsShape::Arbitrary { .. } => {
376+
// Checked below.
377+
}
378+
FieldsShape::Union(..) => {
379+
// FIXME: I guess we could also check something here? Like, look at all fields?
380+
return;
381+
}
382+
_ => {
383+
panic!("`ScalarPair` layout with unexpected field shape in {inner:#?}");
384+
}
385+
}
386+
let mut fields = non_zst_fields(cx, &inner);
387+
let (offset1, field1) = fields.next().unwrap_or_else(|| {
388+
panic!("`ScalarPair` layout for type with not even one non-ZST field: {inner:#?}")
389+
});
390+
let (offset2, field2) = fields.next().unwrap_or_else(|| {
391+
panic!("`ScalarPair` layout for type with less than two non-ZST fields: {inner:#?}")
392+
});
393+
assert!(
394+
fields.next().is_none(),
395+
"`ScalarPair` layout for type with at least three non-ZST fields: {inner:#?}"
396+
);
397+
// The fields might be in opposite order.
398+
let (offset1, field1, offset2, field2) = if offset1 <= offset2 {
399+
(offset1, field1, offset2, field2)
400+
} else {
401+
(offset2, field2, offset1, field1)
402+
};
403+
// The fields should be at the right offset, and match the `scalar` layout.
404+
assert_eq!(
405+
offset1,
406+
Size::ZERO,
407+
"`ScalarPair` first field at non-0 offset in {inner:#?}",
408+
);
409+
assert_eq!(
410+
field1.size, size1,
411+
"`ScalarPair` first field with bad size in {inner:#?}",
412+
);
413+
assert_eq!(
414+
field1.align.abi, align1,
415+
"`ScalarPair` first field with bad align in {inner:#?}",
416+
);
417+
assert!(
418+
matches!(field1.abi, Abi::Scalar(_)),
419+
"`ScalarPair` first field with bad ABI in {inner:#?}",
420+
);
421+
assert_eq!(
422+
offset2, field2_offset,
423+
"`ScalarPair` second field at bad offset in {inner:#?}",
424+
);
425+
assert_eq!(
426+
field2.size, size2,
427+
"`ScalarPair` second field with bad size in {inner:#?}",
428+
);
429+
assert_eq!(
430+
field2.align.abi, align2,
431+
"`ScalarPair` second field with bad align in {inner:#?}",
432+
);
433+
assert!(
434+
matches!(field2.abi, Abi::Scalar(_)),
435+
"`ScalarPair` second field with bad ABI in {inner:#?}",
436+
);
437+
}
438+
Abi::Vector { count, element } => {
439+
// No padding in vectors. Alignment can be strengthened, though.
360440
assert!(
361-
layout.layout.size() >= field2_offset + scalar2.size(cx),
441+
layout.layout.align().abi >= element.align(cx).abi,
442+
"alignment mismatch between ABI and layout in {layout:#?}"
443+
);
444+
let size = element.size(cx) * count;
445+
assert_eq!(
446+
layout.layout.size(),
447+
size.align_to(cx.data_layout().vector_align(size).abi),
362448
"size mismatch between ABI and layout in {layout:#?}"
363449
);
364450
}

0 commit comments

Comments
 (0)