diff --git a/src/doc/unstable-book/src/language-features/repr-align-enum.md b/src/doc/unstable-book/src/language-features/repr-align-enum.md new file mode 100644 index 0000000000000..415c6ebe8b4bc --- /dev/null +++ b/src/doc/unstable-book/src/language-features/repr-align-enum.md @@ -0,0 +1,42 @@ +# `repr_align_enum` + +The tracking issue for this feature is: [#57996] + +[#57996]: /~https://github.com/rust-lang/rust/issues/57996 + +------------------------ + +The `repr_align_enum` feature allows using the `#[repr(align(x))]` attribute +on enums, similarly to structs. + +# Examples + +```rust +#![feature(repr_align_enum)] + +#[repr(align(8))] +enum Aligned { + Foo, + Bar { value: u32 }, +} + +fn main() { + assert_eq!(std::mem::align_of::(), 8); +} +``` + +This is equivalent to using an aligned wrapper struct everywhere: + +```rust +#[repr(align(8))] +struct Aligned(Unaligned); + +enum Unaligned { + Foo, + Bar { value: u32 }, +} + +fn main() { + assert_eq!(std::mem::align_of::(), 8); +} +``` diff --git a/src/librustc/hir/check_attr.rs b/src/librustc/hir/check_attr.rs index 4ce41fec18240..4c467567c4d93 100644 --- a/src/librustc/hir/check_attr.rs +++ b/src/librustc/hir/check_attr.rs @@ -186,8 +186,8 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> { }; let (article, allowed_targets) = match &*name.as_str() { - "C" => { - is_c = true; + "C" | "align" => { + is_c |= name == "C"; if target != Target::Struct && target != Target::Union && target != Target::Enum { @@ -212,14 +212,6 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> { continue } } - "align" => { - if target != Target::Struct && - target != Target::Union { - ("a", "struct or union") - } else { - continue - } - } "transparent" => { is_transparent = true; if target != Target::Struct { diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 6c780369a0a2d..e7b9a884b5e0c 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -464,6 +464,9 @@ declare_features! ( // #[optimize(X)] (active, optimize_attribute, "1.34.0", Some(54882), None), + + // #[repr(align(X))] on enums + (active, repr_align_enum, "1.34.0", Some(57996), None), ); declare_features! ( @@ -1700,6 +1703,17 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } } + ast::ItemKind::Enum(..) => { + for attr in attr::filter_by_name(&i.attrs[..], "repr") { + for item in attr.meta_item_list().unwrap_or_else(Vec::new) { + if item.check_name("align") { + gate_feature_post!(&self, repr_align_enum, attr.span, + "`#[repr(align(x))]` on enums is experimental"); + } + } + } + } + ast::ItemKind::Impl(_, polarity, defaultness, _, _, _, _) => { if polarity == ast::ImplPolarity::Negative { gate_feature_post!(&self, optin_builtin_traits, diff --git a/src/test/codegen/align-enum.rs b/src/test/codegen/align-enum.rs new file mode 100644 index 0000000000000..2251c54229ee0 --- /dev/null +++ b/src/test/codegen/align-enum.rs @@ -0,0 +1,36 @@ +// compile-flags: -C no-prepopulate-passes +// ignore-tidy-linelength +// min-llvm-version 7.0 + +#![crate_type = "lib"] +#![feature(repr_align_enum)] + +#[repr(align(64))] +pub enum Align64 { + A(u32), + B(u32), +} +// CHECK: %Align64 = type { [0 x i32], i32, [15 x i32] } + +pub struct Nested64 { + a: u8, + b: Align64, + c: u16, +} + +// CHECK-LABEL: @align64 +#[no_mangle] +pub fn align64(a: u32) -> Align64 { +// CHECK: %a64 = alloca %Align64, align 64 +// CHECK: call void @llvm.memcpy.{{.*}}(i8* align 64 %{{.*}}, i8* align 64 %{{.*}}, i{{[0-9]+}} 64, i1 false) + let a64 = Align64::A(a); + a64 +} + +// CHECK-LABEL: @nested64 +#[no_mangle] +pub fn nested64(a: u8, b: u32, c: u16) -> Nested64 { +// CHECK: %n64 = alloca %Nested64, align 64 + let n64 = Nested64 { a, b: Align64::B(b), c }; + n64 +} diff --git a/src/test/run-pass/structs-enums/align-enum.rs b/src/test/run-pass/structs-enums/align-enum.rs new file mode 100644 index 0000000000000..8d72b1f6f0d24 --- /dev/null +++ b/src/test/run-pass/structs-enums/align-enum.rs @@ -0,0 +1,55 @@ +// run-pass +#![allow(dead_code)] +#![feature(repr_align_enum)] + +use std::mem; + +// Raising alignment +#[repr(align(16))] +enum Align16 { + Foo { foo: u32 }, + Bar { bar: u32 }, +} + +// Raise alignment by maximum +#[repr(align(1), align(16))] +#[repr(align(32))] +#[repr(align(4))] +enum Align32 { + Foo, + Bar, +} + +// Not reducing alignment +#[repr(align(4))] +enum AlsoAlign16 { + Foo { limb_with_align16: Align16 }, + Bar, +} + +// No niche for discriminant when used as limb +#[repr(align(16))] +struct NoNiche16(u64, u64); + +// Discriminant will require extra space, but enum needs to stay compatible +// with alignment 16 +#[repr(align(1))] +enum AnotherAlign16 { + Foo { limb_with_noniche16: NoNiche16 }, + Bar, + Baz, +} + +fn main() { + assert_eq!(mem::align_of::(), 16); + assert_eq!(mem::size_of::(), 16); + + assert_eq!(mem::align_of::(), 32); + assert_eq!(mem::size_of::(), 32); + + assert_eq!(mem::align_of::(), 16); + assert_eq!(mem::size_of::(), 16); + + assert_eq!(mem::align_of::(), 16); + assert_eq!(mem::size_of::(), 32); +} diff --git a/src/test/ui/attr-usage-repr.rs b/src/test/ui/attr-usage-repr.rs index 498bf4d284a73..1df2947cbe2dd 100644 --- a/src/test/ui/attr-usage-repr.rs +++ b/src/test/ui/attr-usage-repr.rs @@ -1,4 +1,5 @@ #![feature(repr_simd)] +#![feature(repr_align_enum)] #[repr(C)] //~ ERROR: attribute should be applied to struct, enum or union fn f() {} @@ -18,7 +19,7 @@ struct SInt(f64, f64); #[repr(C)] enum EExtern { A, B } -#[repr(align(8))] //~ ERROR: attribute should be applied to struct +#[repr(align(8))] enum EAlign { A, B } #[repr(packed)] //~ ERROR: attribute should be applied to struct diff --git a/src/test/ui/attr-usage-repr.stderr b/src/test/ui/attr-usage-repr.stderr index 990984bbb2b3d..abb8685e4cef0 100644 --- a/src/test/ui/attr-usage-repr.stderr +++ b/src/test/ui/attr-usage-repr.stderr @@ -1,5 +1,5 @@ error[E0517]: attribute should be applied to struct, enum or union - --> $DIR/attr-usage-repr.rs:3:8 + --> $DIR/attr-usage-repr.rs:4:8 | LL | #[repr(C)] //~ ERROR: attribute should be applied to struct, enum or union | ^ @@ -7,7 +7,7 @@ LL | fn f() {} | --------- not a struct, enum or union error[E0517]: attribute should be applied to enum - --> $DIR/attr-usage-repr.rs:15:8 + --> $DIR/attr-usage-repr.rs:16:8 | LL | #[repr(i8)] //~ ERROR: attribute should be applied to enum | ^^ @@ -15,15 +15,7 @@ LL | struct SInt(f64, f64); | ---------------------- not an enum error[E0517]: attribute should be applied to struct or union - --> $DIR/attr-usage-repr.rs:21:8 - | -LL | #[repr(align(8))] //~ ERROR: attribute should be applied to struct - | ^^^^^^^^ -LL | enum EAlign { A, B } - | -------------------- not a struct or union - -error[E0517]: attribute should be applied to struct or union - --> $DIR/attr-usage-repr.rs:24:8 + --> $DIR/attr-usage-repr.rs:25:8 | LL | #[repr(packed)] //~ ERROR: attribute should be applied to struct | ^^^^^^ @@ -31,13 +23,13 @@ LL | enum EPacked { A, B } | --------------------- not a struct or union error[E0517]: attribute should be applied to struct - --> $DIR/attr-usage-repr.rs:27:8 + --> $DIR/attr-usage-repr.rs:28:8 | LL | #[repr(simd)] //~ ERROR: attribute should be applied to struct | ^^^^ LL | enum ESimd { A, B } | ------------------- not a struct -error: aborting due to 5 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0517`. diff --git a/src/test/ui/feature-gates/feature-gate-repr_align_enum.rs b/src/test/ui/feature-gates/feature-gate-repr_align_enum.rs new file mode 100644 index 0000000000000..f8e68a9de015b --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-repr_align_enum.rs @@ -0,0 +1,10 @@ +#[repr(align(16))] +struct Foo(u64); + +#[repr(align(8))] //~ ERROR `#[repr(align(x))]` on enums is experimental (see issue #57996) +enum Bar { + Foo { foo: Foo }, + Baz, +} + +fn main() { } diff --git a/src/test/ui/feature-gates/feature-gate-repr_align_enum.stderr b/src/test/ui/feature-gates/feature-gate-repr_align_enum.stderr new file mode 100644 index 0000000000000..6def25f965118 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-repr_align_enum.stderr @@ -0,0 +1,11 @@ +error[E0658]: `#[repr(align(x))]` on enums is experimental (see issue #57996) + --> $DIR/feature-gate-repr_align_enum.rs:4:1 + | +LL | #[repr(align(8))] //~ ERROR `#[repr(align(x))]` on enums is experimental (see issue #57996) + | ^^^^^^^^^^^^^^^^^ + | + = help: add #![feature(repr_align_enum)] to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/repr/repr-align.rs b/src/test/ui/repr/repr-align.rs index 78ed6c7e1c417..9ce89e82ca225 100644 --- a/src/test/ui/repr/repr-align.rs +++ b/src/test/ui/repr/repr-align.rs @@ -1,3 +1,4 @@ +#![feature(repr_align_enum)] #![allow(dead_code)] #[repr(align(16.0))] //~ ERROR: invalid `repr(align)` attribute: not an unsuffixed integer @@ -12,4 +13,7 @@ struct C(i32); #[repr(align(536870912))] // ok: this is the largest accepted alignment struct D(i32); +#[repr(align(15))] //~ ERROR: invalid `repr(align)` attribute: not a power of two +enum E { Left, Right } + fn main() {} diff --git a/src/test/ui/repr/repr-align.stderr b/src/test/ui/repr/repr-align.stderr index e8dbf74232bfa..f1a5d88ace1fd 100644 --- a/src/test/ui/repr/repr-align.stderr +++ b/src/test/ui/repr/repr-align.stderr @@ -1,21 +1,27 @@ error[E0589]: invalid `repr(align)` attribute: not an unsuffixed integer - --> $DIR/repr-align.rs:3:8 + --> $DIR/repr-align.rs:4:8 | LL | #[repr(align(16.0))] //~ ERROR: invalid `repr(align)` attribute: not an unsuffixed integer | ^^^^^^^^^^^ error[E0589]: invalid `repr(align)` attribute: not a power of two - --> $DIR/repr-align.rs:6:8 + --> $DIR/repr-align.rs:7:8 | LL | #[repr(align(15))] //~ ERROR: invalid `repr(align)` attribute: not a power of two | ^^^^^^^^^ error[E0589]: invalid `repr(align)` attribute: larger than 2^29 - --> $DIR/repr-align.rs:9:8 + --> $DIR/repr-align.rs:10:8 | LL | #[repr(align(4294967296))] //~ ERROR: invalid `repr(align)` attribute: larger than 2^29 | ^^^^^^^^^^^^^^^^^ -error: aborting due to 3 previous errors +error[E0589]: invalid `repr(align)` attribute: not a power of two + --> $DIR/repr-align.rs:16:8 + | +LL | #[repr(align(15))] //~ ERROR: invalid `repr(align)` attribute: not a power of two + | ^^^^^^^^^ + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0589`.