Skip to content

Commit d44c01c

Browse files
committed
allow repr(C) enums to be up to 64bit in size
1 parent 63d04de commit d44c01c

File tree

7 files changed

+42
-65
lines changed

7 files changed

+42
-65
lines changed

compiler/rustc_abi/src/lib.rs

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -190,15 +190,11 @@ impl ReprOptions {
190190
/// `c_enum_min_size` along the way) and that will work just fine, it just induces casts when
191191
/// getting/setting the discriminant.
192192
pub fn discr_type(&self, cx: &impl HasDataLayout) -> IntegerType {
193-
self.int.unwrap_or(
194-
if self.c()
195-
&& let Some(max_size) = cx.data_layout().c_enum_max_size
196-
{
197-
IntegerType::Fixed(max_size, true)
198-
} else {
199-
IntegerType::Pointer(true)
200-
},
201-
)
193+
self.int.unwrap_or(if self.c() {
194+
IntegerType::Fixed(cx.data_layout().c_enum_max_size, true)
195+
} else {
196+
IntegerType::Pointer(true)
197+
})
202198
}
203199

204200
/// Returns `true` if this `#[repr()]` should inhabit "smart enum
@@ -288,8 +284,8 @@ pub struct TargetDataLayout {
288284
/// Note: This isn't in LLVM's data layout string, it is `short_enum`
289285
/// so the only valid spec for LLVM is c_int::BITS or 8
290286
pub c_enum_min_size: Integer,
291-
/// Maximum size of #[repr(C)] enums (defaults to pointer size).
292-
pub c_enum_max_size: Option<Integer>,
287+
/// Maximum size of #[repr(C)] enums (defaults to c_longlong::BITS, which is always 64).
288+
pub c_enum_max_size: Integer,
293289
}
294290

295291
impl Default for TargetDataLayout {
@@ -323,7 +319,10 @@ impl Default for TargetDataLayout {
323319
address_space_info: vec![],
324320
instruction_address_space: AddressSpace::ZERO,
325321
c_enum_min_size: Integer::I32,
326-
c_enum_max_size: None,
322+
// C23 allows enums to have any integer type. The largest integer type in the standard
323+
// is `long long`, which is always 64bits (judging from our own definition in
324+
// `library/core/src/ffi/primitives.rs`).
325+
c_enum_max_size: Integer::I64,
327326
}
328327
}
329328
}

compiler/rustc_target/src/spec/mod.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2386,13 +2386,13 @@ impl Target {
23862386
self.c_enum_min_bits.unwrap_or(self.c_int_width as _),
23872387
))
23882388
.map_err(|err| TargetDataLayoutErrors::InvalidBitsSize { err })?;
2389-
dl.c_enum_max_size = match self.c_enum_max_bits {
2390-
None => None,
2391-
Some(max_bits) => Some(
2392-
Integer::from_size(Size::from_bits(max_bits))
2393-
.map_err(|err| TargetDataLayoutErrors::InvalidBitsSize { err })?,
2394-
),
2395-
};
2389+
dl.c_enum_max_size = Integer::from_size(Size::from_bits(
2390+
// C23 allows enums to have any integer type. The largest integer type in the standard
2391+
// is `long long`, which is always 64bits (judging from our own definition in
2392+
// `library/core/src/ffi/primitives.rs`). Hence we default to 64.
2393+
self.c_enum_max_bits.unwrap_or(64),
2394+
))
2395+
.map_err(|err| TargetDataLayoutErrors::InvalidBitsSize { err })?;
23962396

23972397
Ok(dl)
23982398
}

tests/auxiliary/minicore.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,14 @@ impl Neg for i32 {
177177
}
178178
}
179179

