about summary refs log tree commit diff
path: root/compiler/rustc_const_eval/src/util/alignment.rs
diff options
context:
space:
mode:
authorCamille GILLOT <gillot.camille@gmail.com>2021-01-05 20:08:11 +0100
committerCamille GILLOT <gillot.camille@gmail.com>2021-09-07 20:46:26 +0200
commitc5fc2609f0f81698616734e22adee9b9ed67f729 (patch)
treef01d9c73942c336e3c7bbbd5e7a7621a7c230e1f /compiler/rustc_const_eval/src/util/alignment.rs
parentfd9c04fe32d3b7700d600ae1be72d5758ffd66ff (diff)
downloadrust-c5fc2609f0f81698616734e22adee9b9ed67f729.tar.gz
rust-c5fc2609f0f81698616734e22adee9b9ed67f729.zip
Rename rustc_mir to rustc_const_eval.
Diffstat (limited to 'compiler/rustc_const_eval/src/util/alignment.rs')
-rw-r--r--compiler/rustc_const_eval/src/util/alignment.rs70
1 files changed, 70 insertions, 0 deletions
diff --git a/compiler/rustc_const_eval/src/util/alignment.rs b/compiler/rustc_const_eval/src/util/alignment.rs
new file mode 100644
index 00000000000..73adc60577b
--- /dev/null
+++ b/compiler/rustc_const_eval/src/util/alignment.rs
@@ -0,0 +1,70 @@
+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 pack = match is_within_packed(tcx, local_decls, place) {
+        None => {
+            debug!("is_disaligned({:?}) - not within packed", place);
+            return false;
+        }
+        Some(pack) => pack,
+    };
+
+    let ty = place.ty(local_decls, tcx).ty;
+    match tcx.layout_of(param_env.and(ty)) {
+        Ok(layout) if layout.align.abi <= pack => {
+            // If the packed alignment is greater or equal to the field alignment, the type won't be
+            // further disaligned.
+            debug!(
+                "is_disaligned({:?}) - align = {}, packed = {}; not disaligned",
+                place,
+                layout.align.abi.bytes(),
+                pack.bytes()
+            );
+            false
+        }
+        _ => {
+            debug!("is_disaligned({:?}) - true", place);
+            true
+        }
+    }
+}
+
+fn is_within_packed<'tcx, L>(
+    tcx: TyCtxt<'tcx>,
+    local_decls: &L,
+    place: Place<'tcx>,
+) -> Option<Align>
+where
+    L: HasLocalDecls<'tcx>,
+{
+    for (place_base, elem) in place.iter_projections().rev() {
+        match elem {
+            // encountered a Deref, which is ABI-aligned
+            ProjectionElem::Deref => break,
+            ProjectionElem::Field(..) => {
+                let ty = place_base.ty(local_decls, tcx).ty;
+                match ty.kind() {
+                    ty::Adt(def, _) => return def.repr.pack,
+                    _ => {}
+                }
+            }
+            _ => {}
+        }
+    }
+
+    None
+}