about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2017-07-08 22:09:04 +0000
committerbors <bors@rust-lang.org>2017-07-08 22:09:04 +0000
commit4b7f41a22509d87a26d429185aeeaba0a2d024c5 (patch)
tree71de7278e21a82d9eb7e0521b1d7fd00ddc019e0
parent720c596ec62e8fec855c2953f21b0118ae408bdd (diff)
parentb4973e961974ac9bdd9076acbe783b0e43242256 (diff)
downloadrust-4b7f41a22509d87a26d429185aeeaba0a2d024c5.tar.gz
rust-4b7f41a22509d87a26d429185aeeaba0a2d024c5.zip
Auto merge of #43097 - PlasmaPower:large-align, r=eddyb
Raise alignment limit from 2^15 to 2^31 - 1

Fixes #42960
-rw-r--r--src/librustc/ty/layout.rs29
-rw-r--r--src/librustc/ty/mod.rs2
-rw-r--r--src/libsyntax/attr.rs10
-rw-r--r--src/test/compile-fail/repr-align.rs2
-rw-r--r--src/test/run-pass/align-struct.rs19
5 files changed, 41 insertions, 21 deletions
diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs
index 3212c6f07d1..4b8b39c1f59 100644
--- a/src/librustc/ty/layout.rs
+++ b/src/librustc/ty/layout.rs
@@ -285,11 +285,13 @@ impl Size {
 }
 
 /// Alignment of a type in bytes, both ABI-mandated and preferred.
