https://github.com/artemcm updated 
https://github.com/llvm/llvm-project/pull/232743

>From e7b3b8755d5608146f9373aef770b58e6e959788 Mon Sep 17 00:00:00 2001
From: Artem Chikin <[email protected]>
Date: Fri, 25 Sep 2026 11:38:57 +0100
Subject: [PATCH 1/4] [APINotes] Don't give a parameter the API notes of a
 same-named global

Sema processes a parameter's attributes, API notes included, while the 
parameter's `DeclContext` is still the scope around its function. For a 
function at file scope, that scope is the translation unit. This means 
`Sema::ProcessAPINotes` looked up the parameter as a global variable, and gave 
it the notes of any API-noted global with the same name.

A parameter has no API notes entry of its own. Its notes come from its 
function's entry, and `ProcessAPINotes` applies them with the function. So skip 
parameters altogether.
---
 clang/lib/Sema/SemaAPINotes.cpp               |  3 ++
 clang/lib/Sema/SemaDeclObjC.cpp               |  1 -
 .../APINotes/parameter-named-like-global.c    | 35 +++++++++++++++++++
 3 files changed, 38 insertions(+), 1 deletion(-)
 create mode 100644 clang/test/APINotes/parameter-named-like-global.c

diff --git a/clang/lib/Sema/SemaAPINotes.cpp b/clang/lib/Sema/SemaAPINotes.cpp
index c934aa2fee04b..0e38d01dbbcdc 100644
--- a/clang/lib/Sema/SemaAPINotes.cpp
+++ b/clang/lib/Sema/SemaAPINotes.cpp
@@ -1166,6 +1166,9 @@ static void processExactAPINotes(
 void Sema::ProcessAPINotes(Decl *D) {
   if (!D)
     return;
+  // A parameter's notes come from its function's entry.
+  if (isa<ParmVarDecl>(D))
+    return;
   if (!APINotes.hasAPINotes())
     return;
   auto Readers = APINotes.findAPINotes(D->getLocation());
diff --git a/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp
index 4a6fc658575d9..38c68b5c5b624 100644
--- a/clang/lib/Sema/SemaDeclObjC.cpp
+++ b/clang/lib/Sema/SemaDeclObjC.cpp
@@ -4832,7 +4832,6 @@ Decl *SemaObjC::ActOnMethodDeclaration(
   for (unsigned I = 0; I < Sel.getNumArgs(); ++I) {
     ParmVarDecl *Param = ArgInfo[I];
     Param->setDeclContext(ObjCMethod);
-    SemaRef.ProcessAPINotes(Param);
     Params.push_back(Param);
   }
 
diff --git a/clang/test/APINotes/parameter-named-like-global.c 
b/clang/test/APINotes/parameter-named-like-global.c
new file mode 100644
index 0000000000000..c62dc1617199c
--- /dev/null
+++ b/clang/test/APINotes/parameter-named-like-global.c
@@ -0,0 +1,35 @@
+// A parameter takes API notes from its function's entry, never from a lookup
+// of its own. While a parameter's attributes are processed its DeclContext is
+// still the translation unit, so a lookup would find a global variable of the
+// same name and give the parameter that global's notes.
+
+// RUN: rm -rf %t && split-file %s %t
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps 
-fmodules-cache-path=%t/cache -fdisable-module-hash -fapinotes-modules -I %t 
%t/use.c -ast-dump -ast-dump-filter takesShadow -x c | FileCheck 
--check-prefix=PARAM %s
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps 
-fmodules-cache-path=%t/cache -fdisable-module-hash -fapinotes-modules -I %t 
%t/use.c -ast-dump -ast-dump-filter shadow -x c | FileCheck 
--check-prefix=GLOBAL %s
+
+// PARAM: Dumping takesShadow:
+// PARAM-NEXT: FunctionDecl {{.*}} takesShadow 'void (int *)'
+// PARAM-NEXT: ParmVarDecl {{.*}} shadow 'int *'
+// PARAM-EMPTY:
+
+// The global keeps its own notes.
+// GLOBAL: Dumping shadow:
+// GLOBAL-NEXT: VarDecl {{.*}} shadow 'int *'
+// GLOBAL-NEXT: SwiftPrivateAttr
+
+//--- module.modulemap
+module Shadow { header "Shadow.h" export * }
+
+//--- Shadow.apinotes
+Name: Shadow
+Globals:
+  - Name: shadow
+    SwiftPrivate: true
+
+//--- Shadow.h
+extern int *shadow;
+void takesShadow(int *shadow);
+
+//--- use.c
+#include "Shadow.h"
+void caller(void) { takesShadow(shadow); }

>From 3bae4397c0748fa882f21038b0dc94fa4cfd7883 Mon Sep 17 00:00:00 2001
From: Artem Chikin <[email protected]>
Date: Wed, 23 Sep 2026 11:00:37 +0100
Subject: [PATCH 2/4] [APINotes][NFC] Factor out the kind-erased core of
 handleAPINotedAttribute

`handleAPINotedAttribute<A>` uses the attribute's static type in three places:
- The kind that a removal records
- The type that `CreateAttr` returns
= The default displacement check.

Move its body into `handleAPINotedAttributeImpl`, which takes the kind as a 
value, returns `Attr *`, and needs only the `ASTContext`. The existing template 
forwards to it. A caller that knows the kind only at run time can then apply an 
attribute with the default mode's rules, even without `Sema`.

The main complexity is in which existing key a given attribute may displace. 
Most keys displace the first attribute of the same kind. Three keys
displace something else:
- `UnavailableInSwift`
- `SwiftSafety`
- Retain-count conventions

Each of them is the only key that produces its attribute kinds, so the kind 
selects the displacement rule. `isDisplacedBy` encodes the rule for each kind, 
and `findAttrDisplacedBy` replaces the predicate that each call site passed.
---
 clang/lib/Sema/SemaAPINotes.cpp | 168 ++++++++++++++++++--------------
 1 file changed, 96 insertions(+), 72 deletions(-)

diff --git a/clang/lib/Sema/SemaAPINotes.cpp b/clang/lib/Sema/SemaAPINotes.cpp
index 0e38d01dbbcdc..e9a2c7d4987c9 100644
--- a/clang/lib/Sema/SemaAPINotes.cpp
+++ b/clang/lib/Sema/SemaAPINotes.cpp
@@ -138,24 +138,84 @@ template <typename A> struct AttrKindFor {};
     static const attr::Kind value = attr::X;                                   
\
   };
 #include "clang/Basic/AttrList.inc"
+} // namespace
+
+//------------------------------------------------------------------------------
+// Displacement predicates
+//
+// Most API notes keys displace "the first attribute of the same kind".
+// The following three do not: isDisplacedBy, which every application goes
+// through, dispatches to them by kind.
+//------------------------------------------------------------------------------
+
+/// A Swift-platform availability attribute, which `UnavailableInSwift`
+/// displaces. A non-Swift availability attribute is untouched.
+static bool isSwiftAvailabilityAttr(const Attr *A) {
+  if (const auto *AA = dyn_cast<AvailabilityAttr>(A))
+    if (const auto *II = AA->getPlatform())
+      return II->isStr("swift");
+  return false;
+}
+
+/// A `swift_attr` carrying a safety verdict, which `SwiftSafety` displaces.
+static bool isSwiftSafetyAttr(const Attr *A) {
+  if (const auto *SA = dyn_cast<SwiftAttrAttr>(A))
+    return SA->getAttribute() == "safe" || SA->getAttribute() == "unsafe";
+  return false;
+}
+
+/// Any retain-count convention attribute. The conventions are mutually
+/// exclusive, so setting one displaces whichever of the six is present.
+static bool isRetainCountConventionAttr(const Attr *A) {
+  return isa<CFUnknownTransferAttr, CFReturnsRetainedAttr,
+             CFReturnsNotRetainedAttr, NSReturnsRetainedAttr,
+             NSReturnsNotRetainedAttr, CFAuditedTransferAttr>(A);
+}
+
+/// Whether an API note of kind \p Kind displaces the existing attribute \p A.
+static bool isDisplacedBy(const Attr *A, attr::Kind Kind) {
+  switch (Kind) {
+  case attr::Availability:
+    return isSwiftAvailabilityAttr(A);
+  case attr::SwiftAttr:
+    return isSwiftSafetyAttr(A);
+  case attr::CFUnknownTransfer:
+  case attr::CFReturnsRetained:
+  case attr::CFReturnsNotRetained:
+  case attr::NSReturnsRetained:
+  case attr::NSReturnsNotRetained:
+    return isRetainCountConventionAttr(A);
+  default:
+    return A->getKind() == Kind;
+  }
+}
+
+/// The existing attribute an API note of kind \p Kind displaces, which is the
+/// first one it displaces.
+static Decl::attr_iterator findAttrDisplacedBy(const Decl *D, attr::Kind Kind) 
{
+  return llvm::find_if(D->attrs(), [Kind](const Attr *Next) {
+    return isDisplacedBy(Next, Kind);
+  });
+}
 
 /// Handle an attribute introduced by API notes.
 ///
 /// \param IsAddition Whether we should add a new attribute
 /// (otherwise, we might remove an existing attribute).
+/// \param Kind The kind being added or removed. A removal records it, and it
+/// decides which existing attribute an active slice displaces.
 /// \param CreateAttr Create the new attribute to be added.
-template <typename A>
-void handleAPINotedAttribute(
-    Sema &S, Decl *D, bool IsAddition, VersionedInfoMetadata Metadata,
-    llvm::function_ref<A *()> CreateAttr,
-    llvm::function_ref<Decl::attr_iterator(const Decl *)> GetExistingAttr) {
+static void
+handleAPINotedAttributeImpl(ASTContext &Ctx, Decl *D, bool IsAddition,
+                            VersionedInfoMetadata Metadata, attr::Kind Kind,
+                            llvm::function_ref<Attr *()> CreateAttr) {
   if (Metadata.IsActive) {
-    auto Existing = GetExistingAttr(D);
+    const auto *Existing = findAttrDisplacedBy(D, Kind);
     if (Existing != D->attr_end()) {
       // Remove the existing attribute, and treat it as a superseded
       // non-versioned attribute.
       auto *Versioned = SwiftVersionedAdditionAttr::CreateImplicit(
-          S.Context, Metadata.Version, *Existing, /*IsReplacedByActive*/ true,
+          Ctx, Metadata.Version, *Existing, /*IsReplacedByActive*/ true,
           Metadata.SliceGroup);
 
       D->getAttrs().erase(Existing);
@@ -164,16 +224,16 @@ void handleAPINotedAttribute(
 
     // If we're supposed to add a new attribute, do so.
     if (IsAddition) {
-      if (auto Attr = CreateAttr())
+      if (auto *Attr = CreateAttr())
         D->addAttr(Attr);
     }
 
     return;
   }
   if (IsAddition) {
-    if (auto Attr = CreateAttr()) {
+    if (auto *Attr = CreateAttr()) {
       auto *Versioned = SwiftVersionedAdditionAttr::CreateImplicit(
-          S.Context, Metadata.Version, Attr,
+          Ctx, Metadata.Version, Attr,
           /*IsReplacedByActive*/ Metadata.IsReplacement, Metadata.SliceGroup);
       D->addAttr(Versioned);
     }
@@ -182,23 +242,20 @@ void handleAPINotedAttribute(
     // availability, where we're trying to remove a /specific/ kind of
     // attribute.
     auto *Versioned = SwiftVersionedRemovalAttr::CreateImplicit(
-        S.Context, Metadata.Version, AttrKindFor<A>::value,
+        Ctx, Metadata.Version, Kind,
         /*IsReplacedByActive*/ Metadata.IsReplacement, Metadata.SliceGroup);
     D->addAttr(Versioned);
   }
 }
 
+/// Handle an attribute introduced by API notes, naming it statically.
 template <typename A>
-void handleAPINotedAttribute(Sema &S, Decl *D, bool ShouldAddAttribute,
-                             VersionedInfoMetadata Metadata,
-                             llvm::function_ref<A *()> CreateAttr) {
-  handleAPINotedAttribute<A>(
-      S, D, ShouldAddAttribute, Metadata, CreateAttr, [](const Decl *D) {
-        return llvm::find_if(D->attrs(),
-                             [](const Attr *Next) { return isa<A>(Next); });
-      });
+static void handleAPINotedAttribute(Sema &S, Decl *D, bool IsAddition,
+                                    VersionedInfoMetadata Metadata,
+                                    llvm::function_ref<A *()> CreateAttr) {
+  handleAPINotedAttributeImpl(S.Context, D, IsAddition, Metadata,
+                              AttrKindFor<A>::value, CreateAttr);
 }
-} // namespace
 
 template <typename A>
 static void handleAPINotedRetainCountAttribute(Sema &S, Decl *D,
@@ -206,18 +263,9 @@ static void handleAPINotedRetainCountAttribute(Sema &S, 
Decl *D,
                                                VersionedInfoMetadata Metadata) 
{
   // The template argument has a default to make the "removal" case more
   // concise; it doesn't matter /which/ attribute is being removed.
-  handleAPINotedAttribute<A>(
-      S, D, ShouldAddAttribute, Metadata,
-      [&] { return new (S.Context) A(S.Context, getPlaceholderAttrInfo()); },
-      [](const Decl *D) -> Decl::attr_iterator {
-        return llvm::find_if(D->attrs(), [](const Attr *Next) -> bool {
-          return isa<CFReturnsRetainedAttr>(Next) ||
-                 isa<CFReturnsNotRetainedAttr>(Next) ||
-                 isa<NSReturnsRetainedAttr>(Next) ||
-                 isa<NSReturnsNotRetainedAttr>(Next) ||
-                 isa<CFAuditedTransferAttr>(Next);
-        });
-      });
+  handleAPINotedAttribute<A>(S, D, ShouldAddAttribute, Metadata, [&] {
+    return new (S.Context) A(S.Context, getPlaceholderAttrInfo());
+  });
 }
 
 static void handleAPINotedRetainCountConvention(
@@ -276,28 +324,17 @@ static void ProcessAPINotes(Sema &S, Decl *D,
   }
 
   if (Info.UnavailableInSwift) {
-    handleAPINotedAttribute<AvailabilityAttr>(
-        S, D, true, Metadata,
-        [&] {
-          return new (S.Context) AvailabilityAttr(
-              S.Context, getPlaceholderAttrInfo(),
-              &S.Context.Idents.get("swift"), VersionTuple(), VersionTuple(),
-              VersionTuple(),
-              /*Unavailable=*/true,
-              ASTAllocateString(S.Context, Info.UnavailableMsg),
-              /*Strict=*/false,
-              /*Replacement=*/StringRef(),
-              /*Priority=*/Sema::AP_Explicit,
-              /*Environment=*/nullptr);
-        },
-        [](const Decl *D) {
-          return llvm::find_if(D->attrs(), [](const Attr *next) -> bool {
-            if (const auto *AA = dyn_cast<AvailabilityAttr>(next))
-              if (const auto *II = AA->getPlatform())
-                return II->isStr("swift");
-            return false;
-          });
-        });
+    handleAPINotedAttribute<AvailabilityAttr>(S, D, true, Metadata, [&] {
+      return new (S.Context) AvailabilityAttr(
+          S.Context, getPlaceholderAttrInfo(), &S.Context.Idents.get("swift"),
+          VersionTuple(), VersionTuple(), VersionTuple(),
+          /*Unavailable=*/true,
+          ASTAllocateString(S.Context, Info.UnavailableMsg),
+          /*Strict=*/false,
+          /*Replacement=*/StringRef(),
+          /*Priority=*/Sema::AP_Explicit,
+          /*Environment=*/nullptr);
+    });
   }
 
   // swift_private
@@ -312,24 +349,11 @@ static void ProcessAPINotes(Sema &S, Decl *D,
   // swift_safety
   if (auto SafetyKind = Info.getSwiftSafety()) {
     bool Addition = *SafetyKind != api_notes::SwiftSafetyKind::Unspecified;
-    handleAPINotedAttribute<SwiftAttrAttr>(
-        S, D, Addition, Metadata,
-        [&] {
-          return SwiftAttrAttr::Create(
-              S.Context, *SafetyKind == api_notes::SwiftSafetyKind::Safe
-                             ? "safe"
-                             : "unsafe");
-        },
-        [](const Decl *D) {
-          return llvm::find_if(D->attrs(), [](const Attr *attr) {
-            if (const auto *swiftAttr = dyn_cast<SwiftAttrAttr>(attr)) {
-              if (swiftAttr->getAttribute() == "safe" ||
-                  swiftAttr->getAttribute() == "unsafe")
-                return true;
-            }
-            return false;
-          });
-        });
+    handleAPINotedAttribute<SwiftAttrAttr>(S, D, Addition, Metadata, [&] {
+      return SwiftAttrAttr::Create(
+          S.Context,
+          *SafetyKind == api_notes::SwiftSafetyKind::Safe ? "safe" : "unsafe");
+    });
   }
 
   // swift_name

>From 2beb32e72af35e52b1c29afd72df2c4bbe9fa214 Mon Sep 17 00:00:00 2001
From: Artem Chikin <[email protected]>
Date: Fri, 25 Sep 2026 11:45:46 +0100
Subject: [PATCH 3/4] [APINotes][NFC] Factor Sema-free cores out of type and
 nullability notes

To apply a `Type:` or `ResultType:` note, Sema parses the type, adjusts and 
checks it against the declaration, and installs it. Only the parse needs `Sema`.

Previously, SemaAPINotes had to separate code-paths to do this:
1. `Sema::ApplyAPINotesType`, which handled `Type:` notes on `VarDecl`, 
`ObjCPropertyDecl`, and `FieldDecl. It took care of calling into the 
type-parsing code (`ParseTypeFromStringCallback`), and ultimately mutating the 
decl.
2. In `ProcessAPINotes` inline code handled `ResultType:` notes on 
`FunctionDecl`sand `ObjCMethodDecl`s, similarly calling into type-parsing code 
and rebuilding the resulting mutated decl.

This change splits this into 3 different parts:
1. A new `parseAPINotesType` (requires Sema), which handles type parsing for 
all declaration kinds and builds a type info and returns a 
`ParsedAPINotesType{Type, TypeInfo}.
2. `applyTypeToDecl` (does not require Sema, requires ASTContext), which 
installs `{Type, TypeInfo}` onto all relevant declaration kinds.
3. `rebuildFunctionType` (does not require Sema, requires ASTContext), which 
rebuilds `FD->getType()` and replaces three different places in SemaAPINotes 
that previously handled `FunctionProtoType`/`FunctionNoProtoType` rebuild.

Nullability annotations, similarly to type annotations directly mutated the 
decl, when applied.
Previously, SemaAPINotes had:
1. `Sema::ApplyNullability` modified a decl's type by calling 
`CheckImplicitNullabilityTypeSpecifier`.
2. `CheckImplicitNullabilityTypeSpecifier` forwarded to an overlaod of 
`CheckNullabilityTypeSpecifier` with `State = nullptr` and `OverrideExisting = 
true`.
    a. This configuration skipped all Sema operations.

This change simplifies it into:
1. `Sema::OverrideImplicitNullability`, which replaces 
`CheckImplicitNullabilityTypeSpecifier` with a `static` method which takes an 
`ASTContext` instead of `Sema`.
2. `applyNullabilityToDecl`, which contains the body of 
`Sema::ApplyNullability`, calling `Sema::OverrideImplicitNullability` and 
`rebuildFunctionType` using only `ASTContext`.
---
 clang/include/clang/Sema/Sema.h |  36 ++----
 clang/lib/Sema/SemaAPINotes.cpp | 207 ++++++++++++++++++--------------
 clang/lib/Sema/SemaType.cpp     |  93 ++++++--------
 3 files changed, 164 insertions(+), 172 deletions(-)

diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 865defa98a1b3..0fcf58add4264 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -1693,12 +1693,10 @@ class Sema final : public SemaBase {
   /// declaration processed in this translation unit.
   void DiagnoseUnusedAPINotesSelectors();
 
-  /// Whether APINotes should be gathered for all applicable Swift language
-  /// versions, without being applied. Leaving clients of the current module
-  /// to select and apply the correct version.
-  bool captureSwiftVersionIndependentAPINotes() {
-    return APINotes.captureVersionIndependentSwift();
-  }
+  /// Whether API notes should be gathered for all applicable Swift language
+  /// versions, without being applied, leaving clients of the current module to
+  /// select and apply the correct version.
+  bool captureSwiftVersionIndependentAPINotes();
   ///@}
 
   //
@@ -15546,28 +15544,14 @@ class Sema final : public SemaBase {
   // one that came from a typedef.
   bool hasExplicitCallingConv(QualType T);
 
-  /// Check whether a nullability type specifier can be added to the given
-  /// type through some means not written in source (e.g. API notes).
-  ///
-  /// \param Type The type to which the nullability specifier will be
-  /// added. On success, this type will be updated appropriately.
-  ///
-  /// \param Nullability The nullability specifier to add.
-  ///
-  /// \param DiagLoc The location to use for diagnostics.
-  ///
-  /// \param AllowArrayTypes Whether to accept nullability specifiers on an
-  /// array type (e.g., because it will decay to a pointer).
-  ///
-  /// \param OverrideExisting Whether to override an existing, 
locally-specified
-  /// nullability specifier rather than complaining about the conflict.
+  /// Add \p Nullability to \p Type, replacing any nullability specifier
+  /// \p Type carries locally. Emits no diagnostics, so it needs no Sema.
+  /// Also sued by the collapse of captured version-independent API notes.
   ///
   /// \returns true if nullability cannot be applied, false otherwise.
-  bool CheckImplicitNullabilityTypeSpecifier(QualType &Type,
-                                             NullabilityKind Nullability,
-                                             SourceLocation DiagLoc,
-                                             bool AllowArrayTypes,
-                                             bool OverrideExisting);
+  static bool OverrideImplicitNullability(ASTContext &Context, QualType &Type,
+                                          NullabilityKind Nullability,
+                                          bool AllowArrayTypes);
 
   /// Check whether the given variable declaration has a size that fits within
   /// the address space it is declared in. This issues a diagnostic if not.
diff --git a/clang/lib/Sema/SemaAPINotes.cpp b/clang/lib/Sema/SemaAPINotes.cpp
index e9a2c7d4987c9..802cb8894d715 100644
--- a/clang/lib/Sema/SemaAPINotes.cpp
+++ b/clang/lib/Sema/SemaAPINotes.cpp
@@ -58,6 +58,14 @@ static bool isIndirectPointerType(QualType Type) {
          Pointee->isMemberPointerType();
 }
 
+namespace {
+/// A replacement type parsed and validated from an API note.
+struct ParsedAPINotesType {
+  QualType Type;
+  TypeSourceInfo *TypeInfo;
+};
+} // namespace
+
 static void applyAPINotesType(Sema &S, Decl *decl, StringRef typeString,
                               VersionedInfoMetadata metadata) {
   if (typeString.empty())
@@ -424,69 +432,105 @@ static bool checkAPINotesReplacementType(Sema &S, 
SourceLocation Loc,
   return false;
 }
 
-void Sema::ApplyAPINotesType(Decl *D, StringRef TypeString) {
-  if (!TypeString.empty() && ParseTypeFromStringCallback) {
-    auto ParsedType = ParseTypeFromStringCallback(TypeString, "<API Notes>",
-                                                  D->getLocation());
-    if (ParsedType.isUsable()) {
-      QualType Type = Sema::GetTypeFromParser(ParsedType.get());
-      auto TypeInfo = Context.getTrivialTypeSourceInfo(Type, D->getLocation());
-      if (auto Var = dyn_cast<VarDecl>(D)) {
-        // Make adjustments to parameter types.
-        if (isa<ParmVarDecl>(Var)) {
-          Type = ObjC().AdjustParameterTypeForObjCAutoRefCount(
-              Type, D->getLocation(), TypeInfo);
-          Type = Context.getAdjustedParameterType(Type);
-        }
+/// Rebuild \p FD's type from its parameters' types, and from \p ResultType if
+/// given, as ProcessAPINotes does once API notes changed either. An
+/// unprototyped function takes no parameter types, so it is rebuilt only for a
+/// new result type.
+static void rebuildFunctionType(ASTContext &Ctx, FunctionDecl *FD,
+                                std::optional<QualType> ResultType) {
+  if (const auto *Proto = FD->getType()->getAs<FunctionProtoType>()) {
+    SmallVector<QualType, 4> ParamTypes;
+    for (const ParmVarDecl *Param : FD->parameters())
+      ParamTypes.push_back(Param->getType());
+    
FD->setType(Ctx.getFunctionType(ResultType.value_or(Proto->getReturnType()),
+                                    ParamTypes, Proto->getExtProtoInfo()));
+  } else if (ResultType) {
+    FD->setType(Ctx.getFunctionNoProtoType(
+        *ResultType,
+        FD->getType()->castAs<FunctionNoProtoType>()->getExtInfo()));
+  }
+}
 
-        if (!checkAPINotesReplacementType(*this, Var->getLocation(),
-                                          Var->getType(), Type)) {
-          Var->setType(Type);
-          Var->setTypeSourceInfo(TypeInfo);
-        }
-      } else if (auto property = dyn_cast<ObjCPropertyDecl>(D)) {
-        if (!checkAPINotesReplacementType(*this, property->getLocation(),
-                                          property->getType(), Type)) {
-          property->setType(Type, TypeInfo);
-        }
-      } else if (auto field = dyn_cast<FieldDecl>(D)) {
-        if (!checkAPINotesReplacementType(*this, field->getLocation(),
-                                          field->getType(), Type)) {
-          field->setType(Type);
-          field->setTypeSourceInfo(TypeInfo);
-        }
-      } else {
-        llvm_unreachable("API notes allowed a type on an unknown declaration");
-      }
+/// Install a replacement type on \p D, as ProcessAPINotes does once it has
+/// parsed, adjusted and checked it; for a function or method, its result type.
+/// Needs no Sema.
+static void applyTypeToDecl(ASTContext &Ctx, Decl *D, QualType Type,
+                            TypeSourceInfo *TypeInfo) {
+  if (auto *Var = dyn_cast<VarDecl>(D)) {
+    Var->setType(Type);
+    Var->setTypeSourceInfo(TypeInfo);
+  } else if (auto *Property = dyn_cast<ObjCPropertyDecl>(D)) {
+    Property->setType(Type, TypeInfo);
+  } else if (auto *Field = dyn_cast<FieldDecl>(D)) {
+    Field->setType(Type);
+    Field->setTypeSourceInfo(TypeInfo);
+  } else if (auto *Method = dyn_cast<ObjCMethodDecl>(D)) {
+    Method->setReturnType(Type);
+    Method->setReturnTypeSourceInfo(TypeInfo);
+  } else if (auto *Function = dyn_cast<FunctionDecl>(D)) {
+    rebuildFunctionType(Ctx, Function, Type);
+  } else {
+    llvm_unreachable("API notes allowed a type on an unknown declaration");
+  }
+}
+
+static std::optional<ParsedAPINotesType>
+parseAPINotesType(Sema &S, Decl *D, StringRef TypeString) {
+  if (TypeString.empty() || !S.ParseTypeFromStringCallback)
+    return std::nullopt;
+  auto ParsedType = S.ParseTypeFromStringCallback(TypeString, "<API Notes>",
+                                                  D->getLocation());
+  if (!ParsedType.isUsable())
+    return std::nullopt;
+  QualType Type = Sema::GetTypeFromParser(ParsedType.get());
+  auto *TypeInfo = S.Context.getTrivialTypeSourceInfo(Type, D->getLocation());
+  QualType OrigType;
+  if (auto *Var = dyn_cast<VarDecl>(D)) {
+    // Make adjustments to parameter types.
+    if (isa<ParmVarDecl>(Var)) {
+      Type = S.ObjC().AdjustParameterTypeForObjCAutoRefCount(
+          Type, D->getLocation(), TypeInfo);
+      Type = S.Context.getAdjustedParameterType(Type);
     }
+    OrigType = Var->getType();
+  } else if (auto *Property = dyn_cast<ObjCPropertyDecl>(D)) {
+    OrigType = Property->getType();
+  } else if (auto *Field = dyn_cast<FieldDecl>(D)) {
+    OrigType = Field->getType();
+  } else if (auto *Method = dyn_cast<ObjCMethodDecl>(D)) {
+    OrigType = Method->getReturnType();
+  } else if (auto *Function = dyn_cast<FunctionDecl>(D)) {
+    OrigType = Function->getReturnType();
+  } else {
+    llvm_unreachable("API notes allowed a type on an unknown declaration");
   }
+  if (checkAPINotesReplacementType(S, D->getLocation(), OrigType, Type))
+    return std::nullopt;
+  return ParsedAPINotesType{Type, TypeInfo};
 }
 
-void Sema::ApplyNullability(Decl *D, NullabilityKind Nullability) {
-  auto GetModified =
-      [&](class Decl *D, QualType QT,
-          NullabilityKind Nullability) -> std::optional<QualType> {
+void Sema::ApplyAPINotesType(Decl *D, StringRef TypeString) {
+  if (auto Parsed = parseAPINotesType(*this, D, TypeString))
+    applyTypeToDecl(Context, D, Parsed->Type, Parsed->TypeInfo);
+}
+
+/// Apply 'Nullability:' to \p D, as Sema::ApplyNullability does. Needs no
+/// Sema.
+static void applyNullabilityToDecl(ASTContext &Context, Decl *D,
+                                   NullabilityKind Nullability) {
+  auto GetModified = [&](QualType QT) -> std::optional<QualType> {
     QualType Original = QT;
-    CheckImplicitNullabilityTypeSpecifier(QT, Nullability, D->getLocation(),
-                                          isa<ParmVarDecl>(D),
-                                          /*OverrideExisting=*/true);
+    Sema::OverrideImplicitNullability(Context, QT, Nullability,
+                                      isa<ParmVarDecl>(D));
     return (QT.getTypePtr() != Original.getTypePtr()) ? std::optional(QT)
                                                       : std::nullopt;
   };
 
-  if (auto Function = dyn_cast<FunctionDecl>(D)) {
-    if (auto Modified =
-            GetModified(D, Function->getReturnType(), Nullability)) {
-      const FunctionType *FnType = Function->getType()->castAs<FunctionType>();
-      if (const FunctionProtoType *proto = dyn_cast<FunctionProtoType>(FnType))
-        Function->setType(Context.getFunctionType(
-            *Modified, proto->getParamTypes(), proto->getExtProtoInfo()));
-      else
-        Function->setType(
-            Context.getFunctionNoProtoType(*Modified, FnType->getExtInfo()));
-    }
-  } else if (auto Method = dyn_cast<ObjCMethodDecl>(D)) {
-    if (auto Modified = GetModified(D, Method->getReturnType(), Nullability)) {
+  if (auto *Function = dyn_cast<FunctionDecl>(D)) {
+    if (auto Modified = GetModified(Function->getReturnType()))
+      rebuildFunctionType(Context, Function, *Modified);
+  } else if (auto *Method = dyn_cast<ObjCMethodDecl>(D)) {
+    if (auto Modified = GetModified(Method->getReturnType())) {
       Method->setReturnType(*Modified);
 
       // Make it a context-sensitive keyword if we can.
@@ -494,19 +538,19 @@ void Sema::ApplyNullability(Decl *D, NullabilityKind 
Nullability) {
         Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
             Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
     }
-  } else if (auto Value = dyn_cast<ValueDecl>(D)) {
-    if (auto Modified = GetModified(D, Value->getType(), Nullability)) {
+  } else if (auto *Value = dyn_cast<ValueDecl>(D)) {
+    if (auto Modified = GetModified(Value->getType())) {
       Value->setType(*Modified);
 
       // Make it a context-sensitive keyword if we can.
-      if (auto Parm = dyn_cast<ParmVarDecl>(D)) {
+      if (auto *Parm = dyn_cast<ParmVarDecl>(D)) {
         if (Parm->isObjCMethodParameter() && !isIndirectPointerType(*Modified))
           Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
               Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
       }
     }
-  } else if (auto Property = dyn_cast<ObjCPropertyDecl>(D)) {
-    if (auto Modified = GetModified(D, Property->getType(), Nullability)) {
+  } else if (auto *Property = dyn_cast<ObjCPropertyDecl>(D)) {
+    if (auto Modified = GetModified(Property->getType())) {
       Property->setType(*Modified, Property->getTypeSourceInfo());
 
       // Make it a property attribute if we can.
@@ -517,6 +561,10 @@ void Sema::ApplyNullability(Decl *D, NullabilityKind 
Nullability) {
   }
 }
 
+void Sema::ApplyNullability(Decl *D, NullabilityKind Nullability) {
+  applyNullabilityToDecl(Context, D, Nullability);
+}
+
 /// Process API notes for a variable or property.
 static void ProcessAPINotes(Sema &S, Decl *D,
                             const api_notes::VariableInfo &Info,
@@ -649,25 +697,13 @@ static void ProcessAPINotes(Sema &S, FunctionOrMethod 
AnyFunc,
     addSwiftAttrIfAbsent(S, D, "returns_" + Info.SwiftReturnOwnership);
 
   // Result type override.
-  QualType OverriddenResultType;
-  if (Metadata.IsActive && !Info.ResultType.empty() &&
-      S.ParseTypeFromStringCallback) {
-    auto ParsedType = S.ParseTypeFromStringCallback(
-        Info.ResultType, "<API Notes>", D->getLocation());
-    if (ParsedType.isUsable()) {
-      QualType ResultType = Sema::GetTypeFromParser(ParsedType.get());
-
+  std::optional<QualType> OverriddenResultType;
+  if (Metadata.IsActive) {
+    if (auto Parsed = parseAPINotesType(S, D, Info.ResultType)) {
       if (MD) {
-        if (!checkAPINotesReplacementType(S, D->getLocation(),
-                                          MD->getReturnType(), ResultType)) {
-          auto ResultTypeInfo =
-              S.Context.getTrivialTypeSourceInfo(ResultType, D->getLocation());
-          MD->setReturnType(ResultType);
-          MD->setReturnTypeSourceInfo(ResultTypeInfo);
-        }
-      } else if (!checkAPINotesReplacementType(
-                     S, FD->getLocation(), FD->getReturnType(), ResultType)) {
-        OverriddenResultType = ResultType;
+        applyTypeToDecl(S.Context, MD, Parsed->Type, Parsed->TypeInfo);
+      } else {
+        OverriddenResultType = Parsed->Type;
         AnyTypeChanged = true;
       }
     }
@@ -675,23 +711,8 @@ static void ProcessAPINotes(Sema &S, FunctionOrMethod 
AnyFunc,
 
   // If the result type or any of the parameter types changed for a function
   // declaration, we have to rebuild the type.
-  if (FD && AnyTypeChanged) {
-    if (const auto *fnProtoType = FD->getType()->getAs<FunctionProtoType>()) {
-      if (OverriddenResultType.isNull())
-        OverriddenResultType = fnProtoType->getReturnType();
-
-      SmallVector<QualType, 4> ParamTypes;
-      for (auto Param : FD->parameters())
-        ParamTypes.push_back(Param->getType());
-
-      FD->setType(S.Context.getFunctionType(OverriddenResultType, ParamTypes,
-                                            fnProtoType->getExtProtoInfo()));
-    } else if (!OverriddenResultType.isNull()) {
-      const auto *FnNoProtoType = FD->getType()->castAs<FunctionNoProtoType>();
-      FD->setType(S.Context.getFunctionNoProtoType(
-          OverriddenResultType, FnNoProtoType->getExtInfo()));
-    }
-  }
+  if (FD && AnyTypeChanged)
+    rebuildFunctionType(S.Context, FD, OverriddenResultType);
 
   // Retain count convention
   handleAPINotedRetainCountConvention(S, D, Metadata,
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index 3d444bfabc8c3..19e67c1110cdd 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -7512,13 +7512,15 @@ static NullabilityKind 
mapNullabilityAttrKind(ParsedAttr::Kind kind) {
   }
 }
 
-static bool CheckNullabilityTypeSpecifier(
-    Sema &S, TypeProcessingState *State, ParsedAttr *PAttr, QualType &QT,
-    NullabilityKind Nullability, SourceLocation NullabilityLoc,
-    bool IsContextSensitive, bool AllowOnArrayType, bool OverrideExisting) {
-  bool Implicit = (State == nullptr);
-  if (!Implicit)
-    recordNullabilitySeen(S, NullabilityLoc);
+static bool CheckNullabilityTypeSpecifier(TypeProcessingState &State,
+                                          QualType &QT, ParsedAttr &PAttr,
+                                          bool AllowOnArrayType) {
+  NullabilityKind Nullability = mapNullabilityAttrKind(PAttr.getKind());
+  SourceLocation NullabilityLoc = PAttr.getLoc();
+  bool IsContextSensitive = PAttr.isContextSensitiveKeywordAttribute();
+
+  Sema &S = State.getSema();
+  recordNullabilitySeen(S, NullabilityLoc);
 
   // Check for existing nullability attributes on the type.
   QualType Desugared = QT;
@@ -7527,9 +7529,6 @@ static bool CheckNullabilityTypeSpecifier(
     if (auto ExistingNullability = Attributed->getImmediateNullability()) {
       // Duplicated nullability.
       if (Nullability == *ExistingNullability) {
-        if (Implicit)
-          break;
-
         S.Diag(NullabilityLoc, diag::warn_nullability_duplicate)
             << DiagNullabilityKind(Nullability, IsContextSensitive)
             << FixItHint::CreateRemoval(NullabilityLoc);
@@ -7537,16 +7536,11 @@ static bool CheckNullabilityTypeSpecifier(
         break;
       }
 
-      if (!OverrideExisting) {
-        // Conflicting nullability.
-        S.Diag(NullabilityLoc, diag::err_nullability_conflicting)
-            << DiagNullabilityKind(Nullability, IsContextSensitive)
-            << DiagNullabilityKind(*ExistingNullability, false);
-        return true;
-      }
-
-      // Rebuild the attributed type, dropping the existing nullability.
-      QT = rebuildAttributedTypeWithoutNullability(S.Context, QT);
+      // Conflicting nullability.
+      S.Diag(NullabilityLoc, diag::err_nullability_conflicting)
+          << DiagNullabilityKind(Nullability, IsContextSensitive)
+          << DiagNullabilityKind(*ExistingNullability, false);
+      return true;
     }
 
     Desugared = Attributed->getModifiedType();
@@ -7557,13 +7551,13 @@ static bool CheckNullabilityTypeSpecifier(
   // have nullability specifiers on them, which means we cannot
   // provide a useful Fix-It.
   if (auto ExistingNullability = Desugared->getNullability()) {
-    if (Nullability != *ExistingNullability && !Implicit) {
+    if (Nullability != *ExistingNullability) {
       S.Diag(NullabilityLoc, diag::err_nullability_conflicting)
           << DiagNullabilityKind(Nullability, IsContextSensitive)
           << DiagNullabilityKind(*ExistingNullability, false);
 
       // Try to find the typedef with the existing nullability specifier.
-      if (auto TT = Desugared->getAs<TypedefType>()) {
+      if (const auto *TT = Desugared->getAs<TypedefType>()) {
         TypedefNameDecl *typedefDecl = TT->getDecl();
         QualType underlyingType = typedefDecl->getUnderlyingType();
         if (auto typedefNullability =
@@ -7582,9 +7576,8 @@ static bool CheckNullabilityTypeSpecifier(
   // If this definitely isn't a pointer type, reject the specifier.
   if (!Desugared->canHaveNullability() &&
       !(AllowOnArrayType && Desugared->isArrayType())) {
-    if (!Implicit)
-      S.Diag(NullabilityLoc, diag::err_nullability_nonpointer)
-          << DiagNullabilityKind(Nullability, IsContextSensitive) << QT;
+    S.Diag(NullabilityLoc, diag::err_nullability_nonpointer)
+        << DiagNullabilityKind(Nullability, IsContextSensitive) << QT;
 
     return true;
   }
@@ -7613,37 +7606,31 @@ static bool CheckNullabilityTypeSpecifier(
   }
 
   // Form the attributed type.
-  if (State) {
-    assert(PAttr);
-    Attr *A = createNullabilityAttr(S.Context, *PAttr, Nullability);
-    QT = State->getAttributedType(A, QT, QT);
-  } else {
-    QT = S.Context.getAttributedType(Nullability, QT, QT);
-  }
+  Attr *A = createNullabilityAttr(S.Context, PAttr, Nullability);
+  QT = State.getAttributedType(A, QT, QT);
   return false;
 }
 
-static bool CheckNullabilityTypeSpecifier(TypeProcessingState &State,
-                                          QualType &Type, ParsedAttr &Attr,
-                                          bool AllowOnArrayType) {
-  NullabilityKind Nullability = mapNullabilityAttrKind(Attr.getKind());
-  SourceLocation NullabilityLoc = Attr.getLoc();
-  bool IsContextSensitive = Attr.isContextSensitiveKeywordAttribute();
-
-  return CheckNullabilityTypeSpecifier(State.getSema(), &State, &Attr, Type,
-                                       Nullability, NullabilityLoc,
-                                       IsContextSensitive, AllowOnArrayType,
-                                       /*overrideExisting*/ false);
-}
-
-bool Sema::CheckImplicitNullabilityTypeSpecifier(QualType &Type,
-                                                 NullabilityKind Nullability,
-                                                 SourceLocation DiagLoc,
-                                                 bool AllowArrayTypes,
-                                                 bool OverrideExisting) {
-  return CheckNullabilityTypeSpecifier(
-      *this, nullptr, nullptr, Type, Nullability, DiagLoc,
-      /*isContextSensitive*/ false, AllowArrayTypes, OverrideExisting);
+bool Sema::OverrideImplicitNullability(ASTContext &Context, QualType &Type,
+                                       NullabilityKind Nullability,
+                                       bool AllowArrayTypes) {
+  // Drop the nullability the type carries locally, unless it is this one.
+  QualType Desugared = Type;
+  while (auto *Attributed = dyn_cast<AttributedType>(Desugared.getTypePtr())) {
+    if (auto ExistingNullability = Attributed->getImmediateNullability()) {
+      if (Nullability == *ExistingNullability)
+        return false;
+      Type = rebuildAttributedTypeWithoutNullability(Context, Type);
+    }
+    Desugared = Attributed->getModifiedType();
+  }
+
+  if (!Desugared->canHaveNullability() &&
+      !(AllowArrayTypes && Desugared->isArrayType()))
+    return true;
+
+  Type = Context.getAttributedType(Nullability, Type, Type);
+  return false;
 }
 
 bool Sema::CheckVarDeclSizeAddressSpace(const VarDecl *VD, LangAS AS) {

>From 3d60c44f7bddf8c7e46041cbff6956c86f20899d Mon Sep 17 00:00:00 2001
From: Artem Chikin <[email protected]>
Date: Tue, 20 Oct 2026 14:46:41 +0100
Subject: [PATCH 4/4] [APINotes] Capture version-independent API notes only in
 module and PCH builds

`-fswift-version-independent-apinotes` exists so that one module file can serve 
Swift clients at every language version. Only module and PCH builds produce 
such files.

Add `LangOptions::capturesVersionIndependentAPINotes`, and capture only when it 
is true. Every other compilation applies API notes as the default mode does.

A later change collapses captured notes as a compilation reads them. It asks 
the same predicate, so one flag covers both roles. An implicit module build 
needs this, because one invocation both builds modules and reads them.
---
 .../include/clang/APINotes/APINotesManager.h  |  9 ----
 clang/include/clang/Basic/LangOptions.h       |  8 +++
 clang/lib/APINotes/APINotesManager.cpp        |  3 +-
 clang/lib/Sema/SemaAPINotes.cpp               |  7 +++
 .../version-independent-translation-unit.c    | 52 +++++++++++++++++++
 5 files changed, 68 insertions(+), 11 deletions(-)
 create mode 100644 clang/test/APINotes/version-independent-translation-unit.c

diff --git a/clang/include/clang/APINotes/APINotesManager.h 
b/clang/include/clang/APINotes/APINotesManager.h
index aaf48706fb26b..fbadeb9991eba 100644
--- a/clang/include/clang/APINotes/APINotesManager.h
+++ b/clang/include/clang/APINotes/APINotesManager.h
@@ -55,13 +55,6 @@ class APINotesManager {
   /// a compilation, so it can be tested per-declaration without recomputing.
   bool HasAPINotes;
 
-  /// Whether to apply all APINotes as optionally-applied versioned
-  /// entities. This means that when building a Clang module,
-  /// we capture every note on a given decl wrapped in a SwiftVersionedAttr
-  /// (with an empty version field for unversioned notes), and have the
-  /// client apply the relevant version's notes.
-  bool VersionIndependentSwift;
-
   /// The Swift version to use when interpreting versioned API notes.
   llvm::VersionTuple SwiftVersion;
 
@@ -181,8 +174,6 @@ class APINotesManager {
 
   /// Find the API notes readers that correspond to the given source location.
   llvm::SmallVector<APINotesReader *, 2> findAPINotes(SourceLocation Loc);
-
-  bool captureVersionIndependentSwift() { return VersionIndependentSwift; }
 };
 
 } // end namespace api_notes
diff --git a/clang/include/clang/Basic/LangOptions.h 
b/clang/include/clang/Basic/LangOptions.h
index 160c53fed4935..b9a8151c4f98b 100644
--- a/clang/include/clang/Basic/LangOptions.h
+++ b/clang/include/clang/Basic/LangOptions.h
@@ -668,6 +668,14 @@ class LangOptions : public LangOptionsBase {
     return !isCompilingModule() && !ModuleName.empty();
   }
 
+  /// Does this compilation capture API notes for every Swift version, leaving
+  /// its importers to select and apply them.
+  /// Only module or PCH build under -fswift-version-independent-apinotes does.
+  bool capturesVersionIndependentAPINotes(bool GeneratingPreamble) const {
+    return SwiftVersionIndependentAPINotes &&
+           (isCompilingModule() || (CompilingPCH && !GeneratingPreamble));
+  }
+
   /// Do we need to track the owning module for a local declaration?
   bool trackLocalOwningModule() const {
     return isCompilingModule() || ModulesLocalVisibility;
diff --git a/clang/lib/APINotes/APINotesManager.cpp 
b/clang/lib/APINotes/APINotesManager.cpp
index 5c1bb41d804e9..1ce51b6f741c1 100644
--- a/clang/lib/APINotes/APINotesManager.cpp
+++ b/clang/lib/APINotes/APINotesManager.cpp
@@ -50,8 +50,7 @@ class PrettyStackTraceDoubleString : public 
llvm::PrettyStackTraceEntry {
 
 APINotesManager::APINotesManager(SourceManager &SM, const LangOptions 
&LangOpts)
     : SM(SM), ImplicitAPINotes(LangOpts.APINotes),
-      HasAPINotes(LangOpts.APINotes),
-      VersionIndependentSwift(LangOpts.SwiftVersionIndependentAPINotes) {}
+      HasAPINotes(LangOpts.APINotes) {}
 
 APINotesManager::~APINotesManager() {
   // Free the API notes readers.
diff --git a/clang/lib/Sema/SemaAPINotes.cpp b/clang/lib/Sema/SemaAPINotes.cpp
index 802cb8894d715..d9d529991422b 100644
--- a/clang/lib/Sema/SemaAPINotes.cpp
+++ b/clang/lib/Sema/SemaAPINotes.cpp
@@ -21,6 +21,8 @@
 #include "clang/Analysis/Analyses/LifetimeSafety/LifetimeAnnotations.h"
 #include "clang/Basic/SourceLocation.h"
 #include "clang/Lex/Lexer.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/PreprocessorOptions.h"
 #include "clang/Sema/SemaObjC.h"
 #include "clang/Sema/SemaSwift.h"
 #include <stack>
@@ -1560,3 +1562,8 @@ void Sema::DiagnoseUnusedAPINotesSelectors() {
     APINotesSelectorDiagnostics->diagnoseUnused(*this);
   APINotesSelectorDiagnostics.reset();
 }
+
+bool Sema::captureSwiftVersionIndependentAPINotes() {
+  return getLangOpts().capturesVersionIndependentAPINotes(
+      PP.getPreprocessorOpts().GeneratePreamble);
+}
diff --git a/clang/test/APINotes/version-independent-translation-unit.c 
b/clang/test/APINotes/version-independent-translation-unit.c
new file mode 100644
index 0000000000000..f2d929ec6f3b0
--- /dev/null
+++ b/clang/test/APINotes/version-independent-translation-unit.c
@@ -0,0 +1,52 @@
+// A translation unit that does not build a module applies API notes normally
+// under -fswift-version-independent-apinotes. It has one Swift version, so
+// there is no module file to serve several versions and nothing to capture 
for.
+// The same checks run against the default mode.
+
+// RUN: rm -rf %t && split-file %s %t
+// RUN: %clang_cc1 -fapinotes -fswift-version-independent-apinotes 
-fapinotes-swift-version=4 -I %t %t/tu.c -ast-dump -ast-dump-filter tuRenamed 
-x c | FileCheck %s
+// RUN: %clang_cc1 -fapinotes -fapinotes-swift-version=4 -I %t %t/tu.c 
-ast-dump -ast-dump-filter tuRenamed -x c | FileCheck %s
+
+// The 4.0 slice is applied and the unversioned one superseded. No slice
+// markers, which only a capturing module build emits.
+// CHECK: Dumping tuRenamed:
+// CHECK: SwiftVersionedAdditionAttr {{.*}} Implicit 4.0 IsReplacedByActive 
0{{$}}
+// CHECK-NEXT: SwiftNameAttr {{.*}} "tuUnversioned()"
+// CHECK-NEXT: SwiftNameAttr {{.*}} "tuV4()"
+// CHECK-NOT: SwiftVersionedSliceAttr
+
+// A precompiled preamble is the start of its translation unit, so it applies
+// API notes too, and its inline body can't use what they make unavailable.
+// RUN: env CINDEXTEST_EDITING=1 c-index-test -test-load-source-reparse 1 
local %t/preamble.c -fapinotes -Xclang -fswift-version-independent-apinotes 
-Xclang -fapinotes-swift-version=5 -I %t 2>&1 | FileCheck 
--check-prefix=PREAMBLE %s
+// RUN: env CINDEXTEST_EDITING=1 c-index-test -test-load-source-reparse 1 
local %t/preamble.c -fapinotes -Xclang -fapinotes-swift-version=5 -I %t 2>&1 | 
FileCheck --check-prefix=PREAMBLE %s
+// Once for the first parse, and once for the reparse, which uses the preamble.
+// PREAMBLE: Preamble.h:2:{{[0-9]+}}: error: 'preambleGone' is unavailable: 
gone
+// PREAMBLE: Preamble.h:2:{{[0-9]+}}: error: 'preambleGone' is unavailable: 
gone
+
+//--- APINotes.apinotes
+Name: TranslationUnit
+Functions:
+  - Name: tuRenamed
+    SwiftName: 'tuUnversioned()'
+  - Name: preambleGone
+    Availability: none
+    AvailabilityMsg: 'gone'
+SwiftVersions:
+  - Version: 4.0
+    Functions:
+      - Name: tuRenamed
+        SwiftName: 'tuV4()'
+
+//--- TranslationUnit.h
+void tuRenamed(void);
+
+//--- tu.c
+#include "TranslationUnit.h"
+
+//--- Preamble.h
+void preambleGone(void);
+static inline void preambleUser(void) { preambleGone(); }
+
+//--- preamble.c
+#include "Preamble.h"
+int main(void) { return 0; }

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

Reply via email to