Skip to content

Commit 649961e

Browse files
committed
IRGen: Mask all spare bits in multi-payload enums when injecting the tag.
Single-payload enum layout unfortunately assumes that constructing the payload case is a no-op, such as when building Optional.some(x) for a value x. For multi-payload enums, now that we use the unused spare bits to form extra inhabitants when the enum is in turn wrapped in an Optional or other single- payload enum, this means we have to zero all of those bits. The spare bits may have been selected from intra-field or tail padding bytes that are undefined in the underlying payload types. Fixes rdar://problem/47635801.
1 parent 77d1c02 commit 649961e

File tree

2 files changed

+12
-4
lines changed

2 files changed

+12
-4
lines changed

lib/IRGen/GenEnum.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4785,7 +4785,11 @@ namespace {
47854785
Address payloadAddr = projectPayload(IGF, enumAddr);
47864786
auto payload = EnumPayload::load(IGF, payloadAddr, PayloadSchema);
47874787

4788-
auto spareBitMask = ~PayloadTagBits.asAPInt();
4788+
// We need to mask not only the payload tag bits, but all spare bits,
4789+
// because the other spare bits may be used to tag a single-payload
4790+
// enum containing this enum as a payload. Single payload layout
4791+
// unfortunately assumes that tagging the payload case is a no-op.
4792+
auto spareBitMask = ~CommonSpareBits.asAPInt();
47894793
APInt tagBitMask
47904794
= interleaveSpareBits(IGF.IGM, PayloadTagBits, PayloadTagBits.size(),
47914795
spareTagBits, 0);
@@ -4823,7 +4827,11 @@ namespace {
48234827
auto payload = EnumPayload::load(IGF, payloadAddr, PayloadSchema);
48244828

48254829
// Mask off the spare bits.
4826-
auto spareBitMask = ~PayloadTagBits.asAPInt();
4830+
// We need to mask not only the payload tag bits, but all spare bits,
4831+
// because the other spare bits may be used to tag a single-payload
4832+
// enum containing this enum as a payload. Single payload layout
4833+
// unfortunately assumes that tagging the payload case is a no-op.
4834+
auto spareBitMask = ~CommonSpareBits.asAPInt();
48274835
payload.emitApplyAndMask(IGF, spareBitMask);
48284836

48294837
// Store the tag into the spare bits.

test/IRGen/enum_value_semantics.sil

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -570,8 +570,8 @@ bb0(%0 : $SinglePayloadNontrivial):
570570
// CHECK-NEXT: [[SECOND_ADDR:%.*]] = getelementptr inbounds { i64, i64 }, { i64, i64 }* [[PAYLOAD]], i32 0, i32 1
571571
// CHECK-NEXT: [[SECOND:%.*]] = load i64, i64* [[SECOND_ADDR]], align 8
572572

573-
// -- Mask off spare bits in the payload -- 0x3fffffffffffffff
574-
// CHECK-NEXT: [[SECOND_PROJ:%.*]] = and i64 [[SECOND]], 4611686018427387903
573+
// -- Mask off spare bits in the payload -- 0x00fffffffffffff8
574+
// CHECK-NEXT: [[SECOND_PROJ:%.*]] = and i64 [[SECOND]], 72057594037927928
575575

576576
// -- Store the low bits of the tag in the spare bits of the payload
577577
// CHECK-NEXT: [[TAG:%.*]] = zext i32 [[TAG_TMP]] to i64

0 commit comments

Comments
 (0)