about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorErik Desjardins <erikdesjardins@users.noreply.github.com>2024-02-27 00:09:12 -0500
committerErik Desjardins <erikdesjardins@users.noreply.github.com>2024-02-27 00:09:12 -0500
commit4dabbcb23b0dc605cdb4aa6f3499d0f053f7b600 (patch)
tree611a8d10de3f6652d48c63103a04981592bfe82d /compiler
parent71ffdf7ff7ac6df5f9f64de7e780b8345797e8a0 (diff)
downloadrust-4dabbcb23b0dc605cdb4aa6f3499d0f053f7b600.tar.gz
rust-4dabbcb23b0dc605cdb4aa6f3499d0f053f7b600.zip
allow using scalarpair with a common prim of ptr/ptr-sized-int
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_abi/src/layout.rs41
1 files changed, 35 insertions, 6 deletions
diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs
index 28e148bddb2..d023c869e8b 100644
--- a/compiler/rustc_abi/src/layout.rs
+++ b/compiler/rustc_abi/src/layout.rs
@@ -813,15 +813,44 @@ where
                     break;
                 }
             };
-            if let Some(pair) = common_prim {
-                // This is pretty conservative. We could go fancier
-                // by conflating things like i32 and u32, or even
-                // realising that (u8, u8) could just cohabit with
-                // u16 or even u32.
-                if pair != (prim, offset) {
+            if let Some((old_common_prim, common_offset)) = common_prim {
+                // All variants must be at the same offset
+                if offset != common_offset {
                     common_prim = None;
                     break;
                 }
+                // This is pretty conservative. We could go fancier
+                // by realising that (u8, u8) could just cohabit with
+                // u16 or even u32.
+                let new_common_prim = match (old_common_prim, prim) {
+                    // Allow all identical primitives.
+                    (x, y) if x == y => Some(x),
+                    // Allow integers of the same size with differing signedness.
+                    // We arbitrarily choose the signedness of the first variant.
+                    (p @ Primitive::Int(x, _), Primitive::Int(y, _)) if x == y => Some(p),
+                    // Allow integers mixed with pointers of the same layout.
+                    // We must represent this using a pointer, to avoid
+                    // roundtripping pointers through ptrtoint/inttoptr.
+                    (p @ Primitive::Pointer(_), i @ Primitive::Int(..))
+                    | (i @ Primitive::Int(..), p @ Primitive::Pointer(_))
+                        if p.size(dl) == i.size(dl) && p.align(dl) == i.align(dl) =>
+                    {
+                        Some(p)
+                    }
+                    _ => None,
+                };
+                match new_common_prim {
+                    Some(new_prim) => {
+                        // Primitives are compatible.
+                        // We may be updating the primitive here, for example from int->ptr.
+                        common_prim = Some((new_prim, common_offset));
+                    }
+                    None => {
+                        // Primitives are incompatible.
+                        common_prim = None;
+                        break;
+                    }
+                }
             } else {
                 common_prim = Some((prim, offset));
             }