Files
swift-mirror/test/Interop/Cxx/foreign-reference/Inputs/reference-counted.h
Egor Zhdan bd6da5dc64 [cxx-interop][IRGen] Do not try to retain/release a null pointer
This teaches IRGen to only emit a lifetime operation (retain or release) for a C++ foreign reference type if the pointer is not `nullptr`.

Previously the compiler would in some cases emit a release call for `nullptr`, which breaks the assumption that the argument to a custom release function is `_Nonnull`. For instance:
```
var globalOptional: MyRefType? = nil
func foo() { globalOptional = MyRefType.create() }
```
When emitting IR for the assignment operation to `globalOptional`, the compiler would emit code to first retrieve the existing value of `globalOptional` and release it. If the value is `nil`, it does not need to be released.

rdar://97532642
2024-05-07 20:20:45 +01:00

67 lines
1.8 KiB
C++

#ifndef TEST_INTEROP_CXX_FOREIGN_REFERENCE_INPUTS_REFERENCE_COUNTED_H
#define TEST_INTEROP_CXX_FOREIGN_REFERENCE_INPUTS_REFERENCE_COUNTED_H
#include <stdlib.h>
#include <new>
#include "visibility.h"
SWIFT_BEGIN_NULLABILITY_ANNOTATIONS
static int finalLocalRefCount = 100;
namespace NS {
struct __attribute__((swift_attr("import_as_ref")))
__attribute__((swift_attr("retain:LCRetain")))
__attribute__((swift_attr("release:LCRelease"))) LocalCount {
int value = 0;
static LocalCount *create() {
return new (malloc(sizeof(LocalCount))) LocalCount();
}
int returns42() { return 42; }
int constMethod() const { return 42; }
};
}
inline void LCRetain(NS::LocalCount *x) { x->value++; }
inline void LCRelease(NS::LocalCount *x) {
x->value--;
finalLocalRefCount = x->value;
}
static int globalCount = 0;
struct __attribute__((swift_attr("import_as_ref")))
__attribute__((swift_attr("retain:GCRetain")))
__attribute__((swift_attr("release:GCRelease"))) GlobalCount {
static GlobalCount *create() {
return new (malloc(sizeof(GlobalCount))) GlobalCount();
}
};
inline void GCRetain(GlobalCount *x) { globalCount++; }
inline void GCRelease(GlobalCount *x) { globalCount--; }
struct __attribute__((swift_attr("import_as_ref")))
__attribute__((swift_attr("retain:GCRetainNullableInit")))
__attribute__((swift_attr("release:GCReleaseNullableInit")))
GlobalCountNullableInit {
static GlobalCountNullableInit *_Nullable create(bool wantNullptr) {
if (wantNullptr)
return nullptr;
return new (malloc(sizeof(GlobalCountNullableInit)))
GlobalCountNullableInit();
}
};
inline void GCRetainNullableInit(GlobalCountNullableInit *x) { globalCount++; }
inline void GCReleaseNullableInit(GlobalCountNullableInit *x) { globalCount--; }
SWIFT_END_NULLABILITY_ANNOTATIONS
#endif // TEST_INTEROP_CXX_FOREIGN_REFERENCE_INPUTS_REFERENCE_COUNTED_H