https://github.com/ziqingluo-90 updated 
https://github.com/llvm/llvm-project/pull/189775

>From f561217ce6be85b30b15331e91423e60a8fba71e Mon Sep 17 00:00:00 2001
From: Ziqing Luo <[email protected]>
Date: Tue, 31 Mar 2026 16:55:30 -0700
Subject: [PATCH] [APINotes][unsafe-buffer-usage] Add
 [[clang::unsafe_buffer_usage]] support in APINotes

Support the ``[[clang::unsafe_buffer_usage]]`` attribute in APINotes, e.g.,
```
    Functions:
      - Name: myUnsafeFunction
        UnsafeBufferUsage: true
```

rdar://171859135
---
 clang/docs/ReleaseNotes.rst                   |  9 ++++++++
 clang/include/clang/APINotes/Types.h          |  7 +++++-
 clang/lib/APINotes/APINotesFormat.h           |  2 +-
 clang/lib/APINotes/APINotesReader.cpp         |  3 +++
 clang/lib/APINotes/APINotesTypes.cpp          |  1 +
 clang/lib/APINotes/APINotesWriter.cpp         |  2 ++
 clang/lib/APINotes/APINotesYAMLCompiler.cpp   |  3 +++
 clang/lib/Sema/SemaAPINotes.cpp               |  8 +++++++
 .../Inputs/Headers/UnsafeBufferUsage.apinotes |  6 +++++
 .../Inputs/Headers/UnsafeBufferUsage.h        |  2 ++
 .../APINotes/Inputs/Headers/module.modulemap  |  5 ++++
 clang/test/APINotes/unsafe-buffer-usage.cpp   | 23 +++++++++++++++++++
 12 files changed, 69 insertions(+), 2 deletions(-)
 create mode 100644 
clang/test/APINotes/Inputs/Headers/UnsafeBufferUsage.apinotes
 create mode 100644 clang/test/APINotes/Inputs/Headers/UnsafeBufferUsage.h
 create mode 100644 clang/test/APINotes/unsafe-buffer-usage.cpp

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index cd7f280fbb6db..13e39e240d9b4 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -252,6 +252,15 @@ Attribute Changes in Clang
   sound because any writer must hold all capabilities, so holding any one
   prevents concurrent writes.
 
+- The ``[[clang::unsafe_buffer_usage]]`` attribute is now supported in API
+  notes. For example:
+
+  .. code-block:: yaml
+
+    Functions:
+      - Name: myUnsafeFunction
+        UnsafeBufferUsage: true
+
 Improvements to Clang's diagnostics
 -----------------------------------
 - ``-Wunused-but-set-variable`` now diagnoses file-scope variables with
