[clang] 7ac78f1 - [clang] Add preliminary lifetimebound support to APINotes (#114830)

via cfe-commits cfe-commits at lists.llvm.org
Mon Nov 4 12:30:00 PST 2024


Author: Gábor Horváth
Date: 2024-11-04T20:29:56Z
New Revision: 7ac78f13421c6e5dee4655211fc35225bb8812bc

URL: https://github.com/llvm/llvm-project/commit/7ac78f13421c6e5dee4655211fc35225bb8812bc
DIFF: https://github.com/llvm/llvm-project/commit/7ac78f13421c6e5dee4655211fc35225bb8812bc.diff

LOG: [clang] Add preliminary lifetimebound support to APINotes (#114830)

Added: 
    clang/test/APINotes/Inputs/Headers/Lifetimebound.apinotes
    clang/test/APINotes/Inputs/Headers/Lifetimebound.h
    clang/test/APINotes/lifetimebound.cpp

Modified: 
    clang/include/clang/APINotes/Types.h
    clang/lib/APINotes/APINotesFormat.h
    clang/lib/APINotes/APINotesReader.cpp
    clang/lib/APINotes/APINotesTypes.cpp
    clang/lib/APINotes/APINotesWriter.cpp
    clang/lib/APINotes/APINotesYAMLCompiler.cpp
    clang/lib/Sema/SemaAPINotes.cpp
    clang/test/APINotes/Inputs/Headers/module.modulemap

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/APINotes/Types.h b/clang/include/clang/APINotes/Types.h
index 89889910d1a073..6327b7d75486fc 100644
--- a/clang/include/clang/APINotes/Types.h
+++ b/clang/include/clang/APINotes/Types.h
@@ -425,6 +425,14 @@ class ParamInfo : public VariableInfo {
   LLVM_PREFERRED_TYPE(bool)
   unsigned NoEscape : 1;
 
+  /// Whether lifetimebound was specified.
+  LLVM_PREFERRED_TYPE(bool)
+  unsigned LifetimeboundSpecified : 1;
+
+  /// Whether the this parameter has the 'lifetimebound' attribute.
+  LLVM_PREFERRED_TYPE(bool)
+  unsigned Lifetimebound : 1;
+
   /// A biased RetainCountConventionKind, where 0 means "unspecified".
   ///
   /// Only relevant for out-parameters.
@@ -432,7 +440,9 @@ class ParamInfo : public VariableInfo {
 
 public:
   ParamInfo()
-      : NoEscapeSpecified(false), NoEscape(false), RawRetainCountConvention() {}
+      : NoEscapeSpecified(false), NoEscape(false),
+        LifetimeboundSpecified(false), Lifetimebound(false),
+        RawRetainCountConvention() {}
 
   std::optional<bool> isNoEscape() const {
     if (!NoEscapeSpecified)
@@ -444,6 +454,16 @@ class ParamInfo : public VariableInfo {
     NoEscape = Value.value_or(false);
   }
 
+  std::optional<bool> isLifetimebound() const {
+    if (!LifetimeboundSpecified)
+      return std::nullopt;
+    return Lifetimebound;
+  }
+  void setLifetimebound(std::optional<bool> Value) {
+    LifetimeboundSpecified = Value.has_value();
+    Lifetimebound = Value.value_or(false);
+  }
+
   std::optional<RetainCountConventionKind> getRetainCountConvention() const {
     if (!RawRetainCountConvention)
       return std::nullopt;
@@ -463,6 +483,11 @@ class ParamInfo : public VariableInfo {
       NoEscape = RHS.NoEscape;
     }
 
+    if (!LifetimeboundSpecified && RHS.LifetimeboundSpecified) {
+      LifetimeboundSpecified = true;
+      Lifetimebound = RHS.Lifetimebound;
+    }
+
     if (!RawRetainCountConvention)
       RawRetainCountConvention = RHS.RawRetainCountConvention;
 
@@ -478,6 +503,8 @@ inline bool operator==(const ParamInfo &LHS, const ParamInfo &RHS) {
   return static_cast<const VariableInfo &>(LHS) == RHS &&
          LHS.NoEscapeSpecified == RHS.NoEscapeSpecified &&
          LHS.NoEscape == RHS.NoEscape &&
+         LHS.LifetimeboundSpecified == RHS.LifetimeboundSpecified &&
+         LHS.Lifetimebound == RHS.Lifetimebound &&
          LHS.RawRetainCountConvention == RHS.RawRetainCountConvention;
 }
 

diff  --git a/clang/lib/APINotes/APINotesFormat.h b/clang/lib/APINotes/APINotesFormat.h
index d724a9ea471b54..014ee7e2e3d397 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 = 30; // fields
+const uint16_t VERSION_MINOR = 31; // lifetimebound
 
 const uint8_t kSwiftCopyable = 1;
 const uint8_t kSwiftNonCopyable = 2;

diff  --git a/clang/lib/APINotes/APINotesReader.cpp b/clang/lib/APINotes/APINotesReader.cpp
index da8a86f7adb16e..1bde8482fce033 100644
--- a/clang/lib/APINotes/APINotesReader.cpp
+++ b/clang/lib/APINotes/APINotesReader.cpp
@@ -331,6 +331,9 @@ void ReadParamInfo(const uint8_t *&Data, ParamInfo &Info) {
     Info.setRetainCountConvention(Convention);
   }
   Payload >>= 3;
+  if (Payload & 0x01)
+    Info.setLifetimebound(Payload & 0x02);
+  Payload >>= 2;
   if (Payload & 0x01)
     Info.setNoEscape(Payload & 0x02);
   Payload >>= 2;

diff  --git a/clang/lib/APINotes/APINotesTypes.cpp b/clang/lib/APINotes/APINotesTypes.cpp
index a87ecb3bc30eec..be7dec3295b4ce 100644
--- a/clang/lib/APINotes/APINotesTypes.cpp
+++ b/clang/lib/APINotes/APINotesTypes.cpp
@@ -65,6 +65,8 @@ LLVM_DUMP_METHOD void ParamInfo::dump(llvm::raw_ostream &OS) const {
   static_cast<const VariableInfo &>(*this).dump(OS);
   if (NoEscapeSpecified)
     OS << (NoEscape ? "[NoEscape] " : "");
+  if (LifetimeboundSpecified)
+    OS << (Lifetimebound ? "[Lifetimebound] " : "");
   OS << "RawRetainCountConvention: " << RawRetainCountConvention << ' ';
   OS << '\n';
 }

diff  --git a/clang/lib/APINotes/APINotesWriter.cpp b/clang/lib/APINotes/APINotesWriter.cpp
index a2b3669a314476..d81394edfde304 100644
--- a/clang/lib/APINotes/APINotesWriter.cpp
+++ b/clang/lib/APINotes/APINotesWriter.cpp
@@ -1052,6 +1052,12 @@ void emitParamInfo(raw_ostream &OS, const ParamInfo &PI) {
     if (*noescape)
       flags |= 0x02;
   }
+  flags <<= 2;
+  if (auto lifetimebound = PI.isLifetimebound()) {
+    flags |= 0x01;
+    if (*lifetimebound)
+      flags |= 0x02;
+  }
   flags <<= 3;
   if (auto RCC = PI.getRetainCountConvention())
     flags |= static_cast<uint8_t>(RCC.value()) + 1;

diff  --git a/clang/lib/APINotes/APINotesYAMLCompiler.cpp b/clang/lib/APINotes/APINotesYAMLCompiler.cpp
index f72a1d65b5456f..11578e4d054b7f 100644
--- a/clang/lib/APINotes/APINotesYAMLCompiler.cpp
+++ b/clang/lib/APINotes/APINotesYAMLCompiler.cpp
@@ -70,6 +70,7 @@ namespace {
 struct Param {
   unsigned Position;
   std::optional<bool> NoEscape = false;
+  std::optional<bool> Lifetimebound = false;
   std::optional<NullabilityKind> Nullability;
   std::optional<RetainCountConventionKind> RetainCountConvention;
   StringRef Type;
@@ -121,6 +122,7 @@ template <> struct MappingTraits<Param> {
     IO.mapOptional("Nullability", P.Nullability, std::nullopt);
     IO.mapOptional("RetainCountConvention", P.RetainCountConvention);
     IO.mapOptional("NoEscape", P.NoEscape);
+    IO.mapOptional("Lifetimebound", P.Lifetimebound);
     IO.mapOptional("Type", P.Type, StringRef(""));
   }
 };
@@ -734,6 +736,7 @@ class YAMLConverter {
       if (P.Nullability)
         PI.setNullabilityAudited(*P.Nullability);
       PI.setNoEscape(P.NoEscape);
+      PI.setLifetimebound(P.Lifetimebound);
       PI.setType(std::string(P.Type));
       PI.setRetainCountConvention(P.RetainCountConvention);
       if (OutInfo.Params.size() <= P.Position)

diff  --git a/clang/lib/Sema/SemaAPINotes.cpp b/clang/lib/Sema/SemaAPINotes.cpp
index ec43a0def9c1e6..edb4c19d59745c 100644
--- a/clang/lib/Sema/SemaAPINotes.cpp
+++ b/clang/lib/Sema/SemaAPINotes.cpp
@@ -12,6 +12,7 @@
 
 #include "clang/APINotes/APINotesReader.h"
 #include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
 #include "clang/AST/DeclObjC.h"
 #include "clang/Basic/SourceLocation.h"
 #include "clang/Lex/Lexer.h"
@@ -415,6 +416,13 @@ static void ProcessAPINotes(Sema &S, ParmVarDecl *D,
       return new (S.Context) NoEscapeAttr(S.Context, getPlaceholderAttrInfo());
     });
 
+  if (auto Lifetimebound = Info.isLifetimebound())
+    handleAPINotedAttribute<LifetimeBoundAttr>(
+        S, D, *Lifetimebound, Metadata, [&] {
+          return new (S.Context)
+              LifetimeBoundAttr(S.Context, getPlaceholderAttrInfo());
+        });
+
   // Retain count convention
   handleAPINotedRetainCountConvention(S, D, Metadata,
                                       Info.getRetainCountConvention());
@@ -860,13 +868,12 @@ void Sema::ProcessAPINotes(Decl *D) {
   if (!D)
     return;
 
+  auto *DC = D->getDeclContext();
   // Globals.
-  if (D->getDeclContext()->isFileContext() ||
-      D->getDeclContext()->isNamespace() ||
-      D->getDeclContext()->isExternCContext() ||
-      D->getDeclContext()->isExternCXXContext()) {
+  if (DC->isFileContext() || DC->isNamespace() || DC->isExternCContext() ||
+      DC->isExternCXXContext()) {
     std::optional<api_notes::Context> APINotesContext =
-        UnwindNamespaceContext(D->getDeclContext(), APINotes);
+        UnwindNamespaceContext(DC, APINotes);
     // Global variables.
     if (auto VD = dyn_cast<VarDecl>(D)) {
       for (auto Reader : APINotes.findAPINotes(D->getLocation())) {
@@ -967,8 +974,8 @@ void Sema::ProcessAPINotes(Decl *D) {
   }
 
   // Enumerators.
-  if (D->getDeclContext()->getRedeclContext()->isFileContext() ||
-      D->getDeclContext()->getRedeclContext()->isExternCContext()) {
+  if (DC->getRedeclContext()->isFileContext() ||
+      DC->getRedeclContext()->isExternCContext()) {
     if (auto EnumConstant = dyn_cast<EnumConstantDecl>(D)) {
       for (auto Reader : APINotes.findAPINotes(D->getLocation())) {
         auto Info = Reader->lookupEnumConstant(EnumConstant->getName());
@@ -979,7 +986,7 @@ void Sema::ProcessAPINotes(Decl *D) {
     }
   }
 
-  if (auto ObjCContainer = dyn_cast<ObjCContainerDecl>(D->getDeclContext())) {
+  if (auto ObjCContainer = dyn_cast<ObjCContainerDecl>(DC)) {
     // Location function that looks up an Objective-C context.
     auto GetContext = [&](api_notes::APINotesReader *Reader)
         -> std::optional<api_notes::ContextID> {
@@ -1063,7 +1070,7 @@ void Sema::ProcessAPINotes(Decl *D) {
     }
   }
 
-  if (auto TagContext = dyn_cast<TagDecl>(D->getDeclContext())) {
+  if (auto TagContext = dyn_cast<TagDecl>(DC)) {
     if (auto CXXMethod = dyn_cast<CXXMethodDecl>(D)) {
       if (!isa<CXXConstructorDecl>(CXXMethod) &&
           !isa<CXXDestructorDecl>(CXXMethod) &&

diff  --git a/clang/test/APINotes/Inputs/Headers/Lifetimebound.apinotes b/clang/test/APINotes/Inputs/Headers/Lifetimebound.apinotes
new file mode 100644
index 00000000000000..d07d87cf02f025
--- /dev/null
+++ b/clang/test/APINotes/Inputs/Headers/Lifetimebound.apinotes
@@ -0,0 +1,14 @@
+---
+Name: Lifetimebound
+Functions:
+  - Name:              funcToAnnotate
+    Parameters:
+      - Position:      0
+        Lifetimebound: true
+Tags:
+- Name: MyClass
+  Methods:
+    - Name: methodToAnnotate
+      Parameters:
+        - Position:      0
+          Lifetimebound: true

diff  --git a/clang/test/APINotes/Inputs/Headers/Lifetimebound.h b/clang/test/APINotes/Inputs/Headers/Lifetimebound.h
new file mode 100644
index 00000000000000..2ec302f7801a77
--- /dev/null
+++ b/clang/test/APINotes/Inputs/Headers/Lifetimebound.h
@@ -0,0 +1,8 @@
+int *funcToAnnotate(int *p);
+
+// TODO: support annotating ctors and 'this'.
+struct MyClass {
+    MyClass(int*);
+    int *annotateThis();
+    int *methodToAnnotate(int *p);
+};

diff  --git a/clang/test/APINotes/Inputs/Headers/module.modulemap b/clang/test/APINotes/Inputs/Headers/module.modulemap
index 7d304863398ecf..31f7d36356d83e 100644
--- a/clang/test/APINotes/Inputs/Headers/module.modulemap
+++ b/clang/test/APINotes/Inputs/Headers/module.modulemap
@@ -17,6 +17,11 @@ module Fields {
   export *
 }
 
+module Lifetimebound {
+  header "Lifetimebound.h"
+  export *
+}
+
 module HeaderLib {
   header "HeaderLib.h"
 }

diff  --git a/clang/test/APINotes/lifetimebound.cpp b/clang/test/APINotes/lifetimebound.cpp
new file mode 100644
index 00000000000000..3e5ce9df895b70
--- /dev/null
+++ b/clang/test/APINotes/lifetimebound.cpp
@@ -0,0 +1,13 @@
+// RUN: rm -rf %t && mkdir -p %t
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache/Lifetimebound -fdisable-module-hash -fapinotes-modules -fsyntax-only -I %S/Inputs/Headers %s -x c++
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache/Lifetimebound -fdisable-module-hash -fapinotes-modules -I %S/Inputs/Headers %s -ast-dump -ast-dump-filter funcToAnnotate -x c++ | FileCheck --check-prefix=CHECK-PARAM %s
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache/Lifetimebound -fdisable-module-hash -fapinotes-modules -I %S/Inputs/Headers %s -ast-dump -ast-dump-filter methodToAnnotate -x c++ | FileCheck --check-prefix=CHECK-METHOD %s
+#include "Lifetimebound.h"
+
+// CHECK-PARAM: FunctionDecl {{.+}} funcToAnnotate 
+// CHECK-PARAM-NEXT: ParmVarDecl {{.+}} p
+// CHECK-PARAM-NEXT: LifetimeBoundAttr
+
+// CHECK-METHOD: CXXMethodDecl {{.+}} methodToAnnotate 
+// CHECK-METHOD-NEXT: ParmVarDecl {{.+}} p
+// CHECK-METHOD-NEXT: LifetimeBoundAttr


        


More information about the cfe-commits mailing list