Skip to content

Commit 4b7f41a

Browse files
committed
Auto merge of #43097 - PlasmaPower:large-align, r=eddyb
Raise alignment limit from 2^15 to 2^31 - 1 Fixes #42960
2 parents 720c596 + b4973e9 commit 4b7f41a

File tree

5 files changed

+41
-21
lines changed

5 files changed

+41
-21
lines changed

src/librustc/ty/layout.rs

+15-14
Original file line numberDiff line numberDiff line change
@@ -285,11 +285,13 @@ impl Size {
285285
}
286286

287287
/// Alignment of a type in bytes, both ABI-mandated and preferred.
288-
/// Since alignments are always powers of 2, we can pack both in one byte,
289-
/// giving each a nibble (4 bits) for a maximum alignment of 2<sup>15</sup> = 32768.
288+
/// Each field is a power of two, giving the alignment a maximum
289+
/// value of 2^(2^8 - 1), which is limited by LLVM to a i32, with
290+
/// a maximum capacity of 2^31 - 1 or 2147483647.
290291
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
291292
pub struct Align {
292-
raw: u8
293+
abi: u8,
294+
pref: u8,
293295
}
294296

295297
impl Align {
@@ -298,7 +300,7 @@ impl Align {
298300
}
299301

300302
pub fn from_bytes(abi: u64, pref: u64) -> Result<Align, String> {
301-
let pack = |align: u64| {
303+
let log2 = |align: u64| {
302304
// Treat an alignment of 0 bytes like 1-byte alignment.
303305
if align == 0 {
304306
return Ok(0);
@@ -312,39 +314,38 @@ impl Align {
312314
}
313315
if bytes != 1 {
314316
Err(format!("`{}` is not a power of 2", align))
315-
} else if pow > 0x0f {
317+
} else if pow > 30 {
316318
Err(format!("`{}` is too large", align))
317319
} else {
318320
Ok(pow)
319321
}
320322
};
321323

322324
Ok(Align {
323-
raw: pack(abi)? | (pack(pref)? << 4)
325+
abi: log2(abi)?,
326+
pref: log2(pref)?,
324327
})
325328
}
326329

327330
pub fn abi(self) -> u64 {
328-
1 << (self.raw & 0xf)
331+
1 << self.abi
329332
}
330333

331334
pub fn pref(self) -> u64 {
332-
1 << (self.raw >> 4)
335+
1 << self.pref
333336
}
334337

335338
pub fn min(self, other: Align) -> Align {
336-
let abi = cmp::min(self.raw & 0x0f, other.raw & 0x0f);
337-
let pref = cmp::min(self.raw & 0xf0, other.raw & 0xf0);
338339
Align {
339-
raw: abi | pref
340+
abi: cmp::min(self.abi, other.abi),
341+
pref: cmp::min(self.pref, other.pref),
340342
}
341343
}
342344

343345
pub fn max(self, other: Align) -> Align {
344-
let abi = cmp::max(self.raw & 0x0f, other.raw & 0x0f);
345-
let pref = cmp::max(self.raw & 0xf0, other.raw & 0xf0);
346346
Align {
347-
raw: abi | pref
347+
abi: cmp::max(self.abi, other.abi),
348+
pref: cmp::max(self.pref, other.pref),
348349
}
349350
}
350351
}

src/librustc/ty/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1398,7 +1398,7 @@ impl_stable_hash_for!(struct ReprFlags {
13981398
#[derive(Copy, Clone, Eq, PartialEq, RustcEncodable, RustcDecodable, Default)]
13991399
pub struct ReprOptions {
14001400
pub int: Option<attr::IntType>,
1401-
pub align: u16,
1401+
pub align: u32,
14021402
pub flags: ReprFlags,
14031403
}
14041404

src/libsyntax/attr.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -974,11 +974,11 @@ pub fn find_repr_attrs(diagnostic: &Handler, attr: &Attribute) -> Vec<ReprAttr>
974974
let mut align_error = None;
975975
if let ast::LitKind::Int(align, ast::LitIntType::Unsuffixed) = value.node {
976976
if align.is_power_of_two() {
977-
// rustc::ty::layout::Align restricts align to <= 32768
978-
if align <= 32768 {
979-
acc.push(ReprAlign(align as u16));
977+
// rustc::ty::layout::Align restricts align to <= 2147483647
978+
if align <= 2147483647 {
979+
acc.push(ReprAlign(align as u32));
980980
} else {
981-
align_error = Some("larger than 32768");
981+
align_error = Some("larger than 2147483647");
982982
}
983983
} else {
984984
align_error = Some("not a power of two");
@@ -1027,7 +1027,7 @@ pub enum ReprAttr {
10271027
ReprExtern,
10281028
ReprPacked,
10291029
ReprSimd,
1030-
ReprAlign(u16),
1030+
ReprAlign(u32),
10311031
}
10321032

10331033
#[derive(Eq, Hash, PartialEq, Debug, RustcEncodable, RustcDecodable, Copy, Clone)]

src/test/compile-fail/repr-align.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ struct A(i32);
1717
#[repr(align(15))] //~ ERROR: invalid `repr(align)` attribute: not a power of two
1818
struct B(i32);
1919

20-
#[repr(align(65536))] //~ ERROR: invalid `repr(align)` attribute: larger than 32768
20+
#[repr(align(4294967296))] //~ ERROR: invalid `repr(align)` attribute: larger than 2147483647
2121
struct C(i32);
2222

2323
fn main() {}

src/test/run-pass/align-struct.rs

+19
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
// except according to those terms.
1010
#![feature(attr_literals)]
1111
#![feature(repr_align)]
12+
#![feature(box_syntax)]
1213

1314
use std::mem;
1415

@@ -60,6 +61,13 @@ struct AlignContainsPacked {
6061
b: Packed,
6162
}
6263

64+
// The align limit was originally smaller (2^15).
65+
// Check that it works with big numbers.
66+
#[repr(align(0x10000))]
67+
struct AlignLarge {
68+
stuff: [u8; 0x10000],
69+
}
70+
6371
impl Align16 {
6472
// return aligned type
6573
pub fn new(i: i32) -> Align16 {
@@ -193,4 +201,15 @@ pub fn main() {
193201
assert_eq!(mem::align_of_val(&a.b), 1);
194202
assert_eq!(mem::size_of_val(&a), 16);
195203
assert!(is_aligned_to(&a, 16));
204+
205+
let mut large = box AlignLarge {
206+
stuff: [0; 0x10000],
207+
};
208+
large.stuff[0] = 132;
209+
*large.stuff.last_mut().unwrap() = 102;
210+
assert_eq!(large.stuff[0], 132);
211+
assert_eq!(large.stuff.last(), Some(&102));
212+
assert_eq!(mem::align_of::<AlignLarge>(), 0x10000);
213+
assert_eq!(mem::align_of_val(&*large), 0x10000);
214+
assert!(is_aligned_to(&*large, 0x10000));
196215
}

0 commit comments

Comments
 (0)