180+
impl Neg for i64 {
181+
type Output = i64;
182+
183+
fn neg(self) -> i64 {
184+
loop {} // Dummy impl, not actually used
185+
}
186+
}
187+
180188
impl Neg for isize {
181189
type Output = isize;
182190

tests/ui/enum-discriminant/repr-c-size.linux32.stderr

Lines changed: 0 additions & 28 deletions
This file was deleted.

tests/ui/enum-discriminant/repr-c-size.msvc32.stderr

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,27 @@
11
warning: literal out of range for `i32`
2-
--> $DIR/repr-c-size.rs:24:9
2+
--> $DIR/repr-c-size.rs:23:9
33
|
44
LL | A = 9223372036854775807, // i64::MAX
55
| ^^^^^^^^^^^^^^^^^^^
66
|
77
= note: the literal `9223372036854775807` does not fit into the type `i32` whose range is `-2147483648..=2147483647`
88
= help: consider using the type `i64` instead
99
note: the lint level is defined here
10-
--> $DIR/repr-c-size.rs:22:8
10+
--> $DIR/repr-c-size.rs:21:8
1111
|
1212
LL | #[warn(overflowing_literals)]
1313
| ^^^^^^^^^^^^^^^^^^^^
1414

1515
warning: literal out of range for `i32`
16-
--> $DIR/repr-c-size.rs:43:9
16+
--> $DIR/repr-c-size.rs:41:9
1717
|
1818
LL | A = 4294967294, // u32::MAX - 1
1919
| ^^^^^^^^^^
2020
|
2121
= note: the literal `4294967294` does not fit into the type `i32` whose range is `-2147483648..=2147483647`
2222
= help: consider using the type `u32` instead
2323
note: the lint level is defined here
24-
--> $DIR/repr-c-size.rs:41:8
24+
--> $DIR/repr-c-size.rs:39:8
2525
|
2626
LL | #[warn(overflowing_literals)]
2727
| ^^^^^^^^^^^^^^^^^^^^

tests/ui/enum-discriminant/repr-c-size.msvc64.stderr

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,27 @@
11
warning: literal out of range for `i32`
2-
--> $DIR/repr-c-size.rs:24:9
2+
--> $DIR/repr-c-size.rs:23:9
33
|
44
LL | A = 9223372036854775807, // i64::MAX
55
| ^^^^^^^^^^^^^^^^^^^
66
|
77
= note: the literal `9223372036854775807` does not fit into the type `i32` whose range is `-2147483648..=2147483647`
88
= help: consider using the type `i64` instead
99
note: the lint level is defined here
10-
--> $DIR/repr-c-size.rs:22:8
10+
--> $DIR/repr-c-size.rs:21:8
1111
|
1212
LL | #[warn(overflowing_literals)]
1313
| ^^^^^^^^^^^^^^^^^^^^
1414

1515
warning: literal out of range for `i32`
16-
--> $DIR/repr-c-size.rs:43:9
16+
--> $DIR/repr-c-size.rs:41:9
1717
|
1818
LL | A = 4294967294, // u32::MAX - 1
1919
| ^^^^^^^^^^
2020
|
2121
= note: the literal `4294967294` does not fit into the type `i32` whose range is `-2147483648..=2147483647`
2222
= help: consider using the type `u32` instead
2323
note: the lint level is defined here
24-
--> $DIR/repr-c-size.rs:41:8
24+
--> $DIR/repr-c-size.rs:39:8
2525
|
2626
LL | #[warn(overflowing_literals)]
2727
| ^^^^^^^^^^^^^^^^^^^^

tests/ui/enum-discriminant/repr-c-size.rs

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,40 +17,38 @@ use minicore::*;
1717

1818
// Fits in i64 but not i32.
1919
// C compiler demo: <https://godbolt.org/z/6v941G3x5>
20-
// FIXME: This seems to be wrong for linux32?
2120
#[repr(C)]
2221
#[warn(overflowing_literals)]
2322
enum OverflowingEnum {
2423
A = 9223372036854775807, // i64::MAX
25-
//[linux32,msvc32,msvc64]~^ WARN: literal out of range
24+
//[msvc32,msvc64]~^ WARN: literal out of range
2625
}
2726

28-
#[cfg(not(linux64))]
27+
#[cfg(any(msvc32,msvc64))]
2928
const _: () = if mem::size_of::<OverflowingEnum>() != 4 {
3029
unsafe { hint::unreachable() }
3130
};
32-
#[cfg(linux64)]
31+
#[cfg(any(linux32,linux64))]
3332
const _: () = if mem::size_of::<OverflowingEnum>() != 8 {
3433
unsafe { hint::unreachable() }
3534
};
3635

3736
// Each value fits in i32 or u32, but not all values fit into the same type.
3837
// C compiler demo: <https://godbolt.org/z/GPYafPhjK>
39-
// FIXME: This seems to do the wrong thing for 32bit Linux?
4038
#[repr(C)]
4139
#[warn(overflowing_literals)]
4240
enum OverflowingEnum2 {
4341
A = 4294967294, // u32::MAX - 1
44-
//[linux32,msvc32,msvc64]~^ WARN: literal out of range
42+
//[msvc32,msvc64]~^ WARN: literal out of range
4543
B = -1,
4644
}
4745

48-
#[cfg(not(linux64))]
49-
const _: () = if mem::size_of::<OverflowingEnum2>() != 4 {
46+
#[cfg(any(msvc32,msvc64))]
47+
const _: () = if mem::size_of::<OverflowingEnum>() != 4 {
5048
unsafe { hint::unreachable() }
5149
};
52-
#[cfg(linux64)]
53-
const _: () = if mem::size_of::<OverflowingEnum2>() != 8 {
50+
#[cfg(any(linux32,linux64))]
51+
const _: () = if mem::size_of::<OverflowingEnum>() != 8 {
5452
unsafe { hint::unreachable() }
5553
};
5654

0 commit comments

Comments
 (0)