Skip to content

Commit b2ebf1c

Browse files
committed
const_eval and codegen: audit uses of is_zst
1 parent bf91321 commit b2ebf1c

File tree

12 files changed

+42
-29
lines changed

12 files changed

+42
-29
lines changed

compiler/rustc_codegen_cranelift/src/unsize.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,8 @@ fn unsize_ptr<'tcx>(
8888
let src_f = src_layout.field(fx, i);
8989
assert_eq!(src_layout.fields.offset(i).bytes(), 0);
9090
assert_eq!(dst_layout.fields.offset(i).bytes(), 0);
91-
if src_f.is_zst() {
91+
if src_f.is_1zst() {
92+
// We are looking for the one non-1-ZST field; this is not it.
9293
continue;
9394
}
9495
assert_eq!(src_layout.size, src_f.size);
@@ -151,6 +152,7 @@ pub(crate) fn coerce_unsized_into<'tcx>(
151152
let dst_f = dst.place_field(fx, FieldIdx::new(i));
152153

153154
if dst_f.layout().is_zst() {
155+
// No data here, nothing to copy/coerce.
154156
continue;
155157
}
156158

compiler/rustc_codegen_cranelift/src/vtable.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,8 @@ pub(crate) fn get_ptr_and_method_ref<'tcx>(
5151
'descend_newtypes: while !arg.layout().ty.is_unsafe_ptr() && !arg.layout().ty.is_ref() {
5252
for i in 0..arg.layout().fields.count() {
5353
let field = arg.value_field(fx, FieldIdx::new(i));
54-
if !field.layout().is_zst() {
55-
// we found the one non-zero-sized field that is allowed
54+
if !field.layout().is_1zst() {
55+
// we found the one non-1-ZST field that is allowed
5656
// now find *its* non-zero-sized field, or stop if it's a
5757
// pointer
5858
arg = field;

compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -445,9 +445,9 @@ pub fn type_di_node<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll D
445445
ty::RawPtr(ty::TypeAndMut { ty: pointee_type, .. }) | ty::Ref(_, pointee_type, _) => {
446446
build_pointer_or_reference_di_node(cx, t, pointee_type, unique_type_id)
447447
}
448-
// Box<T, A> may have a non-ZST allocator A. In that case, we
448+
// Box<T, A> may have a non-1-ZST allocator A. In that case, we
449449
// cannot treat Box<T, A> as just an owned alias of `*mut T`.
450-
ty::Adt(def, args) if def.is_box() && cx.layout_of(args.type_at(1)).is_zst() => {
450+
ty::Adt(def, args) if def.is_box() && cx.layout_of(args.type_at(1)).is_1zst() => {
451451
build_pointer_or_reference_di_node(cx, t, t.boxed_ty(), unique_type_id)
452452
}
453453
ty::FnDef(..) | ty::FnPtr(_) => build_subroutine_type_di_node(cx, unique_type_id),

compiler/rustc_codegen_ssa/src/base.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ pub fn unsize_ptr<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
202202
(src, unsized_info(bx, a, b, old_info))
203203
}
204204
(&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => {
205-
assert_eq!(def_a, def_b);
205+
assert_eq!(def_a, def_b); // implies same number of fields
206206
let src_layout = bx.cx().layout_of(src_ty);
207207
let dst_layout = bx.cx().layout_of(dst_ty);
208208
if src_ty == dst_ty {
@@ -211,7 +211,8 @@ pub fn unsize_ptr<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
211211
let mut result = None;
212212
for i in 0..src_layout.fields.count() {
213213
let src_f = src_layout.field(bx.cx(), i);
214-
if src_f.is_zst() {
214+
if src_f.is_1zst() {
215+
// We are looking for the one non-1-ZST field; this is not it.
215216
continue;
216217
}
217218

@@ -272,13 +273,14 @@ pub fn coerce_unsized_into<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
272273
}
273274

274275
(&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => {
275-
assert_eq!(def_a, def_b);
276+
assert_eq!(def_a, def_b); // implies same number of fields
276277

277278
for i in def_a.variant(FIRST_VARIANT).fields.indices() {
278279
let src_f = src.project_field(bx, i.as_usize());
279280
let dst_f = dst.project_field(bx, i.as_usize());
280281

281282
if dst_f.layout.is_zst() {
283+
// No data here, nothing to copy/coerce.
282284
continue;
283285
}
284286

compiler/rustc_codegen_ssa/src/mir/block.rs

+7-6
Original file line numberDiff line numberDiff line change
@@ -933,8 +933,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
933933
{
934934
for i in 0..op.layout.fields.count() {
935935
let field = op.extract_field(bx, i);
936-
if !field.layout.is_zst() {
937-
// we found the one non-zero-sized field that is allowed
936+
if !field.layout.is_1zst() {
937+
// we found the one non-1-ZST field that is allowed
938938
// now find *its* non-zero-sized field, or stop if it's a
939939
// pointer
940940
op = field;
@@ -975,10 +975,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
975975
{
976976
for i in 0..op.layout.fields.count() {
977977
let field = op.extract_field(bx, i);
978-
if !field.layout.is_zst() {
979-
// we found the one non-zero-sized field that is allowed
980-
// now find *its* non-zero-sized field, or stop if it's a
981-
// pointer
978+
if !field.layout.is_1zst() {
979+
// We found the one non-1-ZST field that is allowed. (The rules
980+
// for `DispatchFromDyn` ensure there's exactly one such field.)
981+
// Now find *its* non-zero-sized field, or stop if it's a
982+
// pointer.
982983
op = field;
983984
continue 'descend_newtypes;
984985
}

compiler/rustc_codegen_ssa/src/mir/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ impl<'tcx, V: CodegenObject> LocalRef<'tcx, V> {
145145
if layout.is_zst() {
146146
// Zero-size temporaries aren't always initialized, which
147147
// doesn't matter because they don't contain data, but
148-
// we need something in the operand.
148+
// we need something sufficiently aligned in the operand.
149149
LocalRef::Operand(OperandRef::zero_sized(layout))
150150
} else {
151151
LocalRef::PendingOperand

compiler/rustc_codegen_ssa/src/mir/operand.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@ pub enum OperandValue<V> {
5050
/// from [`ConstMethods::const_poison`].
5151
///
5252
/// An `OperandValue` *must* be this variant for any type for which
53-
/// `is_zst` on its `Layout` returns `true`.
53+
/// `is_zst` on its `Layout` returns `true`. Note however that
54+
/// these values can still require alignment.
5455
ZeroSized,
5556
}
5657

compiler/rustc_codegen_ssa/src/mir/place.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,8 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
114114
bx.struct_gep(ty, self.llval, 1)
115115
}
116116
Abi::Scalar(_) | Abi::ScalarPair(..) | Abi::Vector { .. } if field.is_zst() => {
117-
// ZST fields are not included in Scalar, ScalarPair, and Vector layouts, so manually offset the pointer.
117+
// ZST fields (even some that require alignment) are not included in Scalar,
118+
// ScalarPair, and Vector layouts, so manually offset the pointer.
118119
bx.gep(bx.cx().type_i8(), self.llval, &[bx.const_usize(offset.bytes())])
119120
}
120121
Abi::Scalar(_) | Abi::ScalarPair(..) => {

compiler/rustc_codegen_ssa/src/mir/rvalue.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1004,6 +1004,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
10041004
mir::Rvalue::Aggregate(..) => {
10051005
let ty = rvalue.ty(self.mir, self.cx.tcx());
10061006
let ty = self.monomorphize(ty);
1007+
// For ZST this can be `OperandValueKind::ZeroSized`.
10071008
self.cx.spanned_layout_of(ty, span).is_zst()
10081009
}
10091010
}

compiler/rustc_const_eval/src/interpret/cast.rs

+12-8
Original file line numberDiff line numberDiff line change
@@ -410,21 +410,25 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
410410
self.unsize_into_ptr(src, dest, *s, *c)
411411
}
412412
(&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => {
413-
assert_eq!(def_a, def_b);
413+
assert_eq!(def_a, def_b); // implies same number of fields
414414

415-
// unsizing of generic struct with pointer fields
416-
// Example: `Arc<T>` -> `Arc<Trait>`
417-
// here we need to increase the size of every &T thin ptr field to a fat ptr
415+
// Unsizing of generic struct with pointer fields, like `Arc<T>` -> `Arc<Trait>`.
416+
// There can be extra fields as long as they don't change their type or are 1-ZST.
417+
// There might also be no field that actually needs unsizing.
418+
let mut found_cast_field = false;
418419
for i in 0..src.layout.fields.count() {
419420
let cast_ty_field = cast_ty.field(self, i);
420-
if cast_ty_field.is_zst() {
421-
continue;
422-
}
423421
let src_field = self.project_field(src, i)?;
424422
let dst_field = self.project_field(dest, i)?;
425-
if src_field.layout.ty == cast_ty_field.ty {
423+
if src_field.layout.is_1zst() && cast_ty_field.is_1zst() {
424+
// Skip 1-ZST fields.
425+
} else if src_field.layout.ty == cast_ty_field.ty {
426426
self.copy_op(&src_field, &dst_field, /*allow_transmute*/ false)?;
427427
} else {
428+
if found_cast_field {
429+
span_bug!(self.cur_span(), "unsize_into: more than one field to cast");
430+
}
431+
found_cast_field = true;
428432
self.unsize_into(&src_field, cast_ty_field, &dst_field)?;
429433
}
430434
}

compiler/rustc_const_eval/src/interpret/operand.rs

+1
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,7 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> {
239239
// if the entire value is uninit, then so is the field (can happen in ConstProp)
240240
(Immediate::Uninit, _) => Immediate::Uninit,
241241
// the field contains no information, can be left uninit
242+
// (Scalar/ScalarPair can contain even aligned ZST, not just 1-ZST)
242243
_ if layout.is_zst() => Immediate::Uninit,
243244
// some fieldless enum variants can have non-zero size but still `Aggregate` ABI... try
244245
// to detect those here and also give them no data

compiler/rustc_const_eval/src/interpret/terminator.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -684,23 +684,23 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
684684
}
685685
_ => {
686686
// Not there yet, search for the only non-ZST field.
687+
// (The rules for `DispatchFromDyn` ensure there's exactly one such field.)
687688
let mut non_zst_field = None;
688689
for i in 0..receiver.layout.fields.count() {
689690
let field = self.project_field(&receiver, i)?;
690-
let zst =
691-
field.layout.is_zst() && field.layout.align.abi.bytes() == 1;
691+
let zst = field.layout.is_1zst();
692692
if !zst {
693693
assert!(
694694
non_zst_field.is_none(),
695-
"multiple non-ZST fields in dyn receiver type {}",
695+
"multiple non-1-ZST fields in dyn receiver type {}",
696696
receiver.layout.ty
697697
);
698698
non_zst_field = Some(field);
699699
}
700700
}
701701
receiver = non_zst_field.unwrap_or_else(|| {
702702
panic!(
703-
"no non-ZST fields in dyn receiver type {}",
703+
"no non-1-ZST fields in dyn receiver type {}",
704704
receiver.layout.ty
705705
)
706706
});

0 commit comments

Comments
 (0)