diff --git a/compiler/rustc_codegen_cranelift/src/vtable.rs b/compiler/rustc_codegen_cranelift/src/vtable.rs index 7598c6eee03ff..41ea0b122de73 100644 --- a/compiler/rustc_codegen_cranelift/src/vtable.rs +++ b/compiler/rustc_codegen_cranelift/src/vtable.rs @@ -48,19 +48,12 @@ pub(crate) fn get_ptr_and_method_ref<'tcx>( ) -> (Pointer, Value) { let (ptr, vtable) = 'block: { if let Abi::Scalar(_) = arg.layout().abi { - 'descend_newtypes: while !arg.layout().ty.is_unsafe_ptr() && !arg.layout().ty.is_ref() { - for i in 0..arg.layout().fields.count() { - let field = arg.value_field(fx, FieldIdx::new(i)); - if !field.layout().is_1zst() { - // we found the one non-1-ZST field that is allowed - // now find *its* non-zero-sized field, or stop if it's a - // pointer - arg = field; - continue 'descend_newtypes; - } - } - - bug!("receiver has no non-zero-sized fields {:?}", arg); + while !arg.layout().ty.is_unsafe_ptr() && !arg.layout().ty.is_ref() { + let (idx, _) = arg + .layout() + .non_1zst_field(fx) + .expect("not exactly one non-1-ZST field in a `DispatchFromDyn` type"); + arg = arg.value_field(fx, FieldIdx::new(idx)); } } diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index d78a0c4910768..d8f6b4ed836ad 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -928,21 +928,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // we get a value of a built-in pointer type. // // This is also relevant for `Pin<&mut Self>`, where we need to peel the `Pin`. - 'descend_newtypes: while !op.layout.ty.is_unsafe_ptr() - && !op.layout.ty.is_ref() - { - for i in 0..op.layout.fields.count() { - let field = op.extract_field(bx, i); - if !field.layout.is_1zst() { - // we found the one non-1-ZST field that is allowed - // now find *its* non-zero-sized field, or stop if it's a - // pointer - op = field; - continue 'descend_newtypes; - } - } - - span_bug!(span, "receiver has no non-zero-sized fields {:?}", op); + while !op.layout.ty.is_unsafe_ptr() && !op.layout.ty.is_ref() { + let (idx, _) = op.layout.non_1zst_field(bx).expect( + "not exactly one non-1-ZST field in a `DispatchFromDyn` type", + ); + op = op.extract_field(bx, idx); } // 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> { } Immediate(_) => { // See comment above explaining why we peel these newtypes - 'descend_newtypes: while !op.layout.ty.is_unsafe_ptr() - && !op.layout.ty.is_ref() - { - for i in 0..op.layout.fields.count() { - let field = op.extract_field(bx, i); - if !field.layout.is_1zst() { - // We found the one non-1-ZST field that is allowed. (The rules - // for `DispatchFromDyn` ensure there's exactly one such field.) - // Now find *its* non-zero-sized field, or stop if it's a - // pointer. - op = field; - continue 'descend_newtypes; - } - } - - span_bug!(span, "receiver has no non-zero-sized fields {:?}", op); + while !op.layout.ty.is_unsafe_ptr() && !op.layout.ty.is_ref() { + let (idx, _) = op.layout.non_1zst_field(bx).expect( + "not exactly one non-1-ZST field in a `DispatchFromDyn` type", + ); + op = op.extract_field(bx, idx); } // Make sure that we've actually unwrapped the rcvr down diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs index 7e22981542e51..e15499bc68d0a 100644 --- a/compiler/rustc_const_eval/src/interpret/terminator.rs +++ b/compiler/rustc_const_eval/src/interpret/terminator.rs @@ -269,19 +269,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { match layout.ty.kind() { ty::Adt(adt_def, _) if adt_def.repr().transparent() && may_unfold(*adt_def) => { assert!(!adt_def.is_enum()); - // Find the non-1-ZST field. - let mut non_1zst_fields = (0..layout.fields.count()).filter_map(|idx| { - let field = layout.field(self, idx); - if field.is_1zst() { None } else { Some(field) } - }); - let first = non_1zst_fields.next().expect("`unfold_transparent` called on 1-ZST"); - assert!( - non_1zst_fields.next().is_none(), - "more than one non-1-ZST field in a transparent type" - ); - - // Found it! - self.unfold_transparent(first, may_unfold) + // Find the non-1-ZST field, and recurse. + let (_, field) = layout.non_1zst_field(self).unwrap(); + self.unfold_transparent(field, may_unfold) } // Not a transparent type, no further unfolding. _ => layout, @@ -797,25 +787,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { _ => { // Not there yet, search for the only non-ZST field. // (The rules for `DispatchFromDyn` ensure there's exactly one such field.) - let mut non_zst_field = None; - for i in 0..receiver.layout.fields.count() { - let field = self.project_field(&receiver, i)?; - let zst = field.layout.is_1zst(); - if !zst { - assert!( - non_zst_field.is_none(), - "multiple non-1-ZST fields in dyn receiver type {}", - receiver.layout.ty - ); - non_zst_field = Some(field); - } - } - receiver = non_zst_field.unwrap_or_else(|| { - panic!( - "no non-1-ZST fields in dyn receiver type {}", - receiver.layout.ty - ) - }); + let (idx, _) = receiver.layout.non_1zst_field(self).expect( + "not exactly one non-1-ZST field in a `DispatchFromDyn` type", + ); + receiver = self.project_field(&receiver, idx)?; } } }; diff --git a/compiler/rustc_target/src/abi/mod.rs b/compiler/rustc_target/src/abi/mod.rs index dd435dbb0a306..a335585dbf37c 100644 --- a/compiler/rustc_target/src/abi/mod.rs +++ b/compiler/rustc_target/src/abi/mod.rs @@ -144,4 +144,25 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { offset } + + /// Finds the one field that is not a 1-ZST. + /// Returns `None` if there are multiple non-1-ZST fields or only 1-ZST-fields. + pub fn non_1zst_field(&self, cx: &C) -> Option<(usize, Self)> + where + Ty: TyAbiInterface<'a, C> + Copy, + { + let mut found = None; + for field_idx in 0..self.fields.count() { + let field = self.field(cx, field_idx); + if field.is_1zst() { + continue; + } + if found.is_some() { + // More than one non-1-ZST field. + return None; + } + found = Some((field_idx, field)); + } + found + } } diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index 3ffe670d87ac1..16183403d67aa 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -588,19 +588,11 @@ fn make_thin_self_ptr<'tcx>( // To get the type `*mut RcBox`, we just keep unwrapping newtypes until we // get a built-in pointer type let mut fat_pointer_layout = layout; - 'descend_newtypes: while !fat_pointer_layout.ty.is_unsafe_ptr() - && !fat_pointer_layout.ty.is_ref() - { - for i in 0..fat_pointer_layout.fields.count() { - let field_layout = fat_pointer_layout.field(cx, i); - - if !field_layout.is_1zst() { - fat_pointer_layout = field_layout; - continue 'descend_newtypes; - } - } - - bug!("receiver has no non-1-ZST fields {:?}", fat_pointer_layout); + while !fat_pointer_layout.ty.is_unsafe_ptr() && !fat_pointer_layout.ty.is_ref() { + fat_pointer_layout = fat_pointer_layout + .non_1zst_field(cx) + .expect("not exactly one non-1-ZST field in a `DispatchFromDyn` type") + .1 } fat_pointer_layout.ty