Skip to content

Commit 608e57c

Browse files
author
Ulrik Sverdrup
committed
Document #[repr] on non-C-like enums
rustc accepts the following today: #[repr(u8)] enum Flag<T> { Dropped, Alive(T), } and it has a good use (it appears to me): this inhibits the non-nullable pointer optimization that the regular Option<T> and similar enums allow. Document this in the reference, and add tests to make sure it compiles. This means that we guarantee with `repr` that the discriminant will be present and with that size, but not sure if we want to guarantee anything more (no guarantee on placement in struct).
1 parent 541fe5f commit 608e57c

File tree

2 files changed

+113
-6
lines changed

2 files changed

+113
-6
lines changed

src/doc/reference.md

+7-6
Original file line numberDiff line numberDiff line change
@@ -1892,12 +1892,13 @@ interpreted:
18921892

18931893
On `enum`s:
18941894

1895-
- `repr` - on C-like enums, this sets the underlying type used for
1896-
representation. Takes one argument, which is the primitive
1897-
type this enum should be represented for, or `C`, which specifies that it
1898-
should be the default `enum` size of the C ABI for that platform. Note that
1899-
enum representation in C is undefined, and this may be incorrect when the C
1900-
code is compiled with certain flags.
1895+
- `repr` - this sets the underlying type used for representation of the
1896+
discriminant. Takes one argument, which is the primitive type this enum
1897+
should be represented as, or `C`, which specifies that it should be the
1898+
default `enum` size of the C ABI for that platform. Note that enum
1899+
representation in C is implementation defined, and this may be incorrect when
1900+
the C code is compiled with certain flags. The representation attribute
1901+
inhibits elision of the enum discriminant in layout optimizations.
19011902

19021903
On `struct`s:
19031904

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Test that explicit discriminant sizing inhibits the non-nullable pointer
12+
// optimization in enum layout.
13+
14+
use std::mem::size_of;
15+
16+
#[repr(i8)]
17+
enum Ei8<T> {
18+
_None,
19+
_Some(T),
20+
}
21+
22+
#[repr(u8)]
23+
enum Eu8<T> {
24+
_None,
25+
_Some(T),
26+
}
27+
28+
#[repr(i16)]
29+
enum Ei16<T> {
30+
_None,
31+
_Some(T),
32+
}
33+
34+
#[repr(u16)]
35+
enum Eu16<T> {
36+
_None,
37+
_Some(T),
38+
}
39+
40+
#[repr(i32)]
41+
enum Ei32<T> {
42+
_None,
43+
_Some(T),
44+
}
45+
46+
#[repr(u32)]
47+
enum Eu32<T> {
48+
_None,
49+
_Some(T),
50+
}
51+
52+
#[repr(i64)]
53+
enum Ei64<T> {
54+
_None,
55+
_Some(T),
56+
}
57+
58+
#[repr(u64)]
59+
enum Eu64<T> {
60+
_None,
61+
_Some(T),
62+
}
63+
64+
#[repr(isize)]
65+
enum Eint<T> {
66+
_None,
67+
_Some(T),
68+
}
69+
70+
#[repr(usize)]
71+
enum Euint<T> {
72+
_None,
73+
_Some(T),
74+
}
75+
76+
#[repr(C)]
77+
enum EC<T> {
78+
_None,
79+
_Some(T),
80+
}
81+
82+
pub fn main() {
83+
assert_eq!(size_of::<Ei8<()>>(), 1);
84+
assert_eq!(size_of::<Eu8<()>>(), 1);
85+
assert_eq!(size_of::<Ei16<()>>(), 2);
86+
assert_eq!(size_of::<Eu16<()>>(), 2);
87+
assert_eq!(size_of::<Ei32<()>>(), 4);
88+
assert_eq!(size_of::<Eu32<()>>(), 4);
89+
assert_eq!(size_of::<Ei64<()>>(), 8);
90+
assert_eq!(size_of::<Eu64<()>>(), 8);
91+
assert_eq!(size_of::<Eint<()>>(), size_of::<isize>());
92+
assert_eq!(size_of::<Euint<()>>(), size_of::<usize>());
93+
94+
assert!(size_of::<Ei8<&i32>>() > 1);
95+
assert!(size_of::<Eu8<&i32>>() > 1);
96+
assert!(size_of::<Ei16<&i32>>() > 2);
97+
assert!(size_of::<Eu16<&i32>>() > 2);
98+
assert!(size_of::<Ei32<&i32>>() > 4);
99+
assert!(size_of::<Eu32<&i32>>() > 4);
100+
assert!(size_of::<Ei64<&i32>>() > 8);
101+
assert!(size_of::<Eu64<&i32>>() > 8);
102+
assert!(size_of::<Eint<&i32>>() > size_of::<isize>());
103+
assert!(size_of::<Euint<&i32>>() > size_of::<usize>());
104+
105+
assert!(size_of::<EC<&i32>>() > size_of::<EC<()>>());
106+
}

0 commit comments

Comments
 (0)