diff --git a/clang/include/clang/APINotes/Types.h 
b/clang/include/clang/APINotes/Types.h
index fb2b91a3e1750..8291b9e2668ea 100644
--- a/clang/include/clang/APINotes/Types.h
+++ b/clang/include/clang/APINotes/Types.h
@@ -570,6 +570,10 @@ class FunctionInfo : public CommonEntityInfo {
   /// A biased RetainCountConventionKind, where 0 means "unspecified".
   unsigned RawRetainCountConvention : 3;
 
+  /// Whether the function has the [[clang::unsafe_buffer_usage]] attribute
+  LLVM_PREFERRED_TYPE(bool)
+  unsigned UnsafeBufferUsage : 1;
+
   // NullabilityKindSize bits are used to encode the nullability. The info
   // about the return type is stored at position 0, followed by the nullability
   // of the parameters.
@@ -588,7 +592,7 @@ class FunctionInfo : public CommonEntityInfo {
 
   FunctionInfo()
       : NullabilityAudited(false), NumAdjustedNullable(0),
-        RawRetainCountConvention() {}
+        RawRetainCountConvention(), UnsafeBufferUsage(0) {}
 
   static unsigned getMaxNullabilityIndex() {
     return ((sizeof(NullabilityPayload) * CHAR_BIT) / NullabilityKindSize);
@@ -660,6 +664,7 @@ class FunctionInfo : public CommonEntityInfo {
 inline bool operator==(const FunctionInfo &LHS, const FunctionInfo &RHS) {
   return static_cast<const CommonEntityInfo &>(LHS) == RHS &&
          LHS.NullabilityAudited == RHS.NullabilityAudited &&
+         LHS.UnsafeBufferUsage == RHS.UnsafeBufferUsage &&
          LHS.NumAdjustedNullable == RHS.NumAdjustedNullable &&
          LHS.NullabilityPayload == RHS.NullabilityPayload &&
          LHS.ResultType == RHS.ResultType && LHS.Params == RHS.Params &&
diff --git a/clang/lib/APINotes/APINotesFormat.h 
b/clang/lib/APINotes/APINotesFormat.h
index 9d868a1b4da1f..db94e6cf5492b 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 = 38; // SwiftSafety
+const uint16_t VERSION_MINOR = 39; // 39 for [[clang::unsafe_buffer_usage]]
 
 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 f00c7ac1d9d9b..2e6e397577e76 100644
--- a/clang/lib/APINotes/APINotesReader.cpp
+++ b/clang/lib/APINotes/APINotesReader.cpp
@@ -354,6 +354,9 @@ void ReadFunctionInfo(const uint8_t *&Data, FunctionInfo 
&Info) {
   ReadCommonEntityInfo(Data, Info);
 
   uint8_t Payload = endian::readNext<uint8_t, llvm::endianness::little>(Data);
+  if (Payload & 0x1)
+    Info.UnsafeBufferUsage = 1;
+  Payload >>= 0x1;
   if (auto RawConvention = Payload & 0x7) {
     auto Convention = static_cast<RetainCountConventionKind>(RawConvention - 
1);
     Info.setRetainCountConvention(Convention);
diff --git a/clang/lib/APINotes/APINotesTypes.cpp 
b/clang/lib/APINotes/APINotesTypes.cpp
index bff4be104c6c8..177b387d1c480 100644
--- a/clang/lib/APINotes/APINotesTypes.cpp
+++ b/clang/lib/APINotes/APINotesTypes.cpp
@@ -89,6 +89,7 @@ LLVM_DUMP_METHOD void ParamInfo::dump(llvm::raw_ostream &OS) 
const {
 LLVM_DUMP_METHOD void FunctionInfo::dump(llvm::raw_ostream &OS) const {
   static_cast<const CommonEntityInfo &>(*this).dump(OS);
   OS << (NullabilityAudited ? "[NullabilityAudited] " : "")
+     << (UnsafeBufferUsage ? "[UnsafeBufferUsage] " : "")
      << "RawRetainCountConvention: " << RawRetainCountConvention << ' ';
   if (!ResultType.empty())
     OS << "Result Type: " << ResultType << ' ';
diff --git a/clang/lib/APINotes/APINotesWriter.cpp 
b/clang/lib/APINotes/APINotesWriter.cpp
index 390aea57f3915..be9ffaa475b67 100644
--- a/clang/lib/APINotes/APINotesWriter.cpp
+++ b/clang/lib/APINotes/APINotesWriter.cpp
@@ -1122,6 +1122,8 @@ void emitFunctionInfo(raw_ostream &OS, const FunctionInfo 
&FI) {
   flags <<= 3;
   if (auto RCC = FI.getRetainCountConvention())
     flags |= static_cast<uint8_t>(RCC.value()) + 1;
+  flags <<= 0x01;
+  flags |= FI.UnsafeBufferUsage;
 
   llvm::support::endian::Writer writer(OS, llvm::endianness::little);
 
diff --git a/clang/lib/APINotes/APINotesYAMLCompiler.cpp 
b/clang/lib/APINotes/APINotesYAMLCompiler.cpp
index 3b82fdda68af1..202d3069d78ae 100644
--- a/clang/lib/APINotes/APINotesYAMLCompiler.cpp
+++ b/clang/lib/APINotes/APINotesYAMLCompiler.cpp
@@ -316,6 +316,7 @@ struct Function {
   StringRef ResultType;
   StringRef SwiftReturnOwnership;
   SwiftSafetyKind SafetyKind = SwiftSafetyKind::None;
+  bool UnsafeBufferUsage = false;
 };
 
 typedef std::vector<Function> FunctionsSeq;
@@ -341,6 +342,7 @@ template <> struct MappingTraits<Function> {
     IO.mapOptional("SwiftReturnOwnership", F.SwiftReturnOwnership,
                    StringRef(""));
     IO.mapOptional("SwiftSafety", F.SafetyKind, SwiftSafetyKind::None);
+    IO.mapOptional("UnsafeBufferUsage", F.UnsafeBufferUsage, false);
   }
 };
 } // namespace yaml
@@ -1003,6 +1005,7 @@ class YAMLConverter {
     FI.ResultType = std::string(Function.ResultType);
     FI.SwiftReturnOwnership = std::string(Function.SwiftReturnOwnership);
     FI.setRetainCountConvention(Function.RetainCountConvention);
+    FI.UnsafeBufferUsage = Function.UnsafeBufferUsage;
   }
 
   void convertTagContext(std::optional<Context> ParentContext, const Tag &T,
diff --git a/clang/lib/Sema/SemaAPINotes.cpp b/clang/lib/Sema/SemaAPINotes.cpp
index ab314a43abcca..40eb3d3de71a1 100644
--- a/clang/lib/Sema/SemaAPINotes.cpp
+++ b/clang/lib/Sema/SemaAPINotes.cpp
@@ -578,6 +578,14 @@ static void ProcessAPINotes(Sema &S, FunctionOrMethod 
AnyFunc,
   if (Info.NullabilityAudited)
     applyNullability(S, D, Info.getReturnTypeInfo(), Metadata);
 
+  // Add [[clang::unsafe_buffer_usage]]
+  if (Info.UnsafeBufferUsage) {
+    handleAPINotedAttribute<UnsafeBufferUsageAttr>(S, D, true, Metadata, [&]() 
{
+      return UnsafeBufferUsageAttr::Create(S.getASTContext(),
+                                           getPlaceholderAttrInfo());
+    });
+  }
+
   // Parameters.
   unsigned NumParams = FD ? FD->getNumParams() : MD->param_size();
 
diff --git a/clang/test/APINotes/Inputs/Headers/UnsafeBufferUsage.apinotes 
b/clang/test/APINotes/Inputs/Headers/UnsafeBufferUsage.apinotes
new file mode 100644
index 0000000000000..6ebde8f6ffdec
--- /dev/null
+++ b/clang/test/APINotes/Inputs/Headers/UnsafeBufferUsage.apinotes
@@ -0,0 +1,6 @@
+---
+Name: UnsafeBufferUsage
+Functions:
+  - Name: unsafeFunc
+    UnsafeBufferUsage: true
+...
diff --git a/clang/test/APINotes/Inputs/Headers/UnsafeBufferUsage.h 
b/clang/test/APINotes/Inputs/Headers/UnsafeBufferUsage.h
new file mode 100644
index 0000000000000..e80f2e1f0b6d1
--- /dev/null
+++ b/clang/test/APINotes/Inputs/Headers/UnsafeBufferUsage.h
@@ -0,0 +1,2 @@
+void unsafeFunc(int *p, int n);
+void safeFunc(int *p, int n);
diff --git a/clang/test/APINotes/Inputs/Headers/module.modulemap 
b/clang/test/APINotes/Inputs/Headers/module.modulemap
index bedb7d505f794..64ea476e80d8c 100644
--- a/clang/test/APINotes/Inputs/Headers/module.modulemap
+++ b/clang/test/APINotes/Inputs/Headers/module.modulemap
@@ -61,3 +61,8 @@ module SwiftImportAs {
 module SwiftReturnOwnershipForObjC {
   header "SwiftReturnOwnershipForObjC.h"
 }
+
+module UnsafeBufferUsage {
+  header "UnsafeBufferUsage.h"
+  export *
+}
diff --git a/clang/test/APINotes/unsafe-buffer-usage.cpp 
b/clang/test/APINotes/unsafe-buffer-usage.cpp
new file mode 100644
index 0000000000000..03bc4c56e979b
--- /dev/null
+++ b/clang/test/APINotes/unsafe-buffer-usage.cpp
@@ -0,0 +1,23 @@
+// RUN: rm -rf %t && mkdir -p %t
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps 
-fmodules-cache-path=%t/ModulesCache -fdisable-module-hash -fapinotes-modules\
+// RUN:             -I %S/Inputs/Headers %s -x c++ -verify 
-Wunsafe-buffer-usage -Wno-unused-value
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps 
-fmodules-cache-path=%t/ModulesCache -fdisable-module-hash -fapinotes-modules\
+// RUN:             -I %S/Inputs/Headers %s -x c++ -ast-dump -ast-dump-filter 
unsafeFunc | FileCheck %s
+
+#include "UnsafeBufferUsage.h"
+
+// CHECK: FunctionDecl {{.+}} unsafeFunc
+// CHECK: UnsafeBufferUsageAttr
+
+void caller(int *p, int n) {
+  unsafeFunc(p, n); // expected-warning{{function introduces unsafe buffer 
manipulation}}
+  safeFunc(p, n);   // no warning
+}
+
+void unsafeFunc(int *p, int n) {
+  p[n]; // no warning
+}
+
+void safeFunc(int *p, int n) {
+  p[n]; // expected-warning{{unsafe buffer access}}
+}

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to