about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-09-20 08:43:57 +0000
committerbors <bors@rust-lang.org>2024-09-20 08:43:57 +0000
commit2b11f265b68c151909aa7f31bfe49da1d788b317 (patch)
tree197c74998f3249fb9da89998d7f2d3c3b2b38a77
parent976487c48b4fe6eda910c75a42ba23118d560fe1 (diff)
parent937b09b389d17a07cd5e246696ac091aa53e35a1 (diff)
downloadrust-2b11f265b68c151909aa7f31bfe49da1d788b317.tar.gz
rust-2b11f265b68c151909aa7f31bfe49da1d788b317.zip
Auto merge of #130508 - adwinwhite:niche-not-depend-on-order, r=the8472
Get rid of niche selection's dependence on fields's order

Fixes #125630.
Use the optimal niche selection decided in `univariant()` rather than picking niche field manually.

r? `@the8472`
-rw-r--r--compiler/rustc_abi/src/layout.rs13
-rw-r--r--src/tools/miri/tests/fail/uninit/padding-enum.rs5
-rw-r--r--src/tools/miri/tests/fail/uninit/padding-enum.stderr4
-rw-r--r--tests/ui/structs-enums/type-sizes.rs20
4 files changed, 29 insertions, 13 deletions
diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs
index f4de4e06d1b..01593d34c97 100644
--- a/compiler/rustc_abi/src/layout.rs
+++ b/compiler/rustc_abi/src/layout.rs
@@ -527,15 +527,10 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
             let count =
                 (niche_variants.end().index() as u128 - niche_variants.start().index() as u128) + 1;
 
-            // Find the field with the largest niche
-            let (field_index, niche, (niche_start, niche_scalar)) = variants[largest_variant_index]
-                .iter()
-                .enumerate()
-                .filter_map(|(j, field)| Some((j, field.largest_niche?)))
-                .max_by_key(|(_, niche)| niche.available(dl))
-                .and_then(|(j, niche)| Some((j, niche, niche.reserve(dl, count)?)))?;
-            let niche_offset =
-                niche.offset + variant_layouts[largest_variant_index].fields.offset(field_index);
+            // Use the largest niche in the largest variant.
+            let niche = variant_layouts[largest_variant_index].largest_niche?;
+            let (niche_start, niche_scalar) = niche.reserve(dl, count)?;
+            let niche_offset = niche.offset;
             let niche_size = niche.value.size(dl);
             let size = variant_layouts[largest_variant_index].size.align_to(align.abi);
 
diff --git a/src/tools/miri/tests/fail/uninit/padding-enum.rs b/src/tools/miri/tests/fail/uninit/padding-enum.rs
index a9628799b7d..e1a16bea23c 100644
--- a/src/tools/miri/tests/fail/uninit/padding-enum.rs
+++ b/src/tools/miri/tests/fail/uninit/padding-enum.rs
@@ -17,10 +17,11 @@ fn main() {
         assert!(matches!(*p.as_ptr(), E::None));
 
         // Turns out the discriminant is (currently) stored
-        // in the 2nd pointer, so the first half is padding.
+        // in the 1st pointer, so the second half is padding.
         let c = &p as *const _ as *const u8;
+        let padding_offset = mem::size_of::<&'static ()>();
         // Read a padding byte.
-        let _val = *c.add(0);
+        let _val = *c.add(padding_offset);
         //~^ERROR: uninitialized
     }
 }
diff --git a/src/tools/miri/tests/fail/uninit/padding-enum.stderr b/src/tools/miri/tests/fail/uninit/padding-enum.stderr
index 66d3092c9ba..765e7cc4e63 100644
--- a/src/tools/miri/tests/fail/uninit/padding-enum.stderr
+++ b/src/tools/miri/tests/fail/uninit/padding-enum.stderr
@@ -1,8 +1,8 @@
 error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory
   --> tests/fail/uninit/padding-enum.rs:LL:CC
    |
-LL |         let _val = *c.add(0);
-   |                    ^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
+LL |         let _val = *c.add(padding_offset);
+   |                    ^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/tests/ui/structs-enums/type-sizes.rs b/tests/ui/structs-enums/type-sizes.rs
index 5ca9c8678b7..f49ce33841a 100644
--- a/tests/ui/structs-enums/type-sizes.rs
+++ b/tests/ui/structs-enums/type-sizes.rs
@@ -209,6 +209,23 @@ struct ReorderEndNiche {
     b: MiddleNiche4,
 }
 
+// We want that the niche selection doesn't depend on order of the fields. See issue #125630.
+pub enum NicheFieldOrder1 {
+    A {
+        x: NonZero<u64>,
+        y: [NonZero<u64>; 2],
+    },
+    B([u64; 2]),
+}
+
+pub enum NicheFieldOrder2 {
+    A {
+        y: [NonZero<u64>; 2],
+        x: NonZero<u64>,
+    },
+    B([u64; 2]),
+}
+
 
 // standins for std types which we want to be laid out in a reasonable way
 struct RawVecDummy {
@@ -260,6 +277,9 @@ pub fn main() {
                size_of::<EnumWithMaybeUninhabitedVariant<()>>());
     assert_eq!(size_of::<NicheFilledEnumWithAbsentVariant>(), size_of::<&'static ()>());
 
+    assert_eq!(size_of::<NicheFieldOrder1>(), 24);
+    assert_eq!(size_of::<NicheFieldOrder2>(), 24);
+
     assert_eq!(size_of::<Option<Option<(bool, &())>>>(), size_of::<(bool, &())>());
     assert_eq!(size_of::<Option<Option<(&(), bool)>>>(), size_of::<(bool, &())>());
     assert_eq!(size_of::<Option<Option2<bool, &()>>>(), size_of::<(bool, &())>());