summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_abi
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 18:31:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 18:31:44 +0000
commitc23a457e72abe608715ac76f076f47dc42af07a5 (patch)
tree2772049aaf84b5c9d0ed12ec8d86812f7a7904b6 /compiler/rustc_abi
parentReleasing progress-linux version 1.73.0+dfsg1-1~progress7.99u1. (diff)
downloadrustc-c23a457e72abe608715ac76f076f47dc42af07a5.tar.xz
rustc-c23a457e72abe608715ac76f076f47dc42af07a5.zip
Merging upstream version 1.74.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_abi')
-rw-r--r--compiler/rustc_abi/src/layout.rs25
-rw-r--r--compiler/rustc_abi/src/lib.rs53
2 files changed, 64 insertions, 14 deletions
diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs
index a8a1a9057..0706dc18f 100644
--- a/compiler/rustc_abi/src/layout.rs
+++ b/compiler/rustc_abi/src/layout.rs
@@ -157,8 +157,10 @@ pub trait LayoutCalculator {
// for non-ZST uninhabited data (mostly partial initialization).
let absent = |fields: &IndexSlice<FieldIdx, Layout<'_>>| {
let uninhabited = fields.iter().any(|f| f.abi().is_uninhabited());
- let is_zst = fields.iter().all(|f| f.0.is_zst());
- uninhabited && is_zst
+ // We cannot ignore alignment; that might lead us to entirely discard a variant and
+ // produce an enum that is less aligned than it should be!
+ let is_1zst = fields.iter().all(|f| f.0.is_1zst());
+ uninhabited && is_1zst
};
let (present_first, present_second) = {
let mut present_variants = variants
@@ -357,10 +359,8 @@ pub trait LayoutCalculator {
// It'll fit, but we need to make some adjustments.
match layout.fields {
FieldsShape::Arbitrary { ref mut offsets, .. } => {
- for (j, offset) in offsets.iter_enumerated_mut() {
- if !variants[i][j].0.is_zst() {
- *offset += this_offset;
- }
+ for offset in offsets.iter_mut() {
+ *offset += this_offset;
}
}
_ => {
@@ -504,7 +504,7 @@ pub trait LayoutCalculator {
// to make room for a larger discriminant.
for field_idx in st.fields.index_by_increasing_offset() {
let field = &field_layouts[FieldIdx::from_usize(field_idx)];
- if !field.0.is_zst() || field.align().abi.bytes() != 1 {
+ if !field.0.is_1zst() {
start_align = start_align.min(field.align().abi);
break;
}
@@ -603,12 +603,15 @@ pub trait LayoutCalculator {
abi = Abi::Scalar(tag);
} else {
// Try to use a ScalarPair for all tagged enums.
+ // That's possible only if we can find a common primitive type for all variants.
let mut common_prim = None;
let mut common_prim_initialized_in_all_variants = true;
for (field_layouts, layout_variant) in iter::zip(variants, &layout_variants) {
let FieldsShape::Arbitrary { ref offsets, .. } = layout_variant.fields else {
panic!();
};
+ // We skip *all* ZST here and later check if we are good in terms of alignment.
+ // This lets us handle some cases involving aligned ZST.
let mut fields = iter::zip(field_layouts, offsets).filter(|p| !p.0.0.is_zst());
let (field, offset) = match (fields.next(), fields.next()) {
(None, None) => {
@@ -954,9 +957,6 @@ fn univariant(
};
(
- // Place ZSTs first to avoid "interesting offsets", especially with only one
- // or two non-ZST fields. This helps Scalar/ScalarPair layouts.
- !f.0.is_zst(),
// Then place largest alignments first.
cmp::Reverse(alignment_group_key(f)),
// Then prioritize niche placement within alignment group according to
@@ -1073,9 +1073,10 @@ fn univariant(
let size = min_size.align_to(align.abi);
let mut layout_of_single_non_zst_field = None;
let mut abi = Abi::Aggregate { sized };
- // Unpack newtype ABIs and find scalar pairs.
+ // Try to make this a Scalar/ScalarPair.
if sized && size.bytes() > 0 {
- // All other fields must be ZSTs.
+ // We skip *all* ZST here and later check if we are good in terms of alignment.
+ // This lets us handle some cases involving aligned ZST.
let mut non_zst_fields = fields.iter_enumerated().filter(|&(_, f)| !f.0.is_zst());
match (non_zst_fields.next(), non_zst_fields.next(), non_zst_fields.next()) {
diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs
index 12dd1542d..b30ff058a 100644
--- a/compiler/rustc_abi/src/lib.rs
+++ b/compiler/rustc_abi/src/lib.rs
@@ -1,5 +1,5 @@
#![cfg_attr(feature = "nightly", feature(step_trait, rustc_attrs, min_specialization))]
-#![cfg_attr(all(not(bootstrap), feature = "nightly"), allow(internal_features))]
+#![cfg_attr(feature = "nightly", allow(internal_features))]
use std::fmt;
#[cfg(feature = "nightly")]
@@ -1300,12 +1300,18 @@ impl Abi {
matches!(*self, Abi::Uninhabited)
}
- /// Returns `true` is this is a scalar type
+ /// Returns `true` if this is a scalar type
#[inline]
pub fn is_scalar(&self) -> bool {
matches!(*self, Abi::Scalar(_))
}
+ /// Returns `true` if this is a bool
+ #[inline]
+ pub fn is_bool(&self) -> bool {
+ matches!(*self, Abi::Scalar(s) if s.is_bool())
+ }
+
/// Returns the fixed alignment of this ABI, if any is mandated.
pub fn inherent_align<C: HasDataLayout>(&self, cx: &C) -> Option<AbiAndPrefAlign> {
Some(match *self {
@@ -1348,6 +1354,23 @@ impl Abi {
Abi::Uninhabited | Abi::Aggregate { .. } => Abi::Aggregate { sized: true },
}
}
+
+ pub fn eq_up_to_validity(&self, other: &Self) -> bool {
+ match (self, other) {
+ // Scalar, Vector, ScalarPair have `Scalar` in them where we ignore validity ranges.
+ // We do *not* ignore the sign since it matters for some ABIs (e.g. s390x).
+ (Abi::Scalar(l), Abi::Scalar(r)) => l.primitive() == r.primitive(),
+ (
+ Abi::Vector { element: element_l, count: count_l },
+ Abi::Vector { element: element_r, count: count_r },
+ ) => element_l.primitive() == element_r.primitive() && count_l == count_r,
+ (Abi::ScalarPair(l1, l2), Abi::ScalarPair(r1, r2)) => {
+ l1.primitive() == r1.primitive() && l2.primitive() == r2.primitive()
+ }
+ // Everything else must be strictly identical.
+ _ => self == other,
+ }
+ }
}
#[derive(PartialEq, Eq, Hash, Clone, Debug)]
@@ -1660,15 +1683,25 @@ pub struct PointeeInfo {
impl LayoutS {
/// Returns `true` if the layout corresponds to an unsized type.
+ #[inline]
pub fn is_unsized(&self) -> bool {
self.abi.is_unsized()
}
+ #[inline]
pub fn is_sized(&self) -> bool {
self.abi.is_sized()
}
+ /// Returns `true` if the type is sized and a 1-ZST (meaning it has size 0 and alignment 1).
+ pub fn is_1zst(&self) -> bool {
+ self.is_sized() && self.size.bytes() == 0 && self.align.abi.bytes() == 1
+ }
+
/// Returns `true` if the type is a ZST and not unsized.
+ ///
+ /// Note that this does *not* imply that the type is irrelevant for layout! It can still have
+ /// non-trivial alignment constraints. You probably want to use `is_1zst` instead.
pub fn is_zst(&self) -> bool {
match self.abi {
Abi::Scalar(_) | Abi::ScalarPair(..) | Abi::Vector { .. } => false,
@@ -1676,6 +1709,22 @@ impl LayoutS {
Abi::Aggregate { sized } => sized && self.size.bytes() == 0,
}
}
+
+ /// Checks if these two `Layout` are equal enough to be considered "the same for all function
+ /// call ABIs". Note however that real ABIs depend on more details that are not reflected in the
+ /// `Layout`; the `PassMode` need to be compared as well.
+ pub fn eq_abi(&self, other: &Self) -> bool {
+ // The one thing that we are not capturing here is that for unsized types, the metadata must
+ // also have the same ABI, and moreover that the same metadata leads to the same size. The
+ // 2nd point is quite hard to check though.
+ self.size == other.size
+ && self.is_sized() == other.is_sized()
+ && self.abi.eq_up_to_validity(&other.abi)
+ && self.abi.is_bool() == other.abi.is_bool()
+ && self.align.abi == other.align.abi
+ && self.max_repr_align == other.max_repr_align
+ && self.unadjusted_abi_align == other.unadjusted_abi_align
+ }
}
#[derive(Copy, Clone, Debug)]