mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-30 03:57:37 +00:00

the behavior of the type system not only depends on the current assumptions, but also the currentnphase of the compiler. This is mostly necessary as we need to decide whether and how to reveal opaque types. We track this via the `TypingMode`.
74 lines
2.4 KiB
Rust
74 lines
2.4 KiB
Rust
use rustc_abi::Align;
|
|
use rustc_middle::mir::*;
|
|
use rustc_middle::ty::{self, TyCtxt};
|
|
use tracing::debug;
|
|
|
|
/// 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,
|
|
typing_env: ty::TypingEnv<'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_for_codegen(ty, typing_env);
|
|
match tcx.layout_of(typing_env.as_query_input(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()
|
|
}
|