[clang] ae90b60 - [APINotes] Add SwiftDestroyOp API note to map to the "destroy" function (#153261)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Aug 15 00:02:17 PDT 2025
Author: Doug Gregor
Date: 2025-08-15T08:02:14+01:00
New Revision: ae90b60fc8661956250a0b8185be37e8fb92c0d7
URL: https://github.com/llvm/llvm-project/commit/ae90b60fc8661956250a0b8185be37e8fb92c0d7
DIFF: https://github.com/llvm/llvm-project/commit/ae90b60fc8661956250a0b8185be37e8fb92c0d7.diff
LOG: [APINotes] Add SwiftDestroyOp API note to map to the "destroy" function (#153261)
Like retain/release for reference types, "destroy" lets us specify an
operation that is used to deinitialize an instance of a noncopyable
type.
Added:
Modified:
clang/docs/APINotes.rst
clang/include/clang/APINotes/Types.h
clang/lib/APINotes/APINotesFormat.h
clang/lib/APINotes/APINotesReader.cpp
clang/lib/APINotes/APINotesWriter.cpp
clang/lib/APINotes/APINotesYAMLCompiler.cpp
clang/lib/Sema/SemaAPINotes.cpp
clang/test/APINotes/Inputs/Headers/SwiftImportAs.apinotes
clang/test/APINotes/Inputs/Headers/SwiftImportAs.h
clang/test/APINotes/swift-import-as.cpp
Removed:
################################################################################
diff --git a/clang/docs/APINotes.rst b/clang/docs/APINotes.rst
index e5ec154237b0d..dec4b186ff72f 100644
--- a/clang/docs/APINotes.rst
+++ b/clang/docs/APINotes.rst
@@ -206,6 +206,17 @@ declaration kind), all of which are optional:
- Name: tzdb
SwiftCopyable: false
+ A non-copyable type can have a "destroy" operation, specified with
+ `SwiftDestroyOp`, which will be invoked on the instance when it is no
+ longer in use to free up resources.
+
+ ::
+
+ Tags:
+ - Name: WGPUAdapterInfo
+ SwiftCopyable: false
+ SwiftDestroyOp: wgpuAdapterInfoFreeMembers
+
:SwiftConformsTo:
Allows annotating a C++ class as conforming to a Swift protocol. Equivalent
diff --git a/clang/include/clang/APINotes/Types.h b/clang/include/clang/APINotes/Types.h
index 8708b4b092f28..71625715bda19 100644
--- a/clang/include/clang/APINotes/Types.h
+++ b/clang/include/clang/APINotes/Types.h
@@ -751,6 +751,7 @@ class TagInfo : public CommonTypeInfo {
std::optional<std::string> SwiftImportAs;
std::optional<std::string> SwiftRetainOp;
std::optional<std::string> SwiftReleaseOp;
+ std::optional<std::string> SwiftDestroyOp;
std::optional<std::string> SwiftDefaultOwnership;
std::optional<EnumExtensibilityKind> EnumExtensibility;
@@ -798,6 +799,8 @@ class TagInfo : public CommonTypeInfo {
SwiftRetainOp = RHS.SwiftRetainOp;
if (!SwiftReleaseOp)
SwiftReleaseOp = RHS.SwiftReleaseOp;
+ if (!SwiftDestroyOp)
+ SwiftDestroyOp = RHS.SwiftDestroyOp;
if (!SwiftDefaultOwnership)
SwiftDefaultOwnership = RHS.SwiftDefaultOwnership;
@@ -826,6 +829,7 @@ inline bool operator==(const TagInfo &LHS, const TagInfo &RHS) {
LHS.SwiftImportAs == RHS.SwiftImportAs &&
LHS.SwiftRetainOp == RHS.SwiftRetainOp &&
LHS.SwiftReleaseOp == RHS.SwiftReleaseOp &&
+ LHS.SwiftDestroyOp == RHS.SwiftDestroyOp &&
LHS.SwiftDefaultOwnership == RHS.SwiftDefaultOwnership &&
LHS.isFlagEnum() == RHS.isFlagEnum() &&
LHS.isSwiftCopyable() == RHS.isSwiftCopyable() &&
diff --git a/clang/lib/APINotes/APINotesFormat.h b/clang/lib/APINotes/APINotesFormat.h
index 1ac486a2dd94c..69d180e7b3eb5 100644
--- a/clang/lib/APINotes/APINotesFormat.h
+++ b/clang/lib/APINotes/APINotesFormat.h
@@ -24,7 +24,7 @@ const uint16_t VERSION_MAJOR = 0;
/// API notes file minor version number.
///
/// When the format changes IN ANY WAY, this number should be incremented.
-const uint16_t VERSION_MINOR = 36; // Typedef SwiftConformsTo
+const uint16_t VERSION_MINOR = 37; // SwiftDestroyOp
const uint8_t kSwiftConforms = 1;
const uint8_t kSwiftDoesNotConform = 2;
diff --git a/clang/lib/APINotes/APINotesReader.cpp b/clang/lib/APINotes/APINotesReader.cpp
index 8b3812613b166..573356f97ff73 100644
--- a/clang/lib/APINotes/APINotesReader.cpp
+++ b/clang/lib/APINotes/APINotesReader.cpp
@@ -636,6 +636,13 @@ class TagTableInfo
reinterpret_cast<const char *>(Data), DefaultOwnershipLength - 1);
Data += DefaultOwnershipLength - 1;
}
+ unsigned DestroyOpLength =
+ endian::readNext<uint16_t, llvm::endianness::little>(Data);
+ if (DestroyOpLength > 0) {
+ Info.SwiftDestroyOp = std::string(reinterpret_cast<const char *>(Data),
+ DestroyOpLength - 1);
+ Data += DestroyOpLength - 1;
+ }
ReadCommonTypeInfo(Data, Info);
return Info;
diff --git a/clang/lib/APINotes/APINotesWriter.cpp b/clang/lib/APINotes/APINotesWriter.cpp
index c013201d677bf..cf88d118d0979 100644
--- a/clang/lib/APINotes/APINotesWriter.cpp
+++ b/clang/lib/APINotes/APINotesWriter.cpp
@@ -1280,6 +1280,7 @@ class TagTableInfo : public CommonTypeTableInfo<TagTableInfo, TagInfo> {
return 2 + (TI.SwiftImportAs ? TI.SwiftImportAs->size() : 0) +
2 + (TI.SwiftRetainOp ? TI.SwiftRetainOp->size() : 0) +
2 + (TI.SwiftReleaseOp ? TI.SwiftReleaseOp->size() : 0) +
+ 2 + (TI.SwiftDestroyOp ? TI.SwiftDestroyOp->size() : 0) +
2 + (TI.SwiftDefaultOwnership ? TI.SwiftDefaultOwnership->size() : 0) +
3 + getCommonTypeInfoSize(TI);
// clang-format on
@@ -1334,6 +1335,12 @@ class TagTableInfo : public CommonTypeTableInfo<TagTableInfo, TagInfo> {
} else {
writer.write<uint16_t>(0);
}
+ if (auto DestroyOp = TI.SwiftDestroyOp) {
+ writer.write<uint16_t>(DestroyOp->size() + 1);
+ OS.write(DestroyOp->c_str(), DestroyOp->size());
+ } else {
+ writer.write<uint16_t>(0);
+ }
emitCommonTypeInfo(OS, TI);
}
diff --git a/clang/lib/APINotes/APINotesYAMLCompiler.cpp b/clang/lib/APINotes/APINotesYAMLCompiler.cpp
index fcc1d9d54b1c6..a91a1eea03d81 100644
--- a/clang/lib/APINotes/APINotesYAMLCompiler.cpp
+++ b/clang/lib/APINotes/APINotesYAMLCompiler.cpp
@@ -462,6 +462,7 @@ struct Tag {
std::optional<std::string> SwiftImportAs;
std::optional<std::string> SwiftRetainOp;
std::optional<std::string> SwiftReleaseOp;
+ std::optional<std::string> SwiftDestroyOp;
std::optional<std::string> SwiftDefaultOwnership;
std::optional<std::string> SwiftConformance;
std::optional<EnumExtensibilityKind> EnumExtensibility;
@@ -503,6 +504,7 @@ template <> struct MappingTraits<Tag> {
IO.mapOptional("SwiftImportAs", T.SwiftImportAs);
IO.mapOptional("SwiftReleaseOp", T.SwiftReleaseOp);
IO.mapOptional("SwiftRetainOp", T.SwiftRetainOp);
+ IO.mapOptional("SwiftDestroyOp", T.SwiftDestroyOp);
IO.mapOptional("SwiftDefaultOwnership", T.SwiftDefaultOwnership);
IO.mapOptional("SwiftConformsTo", T.SwiftConformance);
IO.mapOptional("EnumExtensibility", T.EnumExtensibility);
@@ -996,6 +998,8 @@ class YAMLConverter {
TI.SwiftRetainOp = T.SwiftRetainOp;
if (T.SwiftReleaseOp)
TI.SwiftReleaseOp = T.SwiftReleaseOp;
+ if (T.SwiftDestroyOp)
+ TI.SwiftDestroyOp = T.SwiftDestroyOp;
if (T.SwiftDefaultOwnership)
TI.SwiftDefaultOwnership = T.SwiftDefaultOwnership;
diff --git a/clang/lib/Sema/SemaAPINotes.cpp b/clang/lib/Sema/SemaAPINotes.cpp
index 272069e5fcc7d..4cc1b76264340 100644
--- a/clang/lib/Sema/SemaAPINotes.cpp
+++ b/clang/lib/Sema/SemaAPINotes.cpp
@@ -698,6 +698,9 @@ static void ProcessAPINotes(Sema &S, TagDecl *D, const api_notes::TagInfo &Info,
if (auto ReleaseOp = Info.SwiftReleaseOp)
D->addAttr(
SwiftAttrAttr::Create(S.Context, "release:" + ReleaseOp.value()));
+ if (auto DestroyOp = Info.SwiftDestroyOp)
+ D->addAttr(
+ SwiftAttrAttr::Create(S.Context, "destroy:" + DestroyOp.value()));
if (auto DefaultOwnership = Info.SwiftDefaultOwnership)
D->addAttr(SwiftAttrAttr::Create(
S.Context, "returned_as_" + DefaultOwnership.value() + "_by_default"));
diff --git a/clang/test/APINotes/Inputs/Headers/SwiftImportAs.apinotes b/clang/test/APINotes/Inputs/Headers/SwiftImportAs.apinotes
index cf739ee81c0a9..15c806842d08f 100644
--- a/clang/test/APINotes/Inputs/Headers/SwiftImportAs.apinotes
+++ b/clang/test/APINotes/Inputs/Headers/SwiftImportAs.apinotes
@@ -32,6 +32,9 @@ Tags:
SwiftEscapable: false
- Name: EscapableType
SwiftEscapable: true
+- Name: NoncopyableWithDestroyType
+ SwiftCopyable: false
+ SwiftDestroyOp: NCDDestroy
Functions:
- Name: functionReturningFrt__
diff --git a/clang/test/APINotes/Inputs/Headers/SwiftImportAs.h b/clang/test/APINotes/Inputs/Headers/SwiftImportAs.h
index 4ff45c754fe88..978b4fbbb3b00 100644
--- a/clang/test/APINotes/Inputs/Headers/SwiftImportAs.h
+++ b/clang/test/APINotes/Inputs/Headers/SwiftImportAs.h
@@ -31,3 +31,8 @@ inline void ORCRetain(struct OpaqueRefCountedType *x);
inline void ORCRelease(struct OpaqueRefCountedType *x);
typedef unsigned WrappedOptions;
+
+struct NoncopyableWithDestroyType {
+};
+
+void NCDDestroy(NoncopyableWithDestroyType instance);
diff --git a/clang/test/APINotes/swift-import-as.cpp b/clang/test/APINotes/swift-import-as.cpp
index 64c8c6f202f98..f5d08df7c6a1b 100644
--- a/clang/test/APINotes/swift-import-as.cpp
+++ b/clang/test/APINotes/swift-import-as.cpp
@@ -15,6 +15,7 @@
// RUN: %clang_cc1 -fmodules -fblocks -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache -fdisable-module-hash -fapinotes-modules -I %S/Inputs/Headers %s -x c++ -ast-dump -ast-dump-filter methodReturningFrt_returns_unretained | FileCheck -check-prefix=CHECK-METHOD-RETURNING-FRT-UNRETAINED %s
// RUN: %clang_cc1 -fmodules -fblocks -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache -fdisable-module-hash -fapinotes-modules -I %S/Inputs/Headers %s -x c++ -ast-dump -ast-dump-filter methodReturningFrt_returns_retained | FileCheck -check-prefix=CHECK-METHOD-RETURNING-FRT-RETAINED %s
// RUN: %clang_cc1 -fmodules -fblocks -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache -fdisable-module-hash -fapinotes-modules -I %S/Inputs/Headers %s -x c++ -ast-dump -ast-dump-filter WrappedOptions | FileCheck -check-prefix=CHECK-WRAPPED-OPTIONS %s
+// RUN: %clang_cc1 -fmodules -fblocks -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache -fdisable-module-hash -fapinotes-modules -I %S/Inputs/Headers %s -x c++ -ast-dump -ast-dump-filter NoncopyableWithDestroyType | FileCheck -check-prefix=CHECK-NONCOPYABLE-WITH-DESTROY %s
#include <SwiftImportAs.h>
@@ -97,3 +98,8 @@
// CHECK-WRAPPED-OPTIONS: TypedefDecl{{.*}}WrappedOptions 'unsigned int'
// CHECK-WRAPPED-OPTIONS: SwiftNewTypeAttr {{.*}} swift_wrapper NK_Struct
// CHECK-WRAPPED-OPTIONS: SwiftAttrAttr {{.*}} "conforms_to:Swift.OptionSet"
+
+// CHECK-NONCOPYABLE-WITH-DESTROY: Dumping NoncopyableWithDestroyType
+// CHECK-NONCOPYABLE-WITH-DESTROY: RecordDecl {{.*}}struct NoncopyableWithDestroyType
+// CHECK-NONCOPYABLE-WITH-DESTROY: SwiftAttrAttr {{.+}} "destroy:NCDDestroy"
+// CHECK-NONCOPYABLE-WITH-DESTROY: SwiftAttrAttr {{.+}} "~Copyable"
More information about the cfe-commits
mailing list