diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 7a625dd5932..d4748b7ef0b 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -981,7 +981,7 @@ fn check_type_defn<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'tcx>, all_sized: b // intermediate types must be sized. let needs_drop_copy = || { packed && { - let ty = tcx.type_of(variant.fields.raw.last().unwrap().did).subst_identity(); + let ty = tcx.type_of(variant.tail().did).subst_identity(); let ty = tcx.erase_regions(ty); if ty.has_infer() { tcx.sess diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index 71799387458..633933317c0 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -103,15 +103,13 @@ fn pointer_kind( Ok(match *t.kind() { ty::Slice(_) | ty::Str => Some(PointerKind::Length), ty::Dynamic(ref tty, _, ty::Dyn) => Some(PointerKind::VTable(tty.principal_def_id())), - ty::Adt(def, substs) if def.is_struct() => { - match def.non_enum_variant().fields.raw.last() { - None => Some(PointerKind::Thin), - Some(f) => { - let field_ty = self.field_ty(span, f, substs); - self.pointer_kind(field_ty, span)? - } + ty::Adt(def, substs) if def.is_struct() => match def.non_enum_variant().tail_opt() { + None => Some(PointerKind::Thin), + Some(f) => { + let field_ty = self.field_ty(span, f, substs); + self.pointer_kind(field_ty, span)? } - } + }, ty::Tuple(fields) => match fields.last() { None => Some(PointerKind::Thin), Some(&f) => self.pointer_kind(f, span)?, diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index c100c45b61a..9a28122535d 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -2028,6 +2028,22 @@ pub fn single_field(&self) -> &FieldDef { &self.fields[FieldIdx::from_u32(0)] } + + /// Returns the last field in this variant, if present. + #[inline] + pub fn tail_opt(&self) -> Option<&FieldDef> { + self.fields.raw.last() + } + + /// Returns the last field in this variant. + /// + /// # Panics + /// + /// Panics, if the variant has no fields. + #[inline] + pub fn tail(&self) -> &FieldDef { + self.tail_opt().expect("expected unsized ADT to have a tail field") + } } impl PartialEq for VariantDef { diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 720d770eed4..e2e4a2dbdc8 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -230,7 +230,7 @@ pub fn struct_tail_with_normalize( if !def.is_struct() { break; } - match def.non_enum_variant().fields.raw.last() { + match def.non_enum_variant().tail_opt() { Some(field) => { f(); ty = field.ty(self, substs); @@ -304,7 +304,7 @@ pub fn struct_lockstep_tails_with_normalize( (&ty::Adt(a_def, a_substs), &ty::Adt(b_def, b_substs)) if a_def == b_def && a_def.is_struct() => { - if let Some(f) = a_def.non_enum_variant().fields.raw.last() { + if let Some(f) = a_def.non_enum_variant().tail_opt() { a = f.ty(self, a_substs); b = f.ty(self, b_substs); } else { diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index aa690719970..e53b784a756 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -366,7 +366,7 @@ fn consider_builtin_pointee_candidate( } ty::Adt(def, substs) if def.is_struct() => { - match def.non_enum_variant().fields.raw.last() { + match def.non_enum_variant().tail_opt() { None => tcx.types.unit, Some(field_def) => { let self_ty = field_def.ty(tcx, substs); diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index 7ff47295e7c..bc6ae5471ad 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -398,12 +398,7 @@ fn consider_builtin_unsize_candidate( return Err(NoSolution); } - let tail_field = a_def - .non_enum_variant() - .fields - .raw - .last() - .expect("expected unsized ADT to have a tail field"); + let tail_field = a_def.non_enum_variant().tail(); let tail_field_ty = tcx.type_of(tail_field.did); let a_tail_ty = tail_field_ty.subst(tcx, a_substs); diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 21a223135ed..bc7dcf8e61d 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -1125,12 +1125,7 @@ fn confirm_builtin_unsize_candidate( return Err(Unimplemented); } - let tail_field = def - .non_enum_variant() - .fields - .raw - .last() - .expect("expected unsized ADT to have a tail field"); + let tail_field = def.non_enum_variant().tail(); let tail_field_ty = tcx.type_of(tail_field.did); // Extract `TailField` and `TailField` from `Struct` and `Struct`, diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index 0dbe6265522..b67cd96a734 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -480,7 +480,7 @@ fn layout_of_uncached<'tcx>( .any(|(i, v)| v.discr != ty::VariantDiscr::Relative(i.as_u32())); let maybe_unsized = def.is_struct() - && def.non_enum_variant().fields.raw.last().is_some_and(|last_field| { + && def.non_enum_variant().tail_opt().is_some_and(|last_field| { let param_env = tcx.param_env(def.did()); !tcx.type_of(last_field.did).subst_identity().is_sized(tcx, param_env) }); @@ -502,14 +502,7 @@ fn layout_of_uncached<'tcx>( // If the struct tail is sized and can be unsized, check that unsizing doesn't move the fields around. if cfg!(debug_assertions) && maybe_unsized - && def - .non_enum_variant() - .fields - .raw - .last() - .unwrap() - .ty(tcx, substs) - .is_sized(tcx, cx.param_env) + && def.non_enum_variant().tail().ty(tcx, substs).is_sized(tcx, cx.param_env) { let mut variants = variants; let tail_replacement = cx.layout_of(Ty::new_slice(tcx, tcx.types.u8)).unwrap(); diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 466616cd22b..6e5c50492c6 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -103,7 +103,7 @@ fn adt_sized_constraint(tcx: TyCtxt<'_>, def_id: DefId) -> &[Ty<'_>] { let result = tcx.mk_type_list_from_iter( def.variants() .iter() - .filter_map(|v| v.fields.raw.last()) + .filter_map(|v| v.tail_opt()) .flat_map(|f| sized_constraint_for_ty(tcx, def, tcx.type_of(f.did).subst_identity())), );