Skip to content

Commit 565b9c2

Browse files
authored
Rollup merge of #115798 - RalfJung:non_1zst_field, r=wesleywiser
add helper method for finding the one non-1-ZST field
2 parents 1ec29fb + 60091fe commit 565b9c2

File tree

5 files changed

+49
-89
lines changed

5 files changed

+49
-89
lines changed

compiler/rustc_codegen_cranelift/src/vtable.rs

+6-13
Original file line numberDiff line numberDiff line change
@@ -48,19 +48,12 @@ pub(crate) fn get_ptr_and_method_ref<'tcx>(
4848
) -> (Pointer, Value) {
4949
let (ptr, vtable) = 'block: {
5050
if let Abi::Scalar(_) = arg.layout().abi {
51-
'descend_newtypes: while !arg.layout().ty.is_unsafe_ptr() && !arg.layout().ty.is_ref() {
52-
for i in 0..arg.layout().fields.count() {
53-
let field = arg.value_field(fx, FieldIdx::new(i));
54-
if !field.layout().is_1zst() {
55-
// we found the one non-1-ZST field that is allowed
56-
// now find *its* non-zero-sized field, or stop if it's a
57-
// pointer
58-
arg = field;
59-
continue 'descend_newtypes;
60-
}
61-
}
62-
63-
bug!("receiver has no non-zero-sized fields {:?}", arg);
51+
while !arg.layout().ty.is_unsafe_ptr() && !arg.layout().ty.is_ref() {
52+
let (idx, _) = arg
53+
.layout()
54+
.non_1zst_field(fx)
55+
.expect("not exactly one non-1-ZST field in a `DispatchFromDyn` type");
56+
arg = arg.value_field(fx, FieldIdx::new(idx));
6457
}
6558
}
6659

compiler/rustc_codegen_ssa/src/mir/block.rs

+10-31
Original file line numberDiff line numberDiff line change
@@ -928,21 +928,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
928928
// we get a value of a built-in pointer type.
929929
//
930930
// This is also relevant for `Pin<&mut Self>`, where we need to peel the `Pin`.
931-
'descend_newtypes: while !op.layout.ty.is_unsafe_ptr()
932-
&& !op.layout.ty.is_ref()
933-
{
934-
for i in 0..op.layout.fields.count() {
935-
let field = op.extract_field(bx, i);
936-
if !field.layout.is_1zst() {
937-
// we found the one non-1-ZST field that is allowed
938-
// now find *its* non-zero-sized field, or stop if it's a
939-
// pointer
940-
op = field;
941-
continue 'descend_newtypes;
942-
}
943-
}
944-
945-
span_bug!(span, "receiver has no non-zero-sized fields {:?}", op);
931+
while !op.layout.ty.is_unsafe_ptr() && !op.layout.ty.is_ref() {
932+
let (idx, _) = op.layout.non_1zst_field(bx).expect(
933+
"not exactly one non-1-ZST field in a `DispatchFromDyn` type",
934+
);
935+
op = op.extract_field(bx, idx);
946936
}
947937

948938
// now that we have `*dyn Trait` or `&dyn Trait`, split it up into its
@@ -970,22 +960,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
970960
}
971961
Immediate(_) => {
972962
// See comment above explaining why we peel these newtypes
973-
'descend_newtypes: while !op.layout.ty.is_unsafe_ptr()
974-
&& !op.layout.ty.is_ref()
975-
{
976-
for i in 0..op.layout.fields.count() {
977-
let field = op.extract_field(bx, i);
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.
983-
op = field;
984-
continue 'descend_newtypes;
985-
}
986-
}
987-
988-
span_bug!(span, "receiver has no non-zero-sized fields {:?}", op);
963+
while !op.layout.ty.is_unsafe_ptr() && !op.layout.ty.is_ref() {
964+
let (idx, _) = op.layout.non_1zst_field(bx).expect(
965+
"not exactly one non-1-ZST field in a `DispatchFromDyn` type",
966+
);
967+
op = op.extract_field(bx, idx);
989968
}
990969

991970
// Make sure that we've actually unwrapped the rcvr down

compiler/rustc_const_eval/src/interpret/terminator.rs

+7-32
Original file line numberDiff line numberDiff line change
@@ -269,19 +269,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
269269
match layout.ty.kind() {
270270
ty::Adt(adt_def, _) if adt_def.repr().transparent() && may_unfold(*adt_def) => {
271271
assert!(!adt_def.is_enum());
272-
// Find the non-1-ZST field.
273-
let mut non_1zst_fields = (0..layout.fields.count()).filter_map(|idx| {
274-
let field = layout.field(self, idx);
275-
if field.is_1zst() { None } else { Some(field) }
276-
});
277-
let first = non_1zst_fields.next().expect("`unfold_transparent` called on 1-ZST");
278-
assert!(
279-
non_1zst_fields.next().is_none(),
280-
"more than one non-1-ZST field in a transparent type"
281-
);
282-
283-
// Found it!
284-
self.unfold_transparent(first, may_unfold)
272+
// Find the non-1-ZST field, and recurse.
273+
let (_, field) = layout.non_1zst_field(self).unwrap();
274+
self.unfold_transparent(field, may_unfold)
285275
}
286276
// Not a transparent type, no further unfolding.
287277
_ => layout,
@@ -797,25 +787,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
797787
_ => {
798788
// Not there yet, search for the only non-ZST field.
799789
// (The rules for `DispatchFromDyn` ensure there's exactly one such field.)
800-
let mut non_zst_field = None;
801-
for i in 0..receiver.layout.fields.count() {
802-
let field = self.project_field(&receiver, i)?;
803-
let zst = field.layout.is_1zst();
804-
if !zst {
805-
assert!(
806-
non_zst_field.is_none(),
807-
"multiple non-1-ZST fields in dyn receiver type {}",
808-
receiver.layout.ty
809-
);
810-
non_zst_field = Some(field);
811-
}
812-
}
813-
receiver = non_zst_field.unwrap_or_else(|| {
814-
panic!(
815-
"no non-1-ZST fields in dyn receiver type {}",
816-
receiver.layout.ty
817-
)
818-
});
790+
let (idx, _) = receiver.layout.non_1zst_field(self).expect(
791+
"not exactly one non-1-ZST field in a `DispatchFromDyn` type",
792+
);
793+
receiver = self.project_field(&receiver, idx)?;
819794
}
820795
}
821796
};

compiler/rustc_target/src/abi/mod.rs

+21
Original file line numberDiff line numberDiff line change
@@ -144,4 +144,25 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
144144

145145
offset
146146
}
147+
148+
/// Finds the one field that is not a 1-ZST.
149+
/// Returns `None` if there are multiple non-1-ZST fields or only 1-ZST-fields.
150+
pub fn non_1zst_field<C>(&self, cx: &C) -> Option<(usize, Self)>
151+
where
152+
Ty: TyAbiInterface<'a, C> + Copy,
153+
{
154+
let mut found = None;
155+
for field_idx in 0..self.fields.count() {
156+
let field = self.field(cx, field_idx);
157+
if field.is_1zst() {
158+
continue;
159+
}
160+
if found.is_some() {
161+
// More than one non-1-ZST field.
162+
return None;
163+
}
164+
found = Some((field_idx, field));
165+
}
166+
found
167+
}
147168
}

