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_allocEmptyBox
|
||||
000000000001c990 T _swift_allocObject
|
||||
000000000001ca60 T _swift_bufferAllocate
|
||||
000000000001ca90 T _swift_bufferHeaderSize
|
||||
|
||||
@@ -169,6 +169,10 @@ SWIFT_RUNTIME_EXPORT
|
||||
BoxPair::Return swift_makeBoxUnique(OpaqueValue *buffer, Metadata const *type,
|
||||
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
|
||||
// Never returns nil. The returned memory is uninitialized.
|
||||
//
|
||||
|
||||
@@ -1761,6 +1761,9 @@ struct TargetHeapLocalVariableMetadata
|
||||
static bool classof(const TargetMetadata<Runtime> *metadata) {
|
||||
return metadata->getKind() == MetadataKind::HeapLocalVariable;
|
||||
}
|
||||
constexpr TargetHeapLocalVariableMetadata()
|
||||
: TargetHeapMetadata<Runtime>(MetadataKind::HeapLocalVariable),
|
||||
OffsetToFirstCapture(0), CaptureDescription(nullptr) {}
|
||||
};
|
||||
using HeapLocalVariableMetadata
|
||||
= TargetHeapLocalVariableMetadata<InProcess>;
|
||||
|
||||
@@ -73,6 +73,11 @@ FUNCTION(ProjectBox, swift_projectBox, DefaultCC,
|
||||
ARGS(RefCountedPtrTy),
|
||||
ATTRS(NoUnwind, ReadNone))
|
||||
|
||||
FUNCTION(AllocEmptyBox, swift_allocEmptyBox, DefaultCC,
|
||||
RETURNS(RefCountedPtrTy),
|
||||
ARGS(),
|
||||
ATTRS(NoUnwind))
|
||||
|
||||
// RefCounted *swift_allocObject(Metadata *type, size_t size, size_t alignMask);
|
||||
FUNCTION_WITH_GLOBAL_SYMBOL_AND_IMPL(AllocObject, swift_allocObject,
|
||||
_swift_allocObject, _swift_allocObject_, RegisterPreservingCC,
|
||||
|
||||
@@ -1430,7 +1430,7 @@ public:
|
||||
allocate(IRGenFunction &IGF, SILType boxedType, GenericEnvironment *env,
|
||||
const llvm::Twine &name) const override {
|
||||
return OwnedAddress(IGF.getTypeInfo(boxedType).getUndefAddress(),
|
||||
IGF.IGM.RefCountedNull);
|
||||
IGF.emitAllocEmptyBoxCall());
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1584,7 +1584,11 @@ const TypeInfo *TypeConverter::convertBoxType(SILBoxType *T) {
|
||||
// For fixed-sized types, we can emit concrete box metadata.
|
||||
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 (!EmptyBoxTI)
|
||||
EmptyBoxTI = new EmptyBoxTypeInfo(IGM);
|
||||
|
||||
@@ -209,6 +209,20 @@ llvm::Value *IRGenFunction::emitProjectBoxCall(llvm::Value *box,
|
||||
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,
|
||||
std::initializer_list<llvm::Value *> args) {
|
||||
auto cc = IGF.IGM.DefaultCC;
|
||||
|
||||
@@ -188,6 +188,8 @@ public:
|
||||
|
||||
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
|
||||
// type. This can be used to identify the type at runtime. For types with
|
||||
// abstraction difference, the metadata contains the layout information for
|
||||
|
||||
@@ -88,6 +88,13 @@ struct _SwiftHashingSecretKey _swift_stdlib_Hashing_secretKey;
|
||||
SWIFT_RUNTIME_STDLIB_INTERFACE
|
||||
__swift_uint64_t _swift_stdlib_HashingDetail_fixedSeedOverride;
|
||||
|
||||
struct _SwiftEmptyBoxStorage {
|
||||
struct HeapObject header;
|
||||
};
|
||||
|
||||
SWIFT_RUNTIME_STDLIB_INTERFACE
|
||||
struct _SwiftEmptyBoxStorage _EmptyBoxStorage;
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
static_assert(std::is_pod<_SwiftEmptyArrayStorage>::value,
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <thread>
|
||||
#include "../SwiftShims/GlobalObjects.h"
|
||||
#include "../SwiftShims/RuntimeShims.h"
|
||||
#if SWIFT_OBJC_INTEROP
|
||||
# include <objc/NSObject.h>
|
||||
@@ -227,6 +228,12 @@ OpaqueValue *swift::swift_projectBox(HeapObject *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.
|
||||
extern "C" LLVM_LIBRARY_VISIBILITY LLVM_ATTRIBUTE_NOINLINE LLVM_ATTRIBUTE_USED
|
||||
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
|
||||
SWIFT_RUNTIME_STDLIB_INTERFACE
|
||||
ClassMetadata CLASS_METADATA_SYM(s20_RawNativeSetStorage);
|
||||
|
||||
// _direct type metadata for Swift._EmptyBoxStorage
|
||||
SWIFT_RUNTIME_STDLIB_INTERFACE
|
||||
ClassMetadata CLASS_METADATA_SYM(s16_EmptyBoxStorage);
|
||||
} // namespace swift
|
||||
|
||||
swift::_SwiftEmptyArrayStorage swift::_swiftEmptyArrayStorage = {
|
||||
@@ -127,6 +131,18 @@ void swift::_swift_instantiateInertHeapObject(void *address,
|
||||
::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 {
|
||||
// An extern variable expected by LLVM's hashing templates. We don't link any
|
||||
// LLVM libs into the runtime, so define this here.
|
||||
|
||||
@@ -114,7 +114,6 @@ sil @testPairedBox : $(@guaranteed { var () }) -> () {
|
||||
bb0(%0 : ${ var () }):
|
||||
// CHECK: entry:
|
||||
%2 = project_box %0 : ${ var () }, 0
|
||||
|
||||
// CHECK-NEXT: call {{.*}}void @writeEmptyTuple(%swift.opaque* nocapture undef)
|
||||
%3 = begin_access [modify] [dynamic] %2 : $*()
|
||||
%write_fn = function_ref @writeEmptyTuple : $@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()
|
||||
sil @empty_box : $@convention(thin) () -> () {
|
||||
entry:
|
||||
// CHECK: store %swift.refcounted* null
|
||||
// CHECK: [[BOX:%.*]] = call {{.*}}swift_allocEmptyBox
|
||||
// CHECK: store %swift.refcounted* [[BOX]]
|
||||
// CHECK: store %swift.opaque* undef
|
||||
%b = alloc_box $<τ_0_0> { var τ_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)
|
||||
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
|
||||
print("done")
|
||||
|
||||
Reference in New Issue
Block a user