| use rustc_middle::mir::*; |
| use rustc_middle::ty::{self, TyCtxt}; |
| use rustc_target::abi::Align; |
| |
| /// Returns `true` if this place is allowed to be less aligned |
| /// than its containing struct (because it is within a packed |
| /// struct). |
| pub fn is_disaligned<'tcx, L>( |
| tcx: TyCtxt<'tcx>, |
| local_decls: &L, |
| param_env: ty::ParamEnv<'tcx>, |
| place: Place<'tcx>, |
| ) -> bool |
| where |
| L: HasLocalDecls<'tcx>, |
| { |
| debug!("is_disaligned({:?})", place); |
| let Some(pack) = is_within_packed(tcx, local_decls, place) else { |
| debug!("is_disaligned({:?}) - not within packed", place); |
| return false; |
| }; |
| |
| let ty = place.ty(local_decls, tcx).ty; |
| let unsized_tail = || tcx.struct_tail_with_normalize(ty, |ty| ty, || {}); |
| match tcx.layout_of(param_env.and(ty)) { |
| Ok(layout) |
| if layout.align.abi <= pack |
| && (layout.is_sized() |
| || matches!(unsized_tail().kind(), ty::Slice(..) | ty::Str)) => |
| { |
| // If the packed alignment is greater or equal to the field alignment, the type won't be |
| // further disaligned. |
| // However we need to ensure the field is sized; for unsized fields, `layout.align` is |
| // just an approximation -- except when the unsized tail is a slice, where the alignment |
| // is fully determined by the type. |
| debug!( |
| "is_disaligned({:?}) - align = {}, packed = {}; not disaligned", |
| place, |
| layout.align.abi.bytes(), |
| pack.bytes() |
| ); |
| false |
| } |
| _ => { |
| // We cannot figure out the layout. Conservatively assume that this is disaligned. |
| debug!("is_disaligned({:?}) - true", place); |
| true |
| } |
| } |
| } |
| |
| pub fn is_within_packed<'tcx, L>( |
| tcx: TyCtxt<'tcx>, |
| local_decls: &L, |
| place: Place<'tcx>, |
| ) -> Option<Align> |
| where |
| L: HasLocalDecls<'tcx>, |
| { |
| place |
| .iter_projections() |
| .rev() |
| // Stop at `Deref`; standard ABI alignment applies there. |
| .take_while(|(_base, elem)| !matches!(elem, ProjectionElem::Deref)) |
| // Consider the packed alignments at play here... |
| .filter_map(|(base, _elem)| { |
| base.ty(local_decls, tcx).ty.ty_adt_def().and_then(|adt| adt.repr().pack) |
| }) |
| // ... and compute their minimum. |
| // The overall smallest alignment is what matters. |
| .min() |
| } |