Skip to content

Commit e3ff693

Browse files
committed
ensure repr(int) on enums uses the same ABI as int
1 parent 2d20b42 commit e3ff693

38 files changed

Lines changed: 285 additions & 95 deletions

File tree

‎compiler/rustc_abi/src/callconv/reg.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ pub enum RegKind {
2525
impl RegKind {
2626
pub fn from_primitive(primitive: Primitive) -> Self {
2727
match primitive {
28-
Primitive::Int(..) | Primitive::Pointer(_) => RegKind::Integer,
28+
Primitive::Bool | Primitive::Int(..) | Primitive::Pointer(_) => RegKind::Integer,
2929
Primitive::Float(Float::PpcF128) => RegKind::PpcF128,
3030
Primitive::Float(Float::F16 | Float::F16B | Float::F32 | Float::F64 | Float::F128) => {
3131
RegKind::Float

‎compiler/rustc_abi/src/layout.rs‎

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -882,8 +882,10 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
882882
// won't be so conservative.
883883

884884
// Use the initial field alignment
885-
let mut ity = if repr.c() || repr.int.is_some() {
885+
let mut ity = if repr.c() {
886886
min_ity
887+
} else if let Some(ity) = repr.int {
888+
Integer::from_attr(dl, ity)
887889
} else {
888890
Integer::for_align(dl, start_align).unwrap_or(min_ity)
889891
};
@@ -917,10 +919,18 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
917919
// We might have no inhabited variants, so pretend there's at least one.
918920
.unwrap_or(WrappingRange { start: 0, end: 0 })
919921
};
920-
let tag = Scalar::Initialized {
921-
value: Primitive::Int(ity, signed),
922-
valid_range: tag_valid_range,
922+
923+
// for an enum that does NOT have an explicit repr, and only has discriminants 0..=1, use Bool for it
924+
let tag = if repr.int.is_none()
925+
&& !repr.c()
926+
&& matches!(tag_valid_range, WrappingRange { start: 0, end: 1 })
927+
&& ity == Integer::I8
928+
{
929+
Scalar::Initialized { value: Primitive::Bool, valid_range: tag_valid_range }
930+
} else {
931+
Scalar::Initialized { value: Primitive::Int(ity, signed), valid_range: tag_valid_range }
923932
};
933+
tracing::info!("variants: {:#?}\ntag: {:#?}", variants, tag);
924934
let mut abi = BackendRepr::Memory { sized: true };
925935

926936
let uninhabited = layout_variants.iter().all(|v| v.is_uninhabited());
@@ -975,6 +985,9 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
975985
// Allow integers of the same size with differing signedness.
976986
// We arbitrarily choose the signedness of the first variant.
977987
(p @ Primitive::Int(x, _), Primitive::Int(y, _)) if x == y => p,
988+
// Allow booleans to unify with integers of size 1
989+
(p @ Primitive::Int(Integer::I8, _), Primitive::Bool)
990+
| (Primitive::Bool, p @ Primitive::Int(Integer::I8, _)) => p,
978991
// Allow integers mixed with pointers of the same layout.
979992
// We must represent this using a pointer, to avoid
980993
// roundtripping pointers through ptrtoint/inttoptr.

‎compiler/rustc_abi/src/layout/simple.rs‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,11 +68,12 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
6868
Primitive::Int(_, false) => 2,
6969
Primitive::Float(_) => 3,
7070
Primitive::Pointer(_) => 4,
71+
Primitive::Bool => 5,
7172
} << 32,
7273
)
7374
// distinguishes references from pointers
7475
.wrapping_add((range.start as u64).rotate_right(16))
75-
// distinguishes char from u32 and bool from u8
76+
// distinguishes char from u32 (and mixes bool up a bit too, even though it shouldn't be needed)
7677
.wrapping_add((range.end as u64).rotate_right(16));
7778

7879
LayoutData {

‎compiler/rustc_abi/src/layout/ty.rs‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ use rustc_macros::StableHash;
77

88
use crate::layout::{FieldIdx, VariantIdx};
99
use crate::{
10-
Align, BackendRepr, FieldsShape, Float, HasDataLayout, LayoutData, Niche, Numeric, PointeeInfo,
11-
Primitive, Size, Variants,
10+
Align, BackendRepr, FieldsShape, Float, HasDataLayout, Integer, LayoutData, Niche, Numeric,
11+
PointeeInfo, Primitive, Size, Variants,
1212
};
1313

1414
// Explicitly import `Float` to avoid ambiguity with `Primitive::Float`.
@@ -349,6 +349,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
349349
// one of the match branches.
350350
let primitive = scalar.primitive();
351351
match primitive {
352+
Primitive::Bool => Some(Numeric::Int(Integer::I8, false)),
352353
Primitive::Int(integer, is_signed) => Some(Numeric::Int(integer, is_signed)),
353354
Primitive::Float(
354355
float @ (Float::F16 | Float::F32 | Float::F64 | Float::F128 | Float::PpcF128),

‎compiler/rustc_abi/src/lib.rs‎

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1476,6 +1476,7 @@ impl Numeric {
14761476
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
14771477
#[cfg_attr(feature = "nightly", derive(StableHash))]
14781478
pub enum Primitive {
1479+
Bool,
14791480
/// The `bool` is the signedness of the `Integer` type.
14801481
///
14811482
/// One would think we would not care about such details this low down,
@@ -1491,6 +1492,7 @@ pub enum Primitive {
14911492
impl fmt::Debug for Primitive {
14921493
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
14931494
let name = match *self {
1495+
Primitive::Bool => "bool",
14941496
Primitive::Int(integer, is_signed) => {
14951497
if is_signed {
14961498
integer.int_ty_str()
@@ -1517,6 +1519,7 @@ impl Primitive {
15171519
let dl = cx.data_layout();
15181520

15191521
match self {
1522+
Bool => Size::from_bits(1),
15201523
Int(i, _) => i.size(),
15211524
Float(f) => f.size(),
15221525
Pointer(a) => dl.pointer_size_in(a),
@@ -1532,6 +1535,7 @@ impl Primitive {
15321535
let dl = cx.data_layout();
15331536

15341537
match self {
1538+
Bool => dl.i1_align,
15351539
Int(i, _) => i.align(dl),
15361540
Float(f) => f.align(dl),
15371541
Pointer(a) => dl.pointer_align_in(a),
@@ -1566,6 +1570,7 @@ impl fmt::Debug for Scalar {
15661570
match self {
15671571
Scalar::Initialized { value, valid_range } => {
15681572
let (size, is_signed) = match *value {
1573+
Primitive::Bool => (Size::from_bits(1), false),
15691574
Primitive::Int(integer, is_signed) => (integer.size(), is_signed),
15701575
Primitive::Float(float) => (float.size(), false),
15711576
Primitive::Pointer(_) => (Size::from_bits(128), false),
@@ -1582,11 +1587,10 @@ impl fmt::Debug for Scalar {
15821587
impl Scalar {
15831588
#[inline]
15841589
pub fn is_bool(&self) -> bool {
1585-
use Integer::*;
15861590
matches!(
15871591
self,
15881592
Scalar::Initialized {
1589-
value: Primitive::Int(I8, false),
1593+
value: Primitive::Bool,
15901594
valid_range: WrappingRange { start: 0, end: 1 }
15911595
}
15921596
)
@@ -2132,14 +2136,33 @@ impl Niche {
21322136
// In practice this means that enums with `count > 1` are unlikely to claim niche zero,
21332137
// since they have to fit perfectly. If niche zero is already reserved, the selection of
21342138
// bounds are of little interest.
2139+
//
2140+
// Because bools still have a size of 1 byte, we may need to potentially adjust the scalar
2141+
// here to compensate for reserving more space than the single bit. Niche reservation will
2142+
// never try to go larger than the in-memory size though, so it's always an adjustment
2143+
// bool -> u8.
21352144
let move_start = |v: WrappingRange| {
21362145
let start = v.start.wrapping_sub(count) & max_value;
2137-
Some((start, Scalar::Initialized { value, valid_range: v.with_start(start) }))
2146+
let valid_range = v.with_start(start);
2147+
let mut value = value;
2148+
if let Primitive::Bool = value
2149+
&& valid_range.end.wrapping_sub(valid_range.start) >= 2
2150+
{
2151+
value = Primitive::Int(Integer::I8, false);
2152+
}
2153+
Some((start, Scalar::Initialized { value, valid_range }))
21382154
};
21392155
let move_end = |v: WrappingRange| {
21402156
let start = v.end.wrapping_add(1) & max_value;
21412157
let end = v.end.wrapping_add(count) & max_value;
2142-
Some((start, Scalar::Initialized { value, valid_range: v.with_end(end) }))
2158+
let valid_range = v.with_end(end);
2159+
let mut value = value;
2160+
if let Primitive::Bool = value
2161+
&& valid_range.end.wrapping_sub(valid_range.start) >= 2
2162+
{
2163+
value = Primitive::Int(Integer::I8, false);
2164+
}
2165+
Some((start, Scalar::Initialized { value, valid_range }))
21432166
};
21442167
let distance_end_zero = max_value - v.end;
21452168
// FIXME: this ought to work for `bool` too, but that seems to be hitting a miscompilation

‎compiler/rustc_abi/src/wrapping_range.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ impl WrappingRange {
9999
}
100100

101101
/// The wrapping distance from `self.start` to `self.end`.
102-
fn width(&self, size: Size) -> u128 {
102+
pub fn width(&self, size: Size) -> u128 {
103103
size.truncate(u128::wrapping_sub(self.end, self.start))
104104
}
105105

‎compiler/rustc_codegen_cranelift/src/common.rs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ pub(crate) fn pointer_ty(tcx: TyCtxt<'_>) -> types::Type {
2626

2727
pub(crate) fn scalar_to_clif_type(tcx: TyCtxt<'_>, scalar: Scalar) -> Type {
2828
match scalar.primitive() {
29+
Primitive::Bool => types::I8,
2930
Primitive::Int(int, _sign) => match int {
3031
Integer::I8 => types::I8,
3132
Integer::I16 => types::I16,

‎compiler/rustc_codegen_gcc/src/type_of.rs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,7 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> {
267267
offset: Size,
268268
) -> Type<'gcc> {
269269
match scalar.primitive() {
270+
Bool => cx.type_u8(),
270271
Int(i, true) => cx.type_from_integer(i),
271272
Int(i, false) => cx.type_from_unsigned_integer(i),
272273
Float(f) => cx.type_from_float(f),

‎compiler/rustc_codegen_llvm/src/abi.rs‎

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ impl LlvmType for Reg {
153153
// But providing a more accurate type means fewer casts in LLVM IR,
154154
// which helps with optimization.
155155
let ty = match hint_vector_elem {
156+
Primitive::Bool => cx.type_i8(),
156157
Primitive::Int(integer, _) => match integer {
157158
Integer::I8 => cx.type_ix(8),
158159
Integer::I16 => cx.type_ix(16),
@@ -493,10 +494,6 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
493494
let apply_range_attr = |idx: AttributePlace, scalar: rustc_abi::Scalar| {
494495
if cx.sess().opts.optimize != config::OptLevel::No
495496
&& matches!(scalar.primitive(), Primitive::Int(..))
496-
// If the value is a boolean, the range is 0..2 and that ultimately
497-
// become 0..0 when the type becomes i1, which would be rejected
498-
// by the LLVM verifier.
499-
&& !scalar.is_bool()
500497
// LLVM also rejects full range.
501498
&& !scalar.is_always_valid(cx)
502499
{

‎compiler/rustc_codegen_llvm/src/builder.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -797,7 +797,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
797797
}
798798

799799
match scalar.primitive() {
800-
abi::Primitive::Int(..) => {
800+
abi::Primitive::Bool | abi::Primitive::Int(..) => {
801801
if !scalar.is_always_valid(bx) {
802802
bx.range_metadata(load, scalar.valid_range(bx));
803803
}

0 commit comments

Comments
 (0)