-/// Since alignments are always powers of 2, we can pack both in one byte,
-/// giving each a nibble (4 bits) for a maximum alignment of 2<sup>15</sup> = 32768.
+/// Each field is a power of two, giving the alignment a maximum
+/// value of 2^(2^8 - 1), which is limited by LLVM to a i32, with
+/// a maximum capacity of 2^31 - 1 or 2147483647.
 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
 pub struct Align {
-    raw: u8
+    abi: u8,
+    pref: u8,
 }
 
 impl Align {
@@ -298,7 +300,7 @@ impl Align {
     }
 
     pub fn from_bytes(abi: u64, pref: u64) -> Result<Align, String> {
-        let pack = |align: u64| {
+        let log2 = |align: u64| {
             // Treat an alignment of 0 bytes like 1-byte alignment.
             if align == 0 {
                 return Ok(0);
@@ -312,7 +314,7 @@ impl Align {
             }
             if bytes != 1 {
                 Err(format!("`{}` is not a power of 2", align))
-            } else if pow > 0x0f {
+            } else if pow > 30 {
                 Err(format!("`{}` is too large", align))
             } else {
                 Ok(pow)
@@ -320,31 +322,30 @@ impl Align {
         };
 
         Ok(Align {
-            raw: pack(abi)? | (pack(pref)? << 4)
+            abi: log2(abi)?,
+            pref: log2(pref)?,
         })
     }
 
     pub fn abi(self) -> u64 {
-        1 << (self.raw & 0xf)
+        1 << self.abi
     }
 
     pub fn pref(self) -> u64 {
-        1 << (self.raw >> 4)
+        1 << self.pref
     }
 
     pub fn min(self, other: Align) -> Align {
-        let abi = cmp::min(self.raw & 0x0f, other.raw & 0x0f);
-        let pref = cmp::min(self.raw & 0xf0, other.raw & 0xf0);
         Align {
-            raw: abi | pref
+            abi: cmp::min(self.abi, other.abi),
+            pref: cmp::min(self.pref, other.pref),
         }
     }
 
     pub fn max(self, other: Align) -> Align {
-        let abi = cmp::max(self.raw & 0x0f, other.raw & 0x0f);
-        let pref = cmp::max(self.raw & 0xf0, other.raw & 0xf0);
         Align {
-            raw: abi | pref
+            abi: cmp::max(self.abi, other.abi),
+            pref: cmp::max(self.pref, other.pref),
         }
     }
 }
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 88aef53ec9d..0ce91b33c51 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -1398,7 +1398,7 @@ impl_stable_hash_for!(struct ReprFlags {
 #[derive(Copy, Clone, Eq, PartialEq, RustcEncodable, RustcDecodable, Default)]
 pub struct ReprOptions {
     pub int: Option<attr::IntType>,
-    pub align: u16,
+    pub align: u32,
     pub flags: ReprFlags,
 }
 
diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs
index f0fc849c0c5..a247fe7f8a5 100644
--- a/src/libsyntax/attr.rs
+++ b/src/libsyntax/attr.rs
@@ -974,11 +974,11 @@ pub fn find_repr_attrs(diagnostic: &Handler, attr: &Attribute) -> Vec<ReprAttr>
                         let mut align_error = None;
                         if let ast::LitKind::Int(align, ast::LitIntType::Unsuffixed) = value.node {
                             if align.is_power_of_two() {
-                                // rustc::ty::layout::Align restricts align to <= 32768
-                                if align <= 32768 {
-                                    acc.push(ReprAlign(align as u16));
+                                // rustc::ty::layout::Align restricts align to <= 2147483647
+                                if align <= 2147483647 {
+                                    acc.push(ReprAlign(align as u32));
                                 } else {
-                                    align_error = Some("larger than 32768");
+                                    align_error = Some("larger than 2147483647");
                                 }
                             } else {
                                 align_error = Some("not a power of two");
@@ -1027,7 +1027,7 @@ pub enum ReprAttr {
     ReprExtern,
     ReprPacked,
     ReprSimd,
-    ReprAlign(u16),
+    ReprAlign(u32),
 }
 
 #[derive(Eq, Hash, PartialEq, Debug, RustcEncodable, RustcDecodable, Copy, Clone)]
diff --git a/src/test/compile-fail/repr-align.rs b/src/test/compile-fail/repr-align.rs
index eb0b27fe9c0..bc9cf065e5a 100644
--- a/src/test/compile-fail/repr-align.rs
+++ b/src/test/compile-fail/repr-align.rs
@@ -17,7 +17,7 @@ struct A(i32);
 #[repr(align(15))] //~ ERROR: invalid `repr(align)` attribute: not a power of two
 struct B(i32);
 
-#[repr(align(65536))] //~ ERROR: invalid `repr(align)` attribute: larger than 32768
+#[repr(align(4294967296))] //~ ERROR: invalid `repr(align)` attribute: larger than 2147483647
 struct C(i32);
 
 fn main() {}
diff --git a/src/test/run-pass/align-struct.rs b/src/test/run-pass/align-struct.rs
index 0b9a3594502..59d05399167 100644
--- a/src/test/run-pass/align-struct.rs
+++ b/src/test/run-pass/align-struct.rs
@@ -9,6 +9,7 @@
 // except according to those terms.
 #![feature(attr_literals)]
 #![feature(repr_align)]
+#![feature(box_syntax)]
 
 use std::mem;
 
@@ -60,6 +61,13 @@ struct AlignContainsPacked {
     b: Packed,
 }
 
+// The align limit was originally smaller (2^15).
+// Check that it works with big numbers.
+#[repr(align(0x10000))]
+struct AlignLarge {
+    stuff: [u8; 0x10000],
+}
+
 impl Align16 {
     // return aligned type
     pub fn new(i: i32) -> Align16 {
@@ -193,4 +201,15 @@ pub fn main() {
     assert_eq!(mem::align_of_val(&a.b), 1);
     assert_eq!(mem::size_of_val(&a), 16);
     assert!(is_aligned_to(&a, 16));
+
+    let mut large = box AlignLarge {
+        stuff: [0; 0x10000],
+    };
+    large.stuff[0] = 132;
+    *large.stuff.last_mut().unwrap() = 102;
+    assert_eq!(large.stuff[0], 132);
+    assert_eq!(large.stuff.last(), Some(&102));
+    assert_eq!(mem::align_of::<AlignLarge>(), 0x10000);
+    assert_eq!(mem::align_of_val(&*large), 0x10000);
+    assert!(is_aligned_to(&*large, 0x10000));
 }