compiler/rustc_ty_utils/src/abi.rs

+5-13
Original file line numberDiff line numberDiff line change
@@ -588,19 +588,11 @@ fn make_thin_self_ptr<'tcx>(
588588
// To get the type `*mut RcBox<Self>`, we just keep unwrapping newtypes until we
589589
// get a built-in pointer type
590590
let mut fat_pointer_layout = layout;
591-
'descend_newtypes: while !fat_pointer_layout.ty.is_unsafe_ptr()
592-
&& !fat_pointer_layout.ty.is_ref()
593-
{
594-
for i in 0..fat_pointer_layout.fields.count() {
595-
let field_layout = fat_pointer_layout.field(cx, i);
596-
597-
if !field_layout.is_1zst() {
598-
fat_pointer_layout = field_layout;
599-
continue 'descend_newtypes;
600-
}
601-
}
602-
603-
bug!("receiver has no non-1-ZST fields {:?}", fat_pointer_layout);
591+
while !fat_pointer_layout.ty.is_unsafe_ptr() && !fat_pointer_layout.ty.is_ref() {
592+
fat_pointer_layout = fat_pointer_layout
593+
.non_1zst_field(cx)
594+
.expect("not exactly one non-1-ZST field in a `DispatchFromDyn` type")
595+
.1
604596
}
605597

606598
fat_pointer_layout.ty

0 commit comments

Comments
 (0)