Skip to content

Commit 631a162

Browse files
committed
Auto merge of #57998 - niklasf:align-enum, r=nagisa
Allow #[repr(align(x))] on enums (#57996) Tracking issue: #57996 Implements an extension of [RFC 1358](https://github.com/rust-lang/rfcs/blob/master/text/1358-repr-align.md) behind a feature flag (`repr_align_enum`). Originally introduced here for structs: #39999. It seems like only HIR-level changes are required, since enums are already aware of their alignment (due to alignment of their limbs). cc @bitshifter
2 parents b139669 + a6fd6ec commit 631a162

File tree

11 files changed

+191
-28
lines changed

11 files changed

+191
-28
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# `repr_align_enum`
2+
3+
The tracking issue for this feature is: [#57996]
4+
5+
[#57996]: https://github.com/rust-lang/rust/issues/57996
6+
7+
------------------------
8+
9+
The `repr_align_enum` feature allows using the `#[repr(align(x))]` attribute
10+
on enums, similarly to structs.
11+
12+
# Examples
13+
14+
```rust
15+
#![feature(repr_align_enum)]
16+
17+
#[repr(align(8))]
18+
enum Aligned {
19+
Foo,
20+
Bar { value: u32 },
21+
}
22+
23+
fn main() {
24+
assert_eq!(std::mem::align_of::<Aligned>(), 8);
25+
}
26+
```
27+
28+
This is equivalent to using an aligned wrapper struct everywhere:
29+
30+
```rust
31+
#[repr(align(8))]
32+
struct Aligned(Unaligned);
33+
34+
enum Unaligned {
35+
Foo,
36+
Bar { value: u32 },
37+
}
38+
39+
fn main() {
40+
assert_eq!(std::mem::align_of::<Aligned>(), 8);
41+
}
42+
```

src/librustc/hir/check_attr.rs

+2-10
Original file line numberDiff line numberDiff line change
@@ -186,8 +186,8 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> {
186186
};
187187

188188
let (article, allowed_targets) = match &*name.as_str() {
189-
"C" => {
190-
is_c = true;
189+
"C" | "align" => {
190+
is_c |= name == "C";
191191
if target != Target::Struct &&
192192
target != Target::Union &&
193193
target != Target::Enum {
@@ -212,14 +212,6 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> {
212212
continue
213213
}
214214
}
215-
"align" => {
216-
if target != Target::Struct &&
217-
target != Target::Union {
218-
("a", "struct or union")
219-
} else {
220-
continue
221-
}
222-
}
223215
"transparent" => {
224216
is_transparent = true;
225217
if target != Target::Struct {

src/libsyntax/feature_gate.rs

+14
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,9 @@ declare_features! (
462462

463463
// #[optimize(X)]
464464
(active, optimize_attribute, "1.34.0", Some(54882), None),
465+
466+
// #[repr(align(X))] on enums
467+
(active, repr_align_enum, "1.34.0", Some(57996), None),
465468
);
466469

467470
declare_features! (
@@ -1698,6 +1701,17 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
16981701
}
16991702
}
17001703

1704+
ast::ItemKind::Enum(..) => {
1705+
for attr in attr::filter_by_name(&i.attrs[..], "repr") {
1706+
for item in attr.meta_item_list().unwrap_or_else(Vec::new) {
1707+
if item.check_name("align") {
1708+
gate_feature_post!(&self, repr_align_enum, attr.span,
1709+
"`#[repr(align(x))]` on enums is experimental");
1710+
}
1711+
}
1712+
}
1713+
}
1714+
17011715
ast::ItemKind::Impl(_, polarity, defaultness, _, _, _, _) => {
17021716
if polarity == ast::ImplPolarity::Negative {
17031717
gate_feature_post!(&self, optin_builtin_traits,

src/test/codegen/align-enum.rs

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// compile-flags: -C no-prepopulate-passes
2+
// ignore-tidy-linelength
3+
// min-llvm-version 7.0
4+
5+
#![crate_type = "lib"]
6+
#![feature(repr_align_enum)]
7+
8+
#[repr(align(64))]
9+
pub enum Align64 {
10+
A(u32),
11+
B(u32),
12+
}
13+
// CHECK: %Align64 = type { [0 x i32], i32, [15 x i32] }
14+
15+
pub struct Nested64 {
16+
a: u8,
17+
b: Align64,
18+
c: u16,
19+
}
20+
21+
// CHECK-LABEL: @align64
22+
#[no_mangle]
23+
pub fn align64(a: u32) -> Align64 {
24+
// CHECK: %a64 = alloca %Align64, align 64
25+
// CHECK: call void @llvm.memcpy.{{.*}}(i8* align 64 %{{.*}}, i8* align 64 %{{.*}}, i{{[0-9]+}} 64, i1 false)
26+
let a64 = Align64::A(a);
27+
a64
28+
}
29+
30+
// CHECK-LABEL: @nested64
31+
#[no_mangle]
32+
pub fn nested64(a: u8, b: u32, c: u16) -> Nested64 {
33+
// CHECK: %n64 = alloca %Nested64, align 64
34+
let n64 = Nested64 { a, b: Align64::B(b), c };
35+
n64
36+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// run-pass
2+
#![allow(dead_code)]
3+
#![feature(repr_align_enum)]
4+
5+
use std::mem;
6+
7+
// Raising alignment
8+
#[repr(align(16))]
9+
enum Align16 {
10+
Foo { foo: u32 },
11+
Bar { bar: u32 },
12+
}
13+
14+
// Raise alignment by maximum
15+
#[repr(align(1), align(16))]
16+
#[repr(align(32))]
17+
#[repr(align(4))]
18+
enum Align32 {
19+
Foo,
20+
Bar,
21+
}
22+
23+
// Not reducing alignment
24+
#[repr(align(4))]
25+
enum AlsoAlign16 {
26+
Foo { limb_with_align16: Align16 },
27+
Bar,
28+
}
29+
30+
// No niche for discriminant when used as limb
31+
#[repr(align(16))]
32+
struct NoNiche16(u64, u64);
33+
34+
// Discriminant will require extra space, but enum needs to stay compatible
35+
// with alignment 16
36+
#[repr(align(1))]
37+
enum AnotherAlign16 {
38+
Foo { limb_with_noniche16: NoNiche16 },
39+
Bar,
40+
Baz,
41+
}
42+
43+
fn main() {
44+
assert_eq!(mem::align_of::<Align16>(), 16);
45+
assert_eq!(mem::size_of::<Align16>(), 16);
46+
47+
assert_eq!(mem::align_of::<Align32>(), 32);
48+
assert_eq!(mem::size_of::<Align32>(), 32);
49+
50+
assert_eq!(mem::align_of::<AlsoAlign16>(), 16);
51+
assert_eq!(mem::size_of::<AlsoAlign16>(), 16);
52+
53+
assert_eq!(mem::align_of::<AnotherAlign16>(), 16);
54+
assert_eq!(mem::size_of::<AnotherAlign16>(), 32);
55+
}

src/test/ui/attr-usage-repr.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#![feature(repr_simd)]
2+
#![feature(repr_align_enum)]
23

34
#[repr(C)] //~ ERROR: attribute should be applied to struct, enum or union
45
fn f() {}
@@ -18,7 +19,7 @@ struct SInt(f64, f64);
1819
#[repr(C)]
1920
enum EExtern { A, B }
2021

21-
#[repr(align(8))] //~ ERROR: attribute should be applied to struct
22+
#[repr(align(8))]
2223
enum EAlign { A, B }
2324

2425
#[repr(packed)] //~ ERROR: attribute should be applied to struct

src/test/ui/attr-usage-repr.stderr

+5-13
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,35 @@
11
error[E0517]: attribute should be applied to struct, enum or union
2-
--> $DIR/attr-usage-repr.rs:3:8
2+
--> $DIR/attr-usage-repr.rs:4:8
33
|
44
LL | #[repr(C)] //~ ERROR: attribute should be applied to struct, enum or union
55
| ^
66
LL | fn f() {}
77
| --------- not a struct, enum or union
88

99
error[E0517]: attribute should be applied to enum
10-
--> $DIR/attr-usage-repr.rs:15:8
10+
--> $DIR/attr-usage-repr.rs:16:8
1111
|
1212
LL | #[repr(i8)] //~ ERROR: attribute should be applied to enum
1313
| ^^
1414
LL | struct SInt(f64, f64);
1515
| ---------------------- not an enum
1616

1717
error[E0517]: attribute should be applied to struct or union
18-
--> $DIR/attr-usage-repr.rs:21:8
19-
|
20-
LL | #[repr(align(8))] //~ ERROR: attribute should be applied to struct
21-
| ^^^^^^^^
22-
LL | enum EAlign { A, B }
23-
| -------------------- not a struct or union
24-
25-
error[E0517]: attribute should be applied to struct or union
26-
--> $DIR/attr-usage-repr.rs:24:8
18+
--> $DIR/attr-usage-repr.rs:25:8
2719
|
2820
LL | #[repr(packed)] //~ ERROR: attribute should be applied to struct
2921
| ^^^^^^
3022
LL | enum EPacked { A, B }
3123
| --------------------- not a struct or union
3224

3325
error[E0517]: attribute should be applied to struct
34-
--> $DIR/attr-usage-repr.rs:27:8
26+
--> $DIR/attr-usage-repr.rs:28:8
3527
|
3628
LL | #[repr(simd)] //~ ERROR: attribute should be applied to struct
3729
| ^^^^
3830
LL | enum ESimd { A, B }
3931
| ------------------- not a struct
4032

41-
error: aborting due to 5 previous errors
33+
error: aborting due to 4 previous errors
4234

4335
For more information about this error, try `rustc --explain E0517`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#[repr(align(16))]
2+
struct Foo(u64);
3+
4+
#[repr(align(8))] //~ ERROR `#[repr(align(x))]` on enums is experimental (see issue #57996)
5+
enum Bar {
6+
Foo { foo: Foo },
7+
Baz,
8+
}
9+
10+
fn main() { }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error[E0658]: `#[repr(align(x))]` on enums is experimental (see issue #57996)
2+
--> $DIR/feature-gate-repr_align_enum.rs:4:1
3+
|
4+
LL | #[repr(align(8))] //~ ERROR `#[repr(align(x))]` on enums is experimental (see issue #57996)
5+
| ^^^^^^^^^^^^^^^^^
6+
|
7+
= help: add #![feature(repr_align_enum)] to the crate attributes to enable
8+
9+
error: aborting due to previous error
10+
11+
For more information about this error, try `rustc --explain E0658`.

src/test/ui/repr/repr-align.rs

+4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#![feature(repr_align_enum)]
12
#![allow(dead_code)]
23

34
#[repr(align(16.0))] //~ ERROR: invalid `repr(align)` attribute: not an unsuffixed integer
@@ -12,4 +13,7 @@ struct C(i32);
1213
#[repr(align(536870912))] // ok: this is the largest accepted alignment
1314
struct D(i32);
1415

16+
#[repr(align(15))] //~ ERROR: invalid `repr(align)` attribute: not a power of two
17+
enum E { Left, Right }
18+
1519
fn main() {}

src/test/ui/repr/repr-align.stderr

+10-4
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,27 @@
11
error[E0589]: invalid `repr(align)` attribute: not an unsuffixed integer
2-
--> $DIR/repr-align.rs:3:8
2+
--> $DIR/repr-align.rs:4:8
33
|
44
LL | #[repr(align(16.0))] //~ ERROR: invalid `repr(align)` attribute: not an unsuffixed integer
55
| ^^^^^^^^^^^
66

77
error[E0589]: invalid `repr(align)` attribute: not a power of two
8-
--> $DIR/repr-align.rs:6:8
8+
--> $DIR/repr-align.rs:7:8
99
|
1010
LL | #[repr(align(15))] //~ ERROR: invalid `repr(align)` attribute: not a power of two
1111
| ^^^^^^^^^
1212

1313
error[E0589]: invalid `repr(align)` attribute: larger than 2^29
14-
--> $DIR/repr-align.rs:9:8
14+
--> $DIR/repr-align.rs:10:8
1515
|
1616
LL | #[repr(align(4294967296))] //~ ERROR: invalid `repr(align)` attribute: larger than 2^29
1717
| ^^^^^^^^^^^^^^^^^
1818

19-
error: aborting due to 3 previous errors
19+
error[E0589]: invalid `repr(align)` attribute: not a power of two
20+
--> $DIR/repr-align.rs:16:8
21+
|
22+
LL | #[repr(align(15))] //~ ERROR: invalid `repr(align)` attribute: not a power of two
23+
| ^^^^^^^^^
24+
25+
error: aborting due to 4 previous errors
2026

2127
For more information about this error, try `rustc --explain E0589`.

0 commit comments

Comments
 (0)