mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
IRGen: EmptyBoxType's representation cannot be nil because of a conflict with extra inhabitant assumption in indirect enums (#10326)
* IRGen: EmptyBoxType's representation cannot be nil because of a conflict with extra inhabitant assumption in indirect enums We map nil to the .None case of Optional. Instead use a singleton object. SR-5148 rdar://32618580
This commit is contained in:
committed by
GitHub
parent
6f3b8ca60f
commit
48e889b51b
@@ -71,6 +71,7 @@ Rename with a non-`stdlib` naming scheme.
|
|||||||
|
|
||||||
```
|
```
|
||||||
000000000001cb30 T _swift_allocBox
|
000000000001cb30 T _swift_allocBox
|
||||||
|
000000000001cb30 T _swift_allocEmptyBox
|
||||||
000000000001c990 T _swift_allocObject
|
000000000001c990 T _swift_allocObject
|
||||||
000000000001ca60 T _swift_bufferAllocate
|
000000000001ca60 T _swift_bufferAllocate
|
||||||
000000000001ca90 T _swift_bufferHeaderSize
|
000000000001ca90 T _swift_bufferHeaderSize
|
||||||
|
|||||||
@@ -169,6 +169,10 @@ SWIFT_RUNTIME_EXPORT
|
|||||||
BoxPair::Return swift_makeBoxUnique(OpaqueValue *buffer, Metadata const *type,
|
BoxPair::Return swift_makeBoxUnique(OpaqueValue *buffer, Metadata const *type,
|
||||||
size_t alignMask);
|
size_t alignMask);
|
||||||
|
|
||||||
|
/// Returns the address of a heap object representing all empty box types.
|
||||||
|
SWIFT_RUNTIME_EXPORT
|
||||||
|
HeapObject* swift_allocEmptyBox();
|
||||||
|
|
||||||
// Allocate plain old memory. This is the generalized entry point
|
// Allocate plain old memory. This is the generalized entry point
|
||||||
// Never returns nil. The returned memory is uninitialized.
|
// Never returns nil. The returned memory is uninitialized.
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -1761,6 +1761,9 @@ struct TargetHeapLocalVariableMetadata
|
|||||||
static bool classof(const TargetMetadata<Runtime> *metadata) {
|
static bool classof(const TargetMetadata<Runtime> *metadata) {
|
||||||
return metadata->getKind() == MetadataKind::HeapLocalVariable;
|
return metadata->getKind() == MetadataKind::HeapLocalVariable;
|
||||||
}
|
}
|
||||||
|
constexpr TargetHeapLocalVariableMetadata()
|
||||||
|
: TargetHeapMetadata<Runtime>(MetadataKind::HeapLocalVariable),
|
||||||
|
OffsetToFirstCapture(0), CaptureDescription(nullptr) {}
|
||||||
};
|
};
|
||||||
using HeapLocalVariableMetadata
|
using HeapLocalVariableMetadata
|
||||||
= TargetHeapLocalVariableMetadata<InProcess>;
|
= TargetHeapLocalVariableMetadata<InProcess>;
|
||||||
|
|||||||
@@ -73,6 +73,11 @@ FUNCTION(ProjectBox, swift_projectBox, DefaultCC,
|
|||||||
ARGS(RefCountedPtrTy),
|
ARGS(RefCountedPtrTy),
|
||||||
ATTRS(NoUnwind, ReadNone))
|
ATTRS(NoUnwind, ReadNone))
|
||||||
|
|
||||||
|
FUNCTION(AllocEmptyBox, swift_allocEmptyBox, DefaultCC,
|
||||||
|
RETURNS(RefCountedPtrTy),
|
||||||
|
ARGS(),
|
||||||
|
ATTRS(NoUnwind))
|
||||||
|
|
||||||
// RefCounted *swift_allocObject(Metadata *type, size_t size, size_t alignMask);
|
// RefCounted *swift_allocObject(Metadata *type, size_t size, size_t alignMask);
|
||||||
FUNCTION_WITH_GLOBAL_SYMBOL_AND_IMPL(AllocObject, swift_allocObject,
|
FUNCTION_WITH_GLOBAL_SYMBOL_AND_IMPL(AllocObject, swift_allocObject,
|
||||||
_swift_allocObject, _swift_allocObject_, RegisterPreservingCC,
|
_swift_allocObject, _swift_allocObject_, RegisterPreservingCC,
|
||||||
|
|||||||
@@ -1430,7 +1430,7 @@ public:
|
|||||||
allocate(IRGenFunction &IGF, SILType boxedType, GenericEnvironment *env,
|
allocate(IRGenFunction &IGF, SILType boxedType, GenericEnvironment *env,
|
||||||
const llvm::Twine &name) const override {
|
const llvm::Twine &name) const override {
|
||||||
return OwnedAddress(IGF.getTypeInfo(boxedType).getUndefAddress(),
|
return OwnedAddress(IGF.getTypeInfo(boxedType).getUndefAddress(),
|
||||||
IGF.IGM.RefCountedNull);
|
IGF.emitAllocEmptyBoxCall());
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -1584,7 +1584,11 @@ const TypeInfo *TypeConverter::convertBoxType(SILBoxType *T) {
|
|||||||
// For fixed-sized types, we can emit concrete box metadata.
|
// For fixed-sized types, we can emit concrete box metadata.
|
||||||
auto &fixedTI = cast<FixedTypeInfo>(eltTI);
|
auto &fixedTI = cast<FixedTypeInfo>(eltTI);
|
||||||
|
|
||||||
// For empty types, we don't really need to allocate anything.
|
// Because we assume in enum's that payloads with a Builtin.NativeObject which
|
||||||
|
// is also the type for indirect enum cases have extra inhabitants of pointers
|
||||||
|
// we can't have a nil pointer as a representation for an empty box type --
|
||||||
|
// nil conflicts with the extra inhabitants. We return a static singleton
|
||||||
|
// empty box object instead.
|
||||||
if (fixedTI.isKnownEmpty(ResilienceExpansion::Maximal)) {
|
if (fixedTI.isKnownEmpty(ResilienceExpansion::Maximal)) {
|
||||||
if (!EmptyBoxTI)
|
if (!EmptyBoxTI)
|
||||||
EmptyBoxTI = new EmptyBoxTypeInfo(IGM);
|
EmptyBoxTI = new EmptyBoxTypeInfo(IGM);
|
||||||
|
|||||||
@@ -209,6 +209,20 @@ llvm::Value *IRGenFunction::emitProjectBoxCall(llvm::Value *box,
|
|||||||
return call;
|
return call;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
llvm::Value *IRGenFunction::emitAllocEmptyBoxCall() {
|
||||||
|
llvm::Attribute::AttrKind attrKinds[] = {
|
||||||
|
llvm::Attribute::NoUnwind,
|
||||||
|
};
|
||||||
|
auto attrs = llvm::AttributeSet::get(IGM.LLVMContext,
|
||||||
|
llvm::AttributeSet::FunctionIndex,
|
||||||
|
attrKinds);
|
||||||
|
llvm::CallInst *call =
|
||||||
|
Builder.CreateCall(IGM.getAllocEmptyBoxFn(), {});
|
||||||
|
call->setCallingConv(IGM.DefaultCC);
|
||||||
|
call->setAttributes(attrs);
|
||||||
|
return call;
|
||||||
|
}
|
||||||
|
|
||||||
static void emitDeallocatingCall(IRGenFunction &IGF, llvm::Constant *fn,
|
static void emitDeallocatingCall(IRGenFunction &IGF, llvm::Constant *fn,
|
||||||
std::initializer_list<llvm::Value *> args) {
|
std::initializer_list<llvm::Value *> args) {
|
||||||
auto cc = IGF.IGM.DefaultCC;
|
auto cc = IGF.IGM.DefaultCC;
|
||||||
|
|||||||
@@ -188,6 +188,8 @@ public:
|
|||||||
|
|
||||||
llvm::Value *emitProjectBoxCall(llvm::Value *box, llvm::Value *typeMetadata);
|
llvm::Value *emitProjectBoxCall(llvm::Value *box, llvm::Value *typeMetadata);
|
||||||
|
|
||||||
|
llvm::Value *emitAllocEmptyBoxCall();
|
||||||
|
|
||||||
// Emit a reference to the canonical type metadata record for the given AST
|
// Emit a reference to the canonical type metadata record for the given AST
|
||||||
// type. This can be used to identify the type at runtime. For types with
|
// type. This can be used to identify the type at runtime. For types with
|
||||||
// abstraction difference, the metadata contains the layout information for
|
// abstraction difference, the metadata contains the layout information for
|
||||||
|
|||||||
@@ -88,6 +88,13 @@ struct _SwiftHashingSecretKey _swift_stdlib_Hashing_secretKey;
|
|||||||
SWIFT_RUNTIME_STDLIB_INTERFACE
|
SWIFT_RUNTIME_STDLIB_INTERFACE
|
||||||
__swift_uint64_t _swift_stdlib_HashingDetail_fixedSeedOverride;
|
__swift_uint64_t _swift_stdlib_HashingDetail_fixedSeedOverride;
|
||||||
|
|
||||||
|
struct _SwiftEmptyBoxStorage {
|
||||||
|
struct HeapObject header;
|
||||||
|
};
|
||||||
|
|
||||||
|
SWIFT_RUNTIME_STDLIB_INTERFACE
|
||||||
|
struct _SwiftEmptyBoxStorage _EmptyBoxStorage;
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
||||||
static_assert(std::is_pod<_SwiftEmptyArrayStorage>::value,
|
static_assert(std::is_pod<_SwiftEmptyArrayStorage>::value,
|
||||||
|
|||||||
@@ -31,6 +31,7 @@
|
|||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
#include "../SwiftShims/GlobalObjects.h"
|
||||||
#include "../SwiftShims/RuntimeShims.h"
|
#include "../SwiftShims/RuntimeShims.h"
|
||||||
#if SWIFT_OBJC_INTEROP
|
#if SWIFT_OBJC_INTEROP
|
||||||
# include <objc/NSObject.h>
|
# include <objc/NSObject.h>
|
||||||
@@ -227,6 +228,12 @@ OpaqueValue *swift::swift_projectBox(HeapObject *o) {
|
|||||||
return metadata->project(o);
|
return metadata->project(o);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HeapObject *swift::swift_allocEmptyBox() {
|
||||||
|
auto heapObject = reinterpret_cast<HeapObject*>(&_EmptyBoxStorage);
|
||||||
|
SWIFT_RT_ENTRY_CALL(swift_retain)(heapObject);
|
||||||
|
return heapObject;
|
||||||
|
}
|
||||||
|
|
||||||
// Forward-declare this, but define it after swift_release.
|
// Forward-declare this, but define it after swift_release.
|
||||||
extern "C" LLVM_LIBRARY_VISIBILITY LLVM_ATTRIBUTE_NOINLINE LLVM_ATTRIBUTE_USED
|
extern "C" LLVM_LIBRARY_VISIBILITY LLVM_ATTRIBUTE_NOINLINE LLVM_ATTRIBUTE_USED
|
||||||
void _swift_release_dealloc(HeapObject *object) SWIFT_CC(RegisterPreservingCC_IMPL);
|
void _swift_release_dealloc(HeapObject *object) SWIFT_CC(RegisterPreservingCC_IMPL);
|
||||||
|
|||||||
@@ -35,6 +35,10 @@ ClassMetadata CLASS_METADATA_SYM(s27_RawNativeDictionaryStorage);
|
|||||||
// _direct type metadata for Swift._RawNativeSetStorage
|
// _direct type metadata for Swift._RawNativeSetStorage
|
||||||
SWIFT_RUNTIME_STDLIB_INTERFACE
|
SWIFT_RUNTIME_STDLIB_INTERFACE
|
||||||
ClassMetadata CLASS_METADATA_SYM(s20_RawNativeSetStorage);
|
ClassMetadata CLASS_METADATA_SYM(s20_RawNativeSetStorage);
|
||||||
|
|
||||||
|
// _direct type metadata for Swift._EmptyBoxStorage
|
||||||
|
SWIFT_RUNTIME_STDLIB_INTERFACE
|
||||||
|
ClassMetadata CLASS_METADATA_SYM(s16_EmptyBoxStorage);
|
||||||
} // namespace swift
|
} // namespace swift
|
||||||
|
|
||||||
swift::_SwiftEmptyArrayStorage swift::_swiftEmptyArrayStorage = {
|
swift::_SwiftEmptyArrayStorage swift::_swiftEmptyArrayStorage = {
|
||||||
@@ -127,6 +131,18 @@ void swift::_swift_instantiateInertHeapObject(void *address,
|
|||||||
::new (address) HeapObject{metadata};
|
::new (address) HeapObject{metadata};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
swift::HeapLocalVariableMetadata _emptyBoxStorageMetadata;
|
||||||
|
|
||||||
|
/// The signleton empty box storage object.
|
||||||
|
swift::_SwiftEmptyBoxStorage swift::_EmptyBoxStorage = {
|
||||||
|
// HeapObject header;
|
||||||
|
{
|
||||||
|
&_emptyBoxStorageMetadata,
|
||||||
|
//&swift::CLASS_METADATA_SYM(s16_EmptyBoxStorage), // isa pointer
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
namespace llvm { namespace hashing { namespace detail {
|
namespace llvm { namespace hashing { namespace detail {
|
||||||
// An extern variable expected by LLVM's hashing templates. We don't link any
|
// An extern variable expected by LLVM's hashing templates. We don't link any
|
||||||
// LLVM libs into the runtime, so define this here.
|
// LLVM libs into the runtime, so define this here.
|
||||||
|
|||||||
@@ -114,8 +114,7 @@ sil @testPairedBox : $(@guaranteed { var () }) -> () {
|
|||||||
bb0(%0 : ${ var () }):
|
bb0(%0 : ${ var () }):
|
||||||
// CHECK: entry:
|
// CHECK: entry:
|
||||||
%2 = project_box %0 : ${ var () }, 0
|
%2 = project_box %0 : ${ var () }, 0
|
||||||
|
// CHECK-NEXT: call {{.*}}void @writeEmptyTuple(%swift.opaque* nocapture undef)
|
||||||
// CHECK-NEXT: call {{.*}}void @writeEmptyTuple(%swift.opaque* nocapture undef)
|
|
||||||
%3 = begin_access [modify] [dynamic] %2 : $*()
|
%3 = begin_access [modify] [dynamic] %2 : $*()
|
||||||
%write_fn = function_ref @writeEmptyTuple : $@convention(thin) (@inout ()) -> ()
|
%write_fn = function_ref @writeEmptyTuple : $@convention(thin) (@inout ()) -> ()
|
||||||
apply %write_fn(%3) : $@convention(thin) (@inout ()) -> ()
|
apply %write_fn(%3) : $@convention(thin) (@inout ()) -> ()
|
||||||
|
|||||||
@@ -365,7 +365,8 @@ sil public_external @partial_empty_box : $@convention(thin) (@owned <τ_0_0> { v
|
|||||||
// CHECK-LABEL: define{{( protected)?}} swiftcc void @empty_box()
|
// CHECK-LABEL: define{{( protected)?}} swiftcc void @empty_box()
|
||||||
sil @empty_box : $@convention(thin) () -> () {
|
sil @empty_box : $@convention(thin) () -> () {
|
||||||
entry:
|
entry:
|
||||||
// CHECK: store %swift.refcounted* null
|
// CHECK: [[BOX:%.*]] = call {{.*}}swift_allocEmptyBox
|
||||||
|
// CHECK: store %swift.refcounted* [[BOX]]
|
||||||
// CHECK: store %swift.opaque* undef
|
// CHECK: store %swift.opaque* undef
|
||||||
%b = alloc_box $<τ_0_0> { var τ_0_0 } <()>
|
%b = alloc_box $<τ_0_0> { var τ_0_0 } <()>
|
||||||
%ba = project_box %b : $<τ_0_0> { var τ_0_0 } <()>, 0
|
%ba = project_box %b : $<τ_0_0> { var τ_0_0 } <()>, 0
|
||||||
|
|||||||
@@ -553,5 +553,50 @@ presentEitherOr(EitherOr<(), String>.Right("foo")) // CHECK-NEXT: Right(foo)
|
|||||||
// CHECK-NEXT: Right(foo)
|
// CHECK-NEXT: Right(foo)
|
||||||
presentEitherOrsOf(t: (), u: "foo")
|
presentEitherOrsOf(t: (), u: "foo")
|
||||||
|
|
||||||
|
// SR-5148
|
||||||
|
enum Payload {
|
||||||
|
case email
|
||||||
|
}
|
||||||
|
enum Test {
|
||||||
|
case a
|
||||||
|
indirect case b(Payload)
|
||||||
|
}
|
||||||
|
|
||||||
|
@inline(never)
|
||||||
|
func printA() {
|
||||||
|
print("an a")
|
||||||
|
}
|
||||||
|
|
||||||
|
@inline(never)
|
||||||
|
func printB() {
|
||||||
|
print("an b")
|
||||||
|
}
|
||||||
|
|
||||||
|
@inline(never)
|
||||||
|
func testCase(_ testEmail: Test) {
|
||||||
|
switch testEmail {
|
||||||
|
case .a:
|
||||||
|
printA()
|
||||||
|
case .b:
|
||||||
|
printB()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@inline(never)
|
||||||
|
func createTestB() -> Test {
|
||||||
|
return Test.b(.email)
|
||||||
|
}
|
||||||
|
|
||||||
|
@inline(never)
|
||||||
|
func createTestA() -> Test {
|
||||||
|
return Test.a
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-NEXT: an b
|
||||||
|
testCase(createTestB())
|
||||||
|
// CHECK-NEXT: b(a.Payload.email)
|
||||||
|
print(createTestB())
|
||||||
|
// CHECK-NEXT: a
|
||||||
|
print(createTestA())
|
||||||
// CHECK-NEXT: done
|
// CHECK-NEXT: done
|
||||||
print("done")
|
print("done")
|
||||||
|
|||||||
Reference in New Issue
Block a user