[clang] [clang][APINotes] Add support for the SwiftEscapable attribute (PR #115866)

Gábor Horváth via cfe-commits cfe-commits at lists.llvm.org
Tue Nov 12 05:11:10 PST 2024


https://github.com/Xazax-hun created https://github.com/llvm/llvm-project/pull/115866

This is similar to SwiftCopyable. Also fix missing SwiftCopyable dump for TagInfo.

>From 70ebdd0a63397130e45b79b3c6096c1847c07110 Mon Sep 17 00:00:00 2001
From: Gabor Horvath <gaborh at apple.com>
Date: Tue, 12 Nov 2024 13:07:01 +0000
Subject: [PATCH] [clang][APINotes] Add support for the SwiftEscapable
 attribute

This is similar to SwiftCopyable. Also fix missing SwiftCopyable dump for
TagInfo.
---
 clang/include/clang/APINotes/Types.h          | 21 ++++++++++++++++++-
 clang/lib/APINotes/APINotesFormat.h           |  7 +++----
 clang/lib/APINotes/APINotesReader.cpp         | 10 +++++++--
 clang/lib/APINotes/APINotesTypes.cpp          |  4 ++++
 clang/lib/APINotes/APINotesWriter.cpp         | 17 +++++++++------
 clang/lib/APINotes/APINotesYAMLCompiler.cpp   |  4 ++++
 clang/lib/Sema/SemaAPINotes.cpp               |  7 +++++++
 .../Inputs/Headers/SwiftImportAs.apinotes     |  4 ++++
 .../APINotes/Inputs/Headers/SwiftImportAs.h   |  3 +++
 clang/test/APINotes/swift-import-as.cpp       | 10 +++++++++
 10 files changed, 74 insertions(+), 13 deletions(-)

diff --git a/clang/include/clang/APINotes/Types.h b/clang/include/clang/APINotes/Types.h
index 6ad1c850701146..a228c3c5b2770d 100644
--- a/clang/include/clang/APINotes/Types.h
+++ b/clang/include/clang/APINotes/Types.h
@@ -724,6 +724,11 @@ class TagInfo : public CommonTypeInfo {
   LLVM_PREFERRED_TYPE(bool)
   unsigned SwiftCopyable : 1;
 
+  LLVM_PREFERRED_TYPE(bool)
+  unsigned SwiftEscapableSpecified : 1;
+  LLVM_PREFERRED_TYPE(bool)
+  unsigned SwiftEscapable : 1;
+
 public:
   std::optional<std::string> SwiftImportAs;
   std::optional<std::string> SwiftRetainOp;
@@ -736,7 +741,8 @@ class TagInfo : public CommonTypeInfo {
 
   TagInfo()
       : HasFlagEnum(0), IsFlagEnum(0), SwiftCopyableSpecified(false),
-        SwiftCopyable(false) {}
+        SwiftCopyable(false), SwiftEscapableSpecified(false),
+        SwiftEscapable(false) {}
 
   std::optional<bool> isFlagEnum() const {
     if (HasFlagEnum)
@@ -757,6 +763,15 @@ class TagInfo : public CommonTypeInfo {
     SwiftCopyable = Value.value_or(false);
   }
 
+  std::optional<bool> isSwiftEscapable() const {
+    return SwiftEscapableSpecified ? std::optional<bool>(SwiftEscapable)
+                                   : std::nullopt;
+  }
+  void setSwiftEscapable(std::optional<bool> Value) {
+    SwiftEscapableSpecified = Value.has_value();
+    SwiftEscapable = Value.value_or(false);
+  }
+
   TagInfo &operator|=(const TagInfo &RHS) {
     static_cast<CommonTypeInfo &>(*this) |= RHS;
 
@@ -779,6 +794,9 @@ class TagInfo : public CommonTypeInfo {
     if (!SwiftCopyableSpecified)
       setSwiftCopyable(RHS.isSwiftCopyable());
 
+    if (!SwiftEscapableSpecified)
+      setSwiftEscapable(RHS.isSwiftEscapable());
+
     return *this;
   }
 
@@ -795,6 +813,7 @@ inline bool operator==(const TagInfo &LHS, const TagInfo &RHS) {
          LHS.SwiftConformance == RHS.SwiftConformance &&
          LHS.isFlagEnum() == RHS.isFlagEnum() &&
          LHS.isSwiftCopyable() == RHS.isSwiftCopyable() &&
+         LHS.isSwiftEscapable() == RHS.isSwiftEscapable() &&
          LHS.EnumExtensibility == RHS.EnumExtensibility;
 }
 
diff --git a/clang/lib/APINotes/APINotesFormat.h b/clang/lib/APINotes/APINotesFormat.h
index 4d1c698ae6310d..a03cef36294dbb 100644
--- a/clang/lib/APINotes/APINotesFormat.h
+++ b/clang/lib/APINotes/APINotesFormat.h
@@ -24,11 +24,10 @@ 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 =
-    32; // implicit parameter support (at position -1)
+const uint16_t VERSION_MINOR = 33; // SwiftEscapable
 
-const uint8_t kSwiftCopyable = 1;
-const uint8_t kSwiftNonCopyable = 2;
+const uint8_t kSwiftConforms = 1;
+const uint8_t kSwiftDoesNotConform = 2;
 
 using IdentifierID = llvm::PointerEmbeddedInt<unsigned, 31>;
 using IdentifierIDField = llvm::BCVBR<16>;
diff --git a/clang/lib/APINotes/APINotesReader.cpp b/clang/lib/APINotes/APINotesReader.cpp
index 0f8fa1355bfb0a..97b8654cbe6c9b 100644
--- a/clang/lib/APINotes/APINotesReader.cpp
+++ b/clang/lib/APINotes/APINotesReader.cpp
@@ -589,10 +589,16 @@ class TagTableInfo
 
     uint8_t Copyable =
         endian::readNext<uint8_t, llvm::endianness::little>(Data);
-    if (Copyable == kSwiftNonCopyable)
+    if (Copyable == kSwiftDoesNotConform)
       Info.setSwiftCopyable(std::optional(false));
-    else if (Copyable == kSwiftCopyable)
+    else if (Copyable == kSwiftConforms)
       Info.setSwiftCopyable(std::optional(true));
+    uint8_t Escapable =
+        endian::readNext<uint8_t, llvm::endianness::little>(Data);
+    if (Escapable == kSwiftDoesNotConform)
+      Info.setSwiftEscapable(std::optional(false));
+    else if (Escapable == kSwiftConforms)
+      Info.setSwiftEscapable(std::optional(true));
 
     unsigned ImportAsLength =
         endian::readNext<uint16_t, llvm::endianness::little>(Data);
diff --git a/clang/lib/APINotes/APINotesTypes.cpp b/clang/lib/APINotes/APINotesTypes.cpp
index b92faa0acc7482..d06277fa367274 100644
--- a/clang/lib/APINotes/APINotesTypes.cpp
+++ b/clang/lib/APINotes/APINotesTypes.cpp
@@ -104,6 +104,10 @@ LLVM_DUMP_METHOD void TagInfo::dump(llvm::raw_ostream &OS) {
   if (EnumExtensibility)
     OS << "Enum Extensibility: " << static_cast<long>(*EnumExtensibility)
        << ' ';
+  if (SwiftCopyableSpecified)
+    OS << (SwiftCopyable ? "[SwiftCopyable] " : "[~SwiftCopyable]");
+  if (SwiftEscapableSpecified)
+    OS << (SwiftEscapable ? "[SwiftEscapable] " : "[~SwiftEscapable]");
   OS << '\n';
 }
 
diff --git a/clang/lib/APINotes/APINotesWriter.cpp b/clang/lib/APINotes/APINotesWriter.cpp
index 3b8b3c80f7c086..4776f767ef6103 100644
--- a/clang/lib/APINotes/APINotesWriter.cpp
+++ b/clang/lib/APINotes/APINotesWriter.cpp
@@ -1266,11 +1266,11 @@ class CommonTypeTableInfo
 class TagTableInfo : public CommonTypeTableInfo<TagTableInfo, TagInfo> {
 public:
   unsigned getUnversionedInfoSize(const TagInfo &TI) {
-    return 2 + (TI.SwiftImportAs ? TI.SwiftImportAs->size() : 0) +
-           2 + (TI.SwiftRetainOp ? TI.SwiftRetainOp->size() : 0) +
-           2 + (TI.SwiftReleaseOp ? TI.SwiftReleaseOp->size() : 0) +
-           2 + (TI.SwiftConformance ? TI.SwiftConformance->size() : 0) +
-           2 + getCommonTypeInfoSize(TI);
+    return 2 + (TI.SwiftImportAs ? TI.SwiftImportAs->size() : 0) + 2 +
+           (TI.SwiftRetainOp ? TI.SwiftRetainOp->size() : 0) + 2 +
+           (TI.SwiftReleaseOp ? TI.SwiftReleaseOp->size() : 0) + 2 +
+           (TI.SwiftConformance ? TI.SwiftConformance->size() : 0) + 3 +
+           getCommonTypeInfoSize(TI);
   }
 
   void emitUnversionedInfo(raw_ostream &OS, const TagInfo &TI) {
@@ -1289,7 +1289,12 @@ class TagTableInfo : public CommonTypeTableInfo<TagTableInfo, TagInfo> {
     writer.write<uint8_t>(Flags);
 
     if (auto Copyable = TI.isSwiftCopyable())
-      writer.write<uint8_t>(*Copyable ? kSwiftCopyable : kSwiftNonCopyable);
+      writer.write<uint8_t>(*Copyable ? kSwiftConforms : kSwiftDoesNotConform);
+    else
+      writer.write<uint8_t>(0);
+
+    if (auto Escapable = TI.isSwiftEscapable())
+      writer.write<uint8_t>(*Escapable ? kSwiftConforms : kSwiftDoesNotConform);
     else
       writer.write<uint8_t>(0);
 
diff --git a/clang/lib/APINotes/APINotesYAMLCompiler.cpp b/clang/lib/APINotes/APINotesYAMLCompiler.cpp
index e3cb2b3f573886..0668dda910f2a8 100644
--- a/clang/lib/APINotes/APINotesYAMLCompiler.cpp
+++ b/clang/lib/APINotes/APINotesYAMLCompiler.cpp
@@ -459,6 +459,7 @@ struct Tag {
   std::optional<bool> FlagEnum;
   std::optional<EnumConvenienceAliasKind> EnumConvenienceKind;
   std::optional<bool> SwiftCopyable;
+  std::optional<bool> SwiftEscapable;
   FunctionsSeq Methods;
   FieldsSeq Fields;
 
@@ -498,6 +499,7 @@ template <> struct MappingTraits<Tag> {
     IO.mapOptional("FlagEnum", T.FlagEnum);
     IO.mapOptional("EnumKind", T.EnumConvenienceKind);
     IO.mapOptional("SwiftCopyable", T.SwiftCopyable);
+    IO.mapOptional("SwiftEscapable", T.SwiftEscapable);
     IO.mapOptional("Methods", T.Methods);
     IO.mapOptional("Fields", T.Fields);
     IO.mapOptional("Tags", T.Tags);
@@ -983,6 +985,8 @@ class YAMLConverter {
 
     if (T.SwiftCopyable)
       TI.setSwiftCopyable(T.SwiftCopyable);
+    if (T.SwiftEscapable)
+      TI.setSwiftEscapable(T.SwiftEscapable);
 
     if (T.EnumConvenienceKind) {
       if (T.EnumExtensibility) {
diff --git a/clang/lib/Sema/SemaAPINotes.cpp b/clang/lib/Sema/SemaAPINotes.cpp
index 5bb58d6c98be95..e73b4b360afead 100644
--- a/clang/lib/Sema/SemaAPINotes.cpp
+++ b/clang/lib/Sema/SemaAPINotes.cpp
@@ -647,6 +647,13 @@ static void ProcessAPINotes(Sema &S, TagDecl *D, const api_notes::TagInfo &Info,
       D->addAttr(SwiftAttrAttr::Create(S.Context, "~Copyable"));
   }
 
+  if (auto Escapable = Info.isSwiftEscapable()) {
+    if (*Escapable)
+      D->addAttr(SwiftAttrAttr::Create(S.Context, "Escapable"));
+    else
+      D->addAttr(SwiftAttrAttr::Create(S.Context, "~Escapable"));
+  }
+
   if (auto Extensibility = Info.EnumExtensibility) {
     using api_notes::EnumExtensibilityKind;
     bool ShouldAddAttribute = (*Extensibility != EnumExtensibilityKind::None);
diff --git a/clang/test/APINotes/Inputs/Headers/SwiftImportAs.apinotes b/clang/test/APINotes/Inputs/Headers/SwiftImportAs.apinotes
index f4f9c7a244e0a3..81fb160c66b638 100644
--- a/clang/test/APINotes/Inputs/Headers/SwiftImportAs.apinotes
+++ b/clang/test/APINotes/Inputs/Headers/SwiftImportAs.apinotes
@@ -13,3 +13,7 @@ Tags:
   SwiftConformsTo: MySwiftModule.MySwiftNonCopyableProtocol
 - Name: CopyableType
   SwiftCopyable: true
+- Name: NonEscapableType
+  SwiftEscapable: false
+- Name: EscapableType
+  SwiftEscapable: true
\ No newline at end of file
diff --git a/clang/test/APINotes/Inputs/Headers/SwiftImportAs.h b/clang/test/APINotes/Inputs/Headers/SwiftImportAs.h
index a8f6d0248eae40..f205cd3c6e7b71 100644
--- a/clang/test/APINotes/Inputs/Headers/SwiftImportAs.h
+++ b/clang/test/APINotes/Inputs/Headers/SwiftImportAs.h
@@ -7,3 +7,6 @@ inline void RCRelease(RefCountedType *x) { x->value--; }
 
 struct NonCopyableType { int value; };
 struct CopyableType { int value; };
+
+struct NonEscapableType { int value; };
+struct EscapableType { int value; };
diff --git a/clang/test/APINotes/swift-import-as.cpp b/clang/test/APINotes/swift-import-as.cpp
index 6457e1557618de..d0e7e31fc1d726 100644
--- a/clang/test/APINotes/swift-import-as.cpp
+++ b/clang/test/APINotes/swift-import-as.cpp
@@ -4,6 +4,8 @@
 // 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 RefCountedType | FileCheck -check-prefix=CHECK-REF-COUNTED %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 NonCopyableType | FileCheck -check-prefix=CHECK-NON-COPYABLE %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 CopyableType | FileCheck -check-prefix=CHECK-COPYABLE %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 NonEscapableType | FileCheck -check-prefix=CHECK-NON-ESCAPABLE %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 EscapableType | FileCheck -check-prefix=CHECK-ESCAPABLE %s
 
 #include <SwiftImportAs.h>
 
@@ -26,3 +28,11 @@
 // CHECK-COPYABLE: Dumping CopyableType:
 // CHECK-COPYABLE-NEXT: CXXRecordDecl {{.+}} imported in SwiftImportAs {{.+}} struct CopyableType
 // CHECK-COPYABLE-NOT: SwiftAttrAttr
+
+// CHECK-NON-ESCAPABLE: Dumping NonEscapableType:
+// CHECK-NON-ESCAPABLE-NEXT: CXXRecordDecl {{.+}} imported in SwiftImportAs {{.+}} struct NonEscapableType
+// CHECK-NON-ESCAPABLE: SwiftAttrAttr {{.+}} "~Escapable"
+
+// CHECK-ESCAPABLE: Dumping EscapableType:
+// CHECK-ESCAPABLE-NEXT: CXXRecordDecl {{.+}} imported in SwiftImportAs {{.+}} struct EscapableType
+// CHECK-ESCAPABLE: SwiftAttrAttr {{.+}} "Escapable"



More information about the cfe-commits mailing list