[Clang importer] Allow noncopyable C structs to define "destroy" operation

A C struct can be imported as noncopyable, but C doesn't have
destructors, so there is no way to provide user-defined logic to
perform the destruction. Introduce a new swift_attr that applies to
imported noncopyable types and which provides such a "destroy"
operation. It can be used like this:

    typedef struct __attribute__((swift_attr("~Copyable")))
                   __attribute__((swift_attr("destroy:wgpuAdapterInfoFreeMembers")))
      WGPUAdapterInfo { /*...*/ } WGPUAdapterInfo;

    void wgpuAdapterInfoFreeMembers(WGPUAdapterInfo adapterInfo);

This will bring the WGPUAdapterInfo struct in as a noncopyable type
that will be cleaned up by calling wgpuAdapterInfoFreeMembers once it
is no longer in use.

Implements rdar://156889370.
This commit is contained in:
Doug Gregor
2025-07-28 00:02:31 -07:00
parent 21b9b9f713
commit 6ba560fb4b
9 changed files with 198 additions and 18 deletions

View File

@@ -374,12 +374,14 @@ namespace {
unsigned explosionSize, llvm::Type *storageType,
Size size, SpareBitVector &&spareBits,
Alignment align,
IsTriviallyDestroyable_t isTriviallyDestroyable,
IsCopyable_t isCopyable,
const clang::RecordDecl *clangDecl)
: StructTypeInfoBase(StructTypeInfoKind::LoadableClangRecordTypeInfo,
fields, explosionSize, FieldsAreABIAccessible,
storageType, size, std::move(spareBits), align,
IsTriviallyDestroyable,
IsCopyable,
isTriviallyDestroyable,
isCopyable,
IsFixedSize, IsABIAccessible),
ClangDecl(clangDecl) {}
@@ -469,6 +471,7 @@ namespace {
AddressOnlyPointerAuthRecordTypeInfo(ArrayRef<ClangFieldInfo> fields,
llvm::Type *storageType, Size size,
Alignment align,
IsCopyable_t isCopyable,
const clang::RecordDecl *clangDecl)
: StructTypeInfoBase(StructTypeInfoKind::AddressOnlyClangRecordTypeInfo,
fields, FieldsAreABIAccessible, storageType, size,
@@ -477,7 +480,7 @@ namespace {
SpareBitVector(std::optional<APInt>{
llvm::APInt(size.getValueInBits(), 0)}),
align, IsNotTriviallyDestroyable,
IsNotBitwiseTakable, IsCopyable, IsFixedSize,
IsNotBitwiseTakable, isCopyable, IsFixedSize,
IsABIAccessible),
clangDecl(clangDecl) {
(void)clangDecl;
@@ -645,6 +648,7 @@ namespace {
AddressOnlyCXXClangRecordTypeInfo(ArrayRef<ClangFieldInfo> fields,
llvm::Type *storageType, Size size,
Alignment align,
IsCopyable_t isCopyable,
const clang::RecordDecl *clangDecl)
: StructTypeInfoBase(StructTypeInfoKind::AddressOnlyClangRecordTypeInfo,
fields, FieldsAreABIAccessible, storageType, size,
@@ -654,9 +658,7 @@ namespace {
llvm::APInt(size.getValueInBits(), 0)}),
align, IsNotTriviallyDestroyable,
IsNotBitwiseTakable,
// TODO: Set this appropriately for the type's
// C++ import behavior.
IsCopyable, IsFixedSize, IsABIAccessible),
isCopyable, IsFixedSize, IsABIAccessible),
ClangDecl(clangDecl) {
(void)ClangDecl;
}
@@ -1342,15 +1344,26 @@ public:
llvmType->setBody(LLVMFields, /*packed*/ true);
if (SwiftType.getStructOrBoundGenericStruct()->isCxxNonTrivial()) {
return AddressOnlyCXXClangRecordTypeInfo::create(
FieldInfos, llvmType, TotalStride, TotalAlignment, ClangDecl);
FieldInfos, llvmType, TotalStride, TotalAlignment,
(SwiftDecl && !SwiftDecl->canBeCopyable())
? IsNotCopyable : IsCopyable,
ClangDecl);
}
if (SwiftType.getStructOrBoundGenericStruct()->isNonTrivialPtrAuth()) {
return AddressOnlyPointerAuthRecordTypeInfo::create(
FieldInfos, llvmType, TotalStride, TotalAlignment, ClangDecl);
FieldInfos, llvmType, TotalStride, TotalAlignment,
(SwiftDecl && !SwiftDecl->canBeCopyable())
? IsNotCopyable : IsCopyable,
ClangDecl);
}
return LoadableClangRecordTypeInfo::create(
FieldInfos, NextExplosionIndex, llvmType, TotalStride,
std::move(SpareBits), TotalAlignment, ClangDecl);
std::move(SpareBits), TotalAlignment,
(SwiftDecl && SwiftDecl->getValueTypeDestructor())
? IsNotTriviallyDestroyable : IsTriviallyDestroyable,
(SwiftDecl && !SwiftDecl->canBeCopyable())
? IsNotCopyable : IsCopyable,
ClangDecl);
}
private: