[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

Egor Zhdan via cfe-commits cfe-commits at lists.llvm.org
Fri Feb 23 16:46:44 PST 2024


https://github.com/egorzhdan updated https://github.com/llvm/llvm-project/pull/78445

>From 40a6247d20e121d9dea0ff83a61f5e7abba7bba6 Mon Sep 17 00:00:00 2001
From: Egor Zhdan <e_zhdan at apple.com>
Date: Wed, 17 Jan 2024 13:41:25 +0000
Subject: [PATCH] [APINotes] Upstream Sema logic to apply API Notes to decls

This upstreams more of the Clang API Notes functionality that is currently implemented in the Apple fork: https://github.com/apple/llvm-project/tree/next/clang/lib/APINotes
---
 .../clang/Basic/DiagnosticSemaKinds.td        |   7 +
 clang/include/clang/Sema/Sema.h               |   6 +
 clang/lib/Sema/CMakeLists.txt                 |   1 +
 clang/lib/Sema/SemaAPINotes.cpp               | 989 ++++++++++++++++++
 clang/lib/Sema/SemaDecl.cpp                   |   4 +
 clang/lib/Sema/SemaDeclAttr.cpp               |   3 +
 clang/lib/Sema/SemaDeclCXX.cpp                |   6 +-
 clang/lib/Sema/SemaDeclObjC.cpp               |   4 +
 clang/lib/Sema/SemaObjCProperty.cpp           |   5 +
 clang/lib/Sema/SemaTemplate.cpp               |   7 +
 10 files changed, 1031 insertions(+), 1 deletion(-)
 create mode 100644 clang/lib/Sema/SemaAPINotes.cpp

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index ebda201361fb07..887d6120f48d2c 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -10760,6 +10760,13 @@ def warn_imp_cast_drops_unaligned : Warning<
 
 } // end of sema category
 
+let CategoryName = "API Notes Issue" in {
+
+def err_incompatible_replacement_type : Error<
+  "API notes replacement type %0 has a different size from original type %1">;
+
+} // end of API Notes category
+
 let CategoryName = "OpenMP Issue" in {
 // OpenMP support.
 def err_omp_expected_var_arg : Error<
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index fcccac10f4733a..77749372b7fb65 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -4883,6 +4883,12 @@ class Sema final {
   bool checkCommonAttributeFeatures(const Stmt *S, const ParsedAttr &A,
                                     bool SkipArgCountCheck = false);
 
+  /// Map any API notes provided for this declaration to attributes on the
+  /// declaration.
+  ///
+  /// Triggered by declaration-attribute processing.
+  void ProcessAPINotes(Decl *D);
+
   /// Determine if type T is a valid subject for a nonnull and similar
   /// attributes. By default, we look through references (the behavior used by
   /// nonnull), but if the second parameter is true, then we treat a reference
diff --git a/clang/lib/Sema/CMakeLists.txt b/clang/lib/Sema/CMakeLists.txt
index 862f9d4ffb825d..e8bff07ced0cfa 100644
--- a/clang/lib/Sema/CMakeLists.txt
+++ b/clang/lib/Sema/CMakeLists.txt
@@ -27,6 +27,7 @@ add_clang_library(clangSema
   Sema.cpp
   SemaAccess.cpp
   SemaAttr.cpp
+  SemaAPINotes.cpp
   SemaAvailability.cpp
   SemaCXXScopeSpec.cpp
   SemaCast.cpp
diff --git a/clang/lib/Sema/SemaAPINotes.cpp b/clang/lib/Sema/SemaAPINotes.cpp
new file mode 100644
index 00000000000000..594d73753a80e0
--- /dev/null
+++ b/clang/lib/Sema/SemaAPINotes.cpp
@@ -0,0 +1,989 @@
+//===--- SemaAPINotes.cpp - API Notes Handling ----------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+//  This file implements the mapping from API notes to declaration attributes.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/APINotes/APINotesReader.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Sema/SemaInternal.h"
+
+using namespace clang;
+
+namespace {
+enum class IsActive_t : bool { Inactive, Active };
+enum class IsReplacement_t : bool { Original, Replacement };
+
+struct VersionedInfoMetadata {
+  /// An empty version refers to unversioned metadata.
+  VersionTuple Version;
+  unsigned IsActive : 1;
+  unsigned IsReplacement : 1;
+
+  VersionedInfoMetadata(VersionTuple Version, IsActive_t Active,
+                        IsReplacement_t Replacement)
+      : Version(Version), IsActive(Active == IsActive_t::Active),
+        IsReplacement(Replacement == IsReplacement_t::Replacement) {}
+};
+} // end anonymous namespace
+
+/// Determine whether this is a multi-level pointer type.
+static bool isIndirectPointerType(QualType Type) {
+  QualType Pointee = Type->getPointeeType();
+  if (Pointee.isNull())
+    return false;
+
+  return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() ||
+         Pointee->isMemberPointerType();
+}
+
+/// Apply nullability to the given declaration.
+static void applyNullability(Sema &S, Decl *D, NullabilityKind Nullability,
+                             VersionedInfoMetadata Metadata) {
+  if (!Metadata.IsActive)
+    return;
+
+  auto IsUnmodified = [&](Decl *D, QualType QT,
+                          NullabilityKind Nullability) -> bool {
+    QualType Original = QT;
+    S.CheckImplicitNullabilityTypeSpecifier(QT, Nullability, D->getLocation(),
+                                            isa<ParmVarDecl>(D),
+                                            /*OverrideExisting=*/true);
+    return QT.getTypePtr() == Original.getTypePtr();
+  };
+
+  if (auto Function = dyn_cast<FunctionDecl>(D)) {
+    if (IsUnmodified(D, Function->getReturnType(), Nullability)) {
+      QualType FnType = Function->getType();
+      Function->setType(FnType);
+    }
+  } else if (auto Method = dyn_cast<ObjCMethodDecl>(D)) {
+    QualType Type = Method->getReturnType();
+    if (IsUnmodified(D, Type, Nullability)) {
+      Method->setReturnType(Type);
+
+      // Make it a context-sensitive keyword if we can.
+      if (!isIndirectPointerType(Type))
+        Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
+            Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
+    }
+  } else if (auto Value = dyn_cast<ValueDecl>(D)) {
+    QualType Type = Value->getType();
+    if (IsUnmodified(D, Type, Nullability)) {
+      Value->setType(Type);
+
+      // Make it a context-sensitive keyword if we can.
+      if (auto Parm = dyn_cast<ParmVarDecl>(D)) {
+        if (Parm->isObjCMethodParameter() && !isIndirectPointerType(Type))
+          Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
+              Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
+      }
+    }
+  } else if (auto Property = dyn_cast<ObjCPropertyDecl>(D)) {
+    QualType Type = Property->getType();
+    if (IsUnmodified(D, Type, Nullability)) {
+      Property->setType(Type, Property->getTypeSourceInfo());
+
+      // Make it a property attribute if we can.
+      if (!isIndirectPointerType(Type))
+        Property->setPropertyAttributes(
+            ObjCPropertyAttribute::kind_null_resettable);
+    }
+  }
+}
+
+/// Copy a string into ASTContext-allocated memory.
+static StringRef ASTAllocateString(ASTContext &Ctx, StringRef String) {
+  void *mem = Ctx.Allocate(String.size(), alignof(char *));
+  memcpy(mem, String.data(), String.size());
+  return StringRef(static_cast<char *>(mem), String.size());
+}
+
+static AttributeCommonInfo getPlaceholderAttrInfo() {
+  return AttributeCommonInfo(SourceRange(),
+                             AttributeCommonInfo::UnknownAttribute,
+                             {AttributeCommonInfo::AS_GNU,
+                              /*Spelling*/ 0, /*IsAlignas*/ false,
+                              /*IsRegularKeywordAttribute*/ false});
+}
+
+namespace {
+template <typename A> struct AttrKindFor {};
+
+#define ATTR(X)                                                                \
+  template <> struct AttrKindFor<X##Attr> {                                    \
+    static const attr::Kind value = attr::X;                                   \
+  };
+#include "clang/Basic/AttrList.inc"
+
+/// Handle an attribute introduced by API notes.
+///
+/// \param IsAddition Whether we should add a new attribute
+/// (otherwise, we might remove an existing attribute).
+/// \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) {
+  if (Metadata.IsActive) {
+    auto Existing = GetExistingAttr(D);
+    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);
+
+      D->getAttrs().erase(Existing);
+      D->addAttr(Versioned);
+    }
+
+    // If we're supposed to add a new attribute, do so.
+    if (IsAddition) {
+      if (auto Attr = CreateAttr())
+        D->addAttr(Attr);
+    }
+
+  } else {
+    if (IsAddition) {
+      if (auto Attr = CreateAttr()) {
+        auto *Versioned = SwiftVersionedAdditionAttr::CreateImplicit(
+            S.Context, Metadata.Version, Attr,
+            /*IsReplacedByActive*/ Metadata.IsReplacement);
+        D->addAttr(Versioned);
+      }
+    } else {
+      // FIXME: This isn't preserving enough information for things like
+      // availability, where we're trying to remove a /specific/ kind of
+      // attribute.
+      auto *Versioned = SwiftVersionedRemovalAttr::CreateImplicit(
+          S.Context, Metadata.Version, AttrKindFor<A>::value,
+          /*IsReplacedByActive*/ Metadata.IsReplacement);
+      D->addAttr(Versioned);
+    }
+  }
+}
+
+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); });
+      });
+}
+} // namespace
+
+template <typename A = CFReturnsRetainedAttr>
+static void handleAPINotedRetainCountAttribute(Sema &S, Decl *D,
+                                               bool ShouldAddAttribute,
+                                               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);
+        });
+      });
+}
+
+static void handleAPINotedRetainCountConvention(
+    Sema &S, Decl *D, VersionedInfoMetadata Metadata,
+    std::optional<api_notes::RetainCountConventionKind> Convention) {
+  if (!Convention)
+    return;
+  switch (*Convention) {
+  case api_notes::RetainCountConventionKind::None:
+    if (isa<FunctionDecl>(D)) {
+      handleAPINotedRetainCountAttribute<CFUnknownTransferAttr>(
+          S, D, /*shouldAddAttribute*/ true, Metadata);
+    } else {
+      handleAPINotedRetainCountAttribute(S, D, /*shouldAddAttribute*/ false,
+                                         Metadata);
+    }
+    break;
+  case api_notes::RetainCountConventionKind::CFReturnsRetained:
+    handleAPINotedRetainCountAttribute<CFReturnsRetainedAttr>(
+        S, D, /*shouldAddAttribute*/ true, Metadata);
+    break;
+  case api_notes::RetainCountConventionKind::CFReturnsNotRetained:
+    handleAPINotedRetainCountAttribute<CFReturnsNotRetainedAttr>(
+        S, D, /*shouldAddAttribute*/ true, Metadata);
+    break;
+  case api_notes::RetainCountConventionKind::NSReturnsRetained:
+    handleAPINotedRetainCountAttribute<NSReturnsRetainedAttr>(
+        S, D, /*shouldAddAttribute*/ true, Metadata);
+    break;
+  case api_notes::RetainCountConventionKind::NSReturnsNotRetained:
+    handleAPINotedRetainCountAttribute<NSReturnsNotRetainedAttr>(
+        S, D, /*shouldAddAttribute*/ true, Metadata);
+    break;
+  }
+}
+
+static void ProcessAPINotes(Sema &S, Decl *D,
+                            const api_notes::CommonEntityInfo &Info,
+                            VersionedInfoMetadata Metadata) {
+  // Availability
+  if (Info.Unavailable) {
+    handleAPINotedAttribute<UnavailableAttr>(S, D, true, Metadata, [&] {
+      return new (S.Context)
+          UnavailableAttr(S.Context, getPlaceholderAttrInfo(),
+                          ASTAllocateString(S.Context, Info.UnavailableMsg));
+    });
+  }
+
+  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);
+        },
+        [](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;
+          });
+        });
+  }
+
+  // swift_private
+  if (auto SwiftPrivate = Info.isSwiftPrivate()) {
+    handleAPINotedAttribute<SwiftPrivateAttr>(
+        S, D, *SwiftPrivate, Metadata, [&] {
+          return new (S.Context)
+              SwiftPrivateAttr(S.Context, getPlaceholderAttrInfo());
+        });
+  }
+
+  // swift_name
+  if (!Info.SwiftName.empty()) {
+    handleAPINotedAttribute<SwiftNameAttr>(
+        S, D, true, Metadata, [&]() -> SwiftNameAttr * {
+          AttributeFactory AF{};
+          AttributePool AP{AF};
+          auto &C = S.getASTContext();
+          ParsedAttr *SNA =
+              AP.create(&C.Idents.get("swift_name"), SourceRange(), nullptr,
+                        SourceLocation(), nullptr, nullptr, nullptr,
+                        ParsedAttr::Form::GNU());
+
+          if (!S.DiagnoseSwiftName(D, Info.SwiftName, D->getLocation(), *SNA,
+                                   /*IsAsync=*/false))
+            return nullptr;
+
+          return new (S.Context)
+              SwiftNameAttr(S.Context, getPlaceholderAttrInfo(),
+                            ASTAllocateString(S.Context, Info.SwiftName));
+        });
+  }
+}
+
+static void ProcessAPINotes(Sema &S, Decl *D,
+                            const api_notes::CommonTypeInfo &Info,
+                            VersionedInfoMetadata Metadata) {
+  // swift_bridge
+  if (auto SwiftBridge = Info.getSwiftBridge()) {
+    handleAPINotedAttribute<SwiftBridgeAttr>(
+        S, D, !SwiftBridge->empty(), Metadata, [&] {
+          return new (S.Context)
+              SwiftBridgeAttr(S.Context, getPlaceholderAttrInfo(),
+                              ASTAllocateString(S.Context, *SwiftBridge));
+        });
+  }
+
+  // ns_error_domain
+  if (auto NSErrorDomain = Info.getNSErrorDomain()) {
+    handleAPINotedAttribute<NSErrorDomainAttr>(
+        S, D, !NSErrorDomain->empty(), Metadata, [&] {
+          return new (S.Context)
+              NSErrorDomainAttr(S.Context, getPlaceholderAttrInfo(),
+                                &S.Context.Idents.get(*NSErrorDomain));
+        });
+  }
+
+  ProcessAPINotes(S, D, static_cast<const api_notes::CommonEntityInfo &>(Info),
+                  Metadata);
+}
+
+/// Check that the replacement type provided by API notes is reasonable.
+///
+/// This is a very weak form of ABI check.
+static bool checkAPINotesReplacementType(Sema &S, SourceLocation Loc,
+                                         QualType OrigType,
+                                         QualType ReplacementType) {
+  if (S.Context.getTypeSize(OrigType) !=
+      S.Context.getTypeSize(ReplacementType)) {
+    S.Diag(Loc, diag::err_incompatible_replacement_type)
+        << ReplacementType << OrigType;
+    return true;
+  }
+
+  return false;
+}
+
+/// Process API notes for a variable or property.
+static void ProcessAPINotes(Sema &S, Decl *D,
+                            const api_notes::VariableInfo &Info,
+                            VersionedInfoMetadata Metadata) {
+  // Type override.
+  if (Metadata.IsActive && !Info.getType().empty() &&
+      S.ParseTypeFromStringCallback) {
+    auto ParsedType = S.ParseTypeFromStringCallback(
+        Info.getType(), "<API Notes>", D->getLocation());
+    if (ParsedType.isUsable()) {
+      QualType Type = Sema::GetTypeFromParser(ParsedType.get());
+      auto TypeInfo =
+          S.Context.getTrivialTypeSourceInfo(Type, D->getLocation());
+
+      if (auto Var = dyn_cast<VarDecl>(D)) {
+        // Make adjustments to parameter types.
+        if (isa<ParmVarDecl>(Var)) {
+          Type = S.AdjustParameterTypeForObjCAutoRefCount(
+              Type, D->getLocation(), TypeInfo);
+          Type = S.Context.getAdjustedParameterType(Type);
+        }
+
+        if (!checkAPINotesReplacementType(S, Var->getLocation(), Var->getType(),
+                                          Type)) {
+          Var->setType(Type);
+          Var->setTypeSourceInfo(TypeInfo);
+        }
+      } else if (auto Property = dyn_cast<ObjCPropertyDecl>(D)) {
+        if (!checkAPINotesReplacementType(S, Property->getLocation(),
+                                          Property->getType(), Type))
+          Property->setType(Type, TypeInfo);
+
+      } else
+        llvm_unreachable("API notes allowed a type on an unknown declaration");
+    }
+  }
+
+  // Nullability.
+  if (auto Nullability = Info.getNullability())
+    applyNullability(S, D, *Nullability, Metadata);
+
+  // Handle common entity information.
+  ProcessAPINotes(S, D, static_cast<const api_notes::CommonEntityInfo &>(Info),
+                  Metadata);
+}
+
+/// Process API notes for a parameter.
+static void ProcessAPINotes(Sema &S, ParmVarDecl *D,
+                            const api_notes::ParamInfo &Info,
+                            VersionedInfoMetadata Metadata) {
+  // noescape
+  if (auto NoEscape = Info.isNoEscape())
+    handleAPINotedAttribute<NoEscapeAttr>(S, D, *NoEscape, Metadata, [&] {
+      return new (S.Context) NoEscapeAttr(S.Context, getPlaceholderAttrInfo());
+    });
+
+  // Retain count convention
+  handleAPINotedRetainCountConvention(S, D, Metadata,
+                                      Info.getRetainCountConvention());
+
+  // Handle common entity information.
+  ProcessAPINotes(S, D, static_cast<const api_notes::VariableInfo &>(Info),
+                  Metadata);
+}
+
+/// Process API notes for a global variable.
+static void ProcessAPINotes(Sema &S, VarDecl *D,
+                            const api_notes::GlobalVariableInfo &Info,
+                            VersionedInfoMetadata metadata) {
+  // Handle common entity information.
+  ProcessAPINotes(S, D, static_cast<const api_notes::VariableInfo &>(Info),
+                  metadata);
+}
+
+/// Process API notes for an Objective-C property.
+static void ProcessAPINotes(Sema &S, ObjCPropertyDecl *D,
+                            const api_notes::ObjCPropertyInfo &Info,
+                            VersionedInfoMetadata Metadata) {
+  // Handle common entity information.
+  ProcessAPINotes(S, D, static_cast<const api_notes::VariableInfo &>(Info),
+                  Metadata);
+
+  if (auto AsAccessors = Info.getSwiftImportAsAccessors()) {
+    handleAPINotedAttribute<SwiftImportPropertyAsAccessorsAttr>(
+        S, D, *AsAccessors, Metadata, [&] {
+          return new (S.Context) SwiftImportPropertyAsAccessorsAttr(
+              S.Context, getPlaceholderAttrInfo());
+        });
+  }
+}
+
+namespace {
+typedef llvm::PointerUnion<FunctionDecl *, ObjCMethodDecl *> FunctionOrMethod;
+}
+
+/// Process API notes for a function or method.
+static void ProcessAPINotes(Sema &S, FunctionOrMethod AnyFunc,
+                            const api_notes::FunctionInfo &Info,
+                            VersionedInfoMetadata Metadata) {
+  // Find the declaration itself.
+  FunctionDecl *FD = AnyFunc.dyn_cast<FunctionDecl *>();
+  Decl *D = FD;
+  ObjCMethodDecl *MD = nullptr;
+  if (!D) {
+    MD = AnyFunc.get<ObjCMethodDecl *>();
+    D = MD;
+  }
+
+  // Nullability of return type.
+  if (Info.NullabilityAudited)
+    applyNullability(S, D, Info.getReturnTypeInfo(), Metadata);
+
+  // Parameters.
+  unsigned NumParams = FD ? FD->getNumParams() : MD->param_size();
+
+  bool AnyTypeChanged = false;
+  for (unsigned I = 0; I != NumParams; ++I) {
+    ParmVarDecl *Param = FD ? FD->getParamDecl(I) : MD->param_begin()[I];
+
+    QualType ParamTypeBefore = Param->getType();
+
+    if (I < Info.Params.size())
+      ProcessAPINotes(S, Param, Info.Params[I], Metadata);
+
+    // Nullability.
+    if (Info.NullabilityAudited)
+      applyNullability(S, Param, Info.getParamTypeInfo(I), Metadata);
+
+    if (ParamTypeBefore.getAsOpaquePtr() != Param->getType().getAsOpaquePtr())
+      AnyTypeChanged = true;
+  }
+
+  // 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());
+
+      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;
+        AnyTypeChanged = true;
+      }
+    }
+  }
+
+  // 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()));
+    }
+  }
+
+  // Retain count convention
+  handleAPINotedRetainCountConvention(S, D, Metadata,
+                                      Info.getRetainCountConvention());
+
+  // Handle common entity information.
+  ProcessAPINotes(S, D, static_cast<const api_notes::CommonEntityInfo &>(Info),
+                  Metadata);
+}
+
+/// Process API notes for a global function.
+static void ProcessAPINotes(Sema &S, FunctionDecl *D,
+                            const api_notes::GlobalFunctionInfo &Info,
+                            VersionedInfoMetadata Metadata) {
+  // Handle common function information.
+  ProcessAPINotes(S, FunctionOrMethod(D),
+                  static_cast<const api_notes::FunctionInfo &>(Info), Metadata);
+}
+
+/// Process API notes for an enumerator.
+static void ProcessAPINotes(Sema &S, EnumConstantDecl *D,
+                            const api_notes::EnumConstantInfo &Info,
+                            VersionedInfoMetadata Metadata) {
+  // Handle common information.
+  ProcessAPINotes(S, D, static_cast<const api_notes::CommonEntityInfo &>(Info),
+                  Metadata);
+}
+
+/// Process API notes for an Objective-C method.
+static void ProcessAPINotes(Sema &S, ObjCMethodDecl *D,
+                            const api_notes::ObjCMethodInfo &Info,
+                            VersionedInfoMetadata Metadata) {
+  // Designated initializers.
+  if (Info.DesignatedInit) {
+    handleAPINotedAttribute<ObjCDesignatedInitializerAttr>(
+        S, D, true, Metadata, [&] {
+          if (ObjCInterfaceDecl *IFace = D->getClassInterface())
+            IFace->setHasDesignatedInitializers();
+
+          return new (S.Context) ObjCDesignatedInitializerAttr(
+              S.Context, getPlaceholderAttrInfo());
+        });
+  }
+
+  // Handle common function information.
+  ProcessAPINotes(S, FunctionOrMethod(D),
+                  static_cast<const api_notes::FunctionInfo &>(Info), Metadata);
+}
+
+/// Process API notes for a tag.
+static void ProcessAPINotes(Sema &S, TagDecl *D, const api_notes::TagInfo &Info,
+                            VersionedInfoMetadata Metadata) {
+  if (auto ImportAs = Info.SwiftImportAs)
+    D->addAttr(SwiftAttrAttr::Create(S.Context, "import_" + ImportAs.value()));
+
+  if (auto RetainOp = Info.SwiftRetainOp)
+    D->addAttr(SwiftAttrAttr::Create(S.Context, "retain:" + RetainOp.value()));
+
+  if (auto ReleaseOp = Info.SwiftReleaseOp)
+    D->addAttr(
+        SwiftAttrAttr::Create(S.Context, "release:" + ReleaseOp.value()));
+
+  if (auto Extensibility = Info.EnumExtensibility) {
+    using api_notes::EnumExtensibilityKind;
+    bool ShouldAddAttribute = (*Extensibility != EnumExtensibilityKind::None);
+    handleAPINotedAttribute<EnumExtensibilityAttr>(
+        S, D, ShouldAddAttribute, Metadata, [&] {
+          EnumExtensibilityAttr::Kind kind;
+          switch (*Extensibility) {
+          case EnumExtensibilityKind::None:
+            llvm_unreachable("remove only");
+          case EnumExtensibilityKind::Open:
+            kind = EnumExtensibilityAttr::Open;
+            break;
+          case EnumExtensibilityKind::Closed:
+            kind = EnumExtensibilityAttr::Closed;
+            break;
+          }
+          return new (S.Context)
+              EnumExtensibilityAttr(S.Context, getPlaceholderAttrInfo(), kind);
+        });
+  }
+
+  if (auto FlagEnum = Info.isFlagEnum()) {
+    handleAPINotedAttribute<FlagEnumAttr>(S, D, *FlagEnum, Metadata, [&] {
+      return new (S.Context) FlagEnumAttr(S.Context, getPlaceholderAttrInfo());
+    });
+  }
+
+  // Handle common type information.
+  ProcessAPINotes(S, D, static_cast<const api_notes::CommonTypeInfo &>(Info),
+                  Metadata);
+}
+
+/// Process API notes for a typedef.
+static void ProcessAPINotes(Sema &S, TypedefNameDecl *D,
+                            const api_notes::TypedefInfo &Info,
+                            VersionedInfoMetadata Metadata) {
+  // swift_wrapper
+  using SwiftWrapperKind = api_notes::SwiftNewTypeKind;
+
+  if (auto SwiftWrapper = Info.SwiftWrapper) {
+    handleAPINotedAttribute<SwiftNewTypeAttr>(
+        S, D, *SwiftWrapper != SwiftWrapperKind::None, Metadata, [&] {
+          SwiftNewTypeAttr::NewtypeKind Kind;
+          switch (*SwiftWrapper) {
+          case SwiftWrapperKind::None:
+            llvm_unreachable("Shouldn't build an attribute");
+
+          case SwiftWrapperKind::Struct:
+            Kind = SwiftNewTypeAttr::NK_Struct;
+            break;
+
+          case SwiftWrapperKind::Enum:
+            Kind = SwiftNewTypeAttr::NK_Enum;
+            break;
+          }
+          AttributeCommonInfo SyntaxInfo{
+              SourceRange(),
+              AttributeCommonInfo::AT_SwiftNewType,
+              {AttributeCommonInfo::AS_GNU, SwiftNewTypeAttr::GNU_swift_wrapper,
+               /*IsAlignas*/ false, /*IsRegularKeywordAttribute*/ false}};
+          return new (S.Context) SwiftNewTypeAttr(S.Context, SyntaxInfo, Kind);
+        });
+  }
+
+  // Handle common type information.
+  ProcessAPINotes(S, D, static_cast<const api_notes::CommonTypeInfo &>(Info),
+                  Metadata);
+}
+
+/// Process API notes for an Objective-C class or protocol.
+static void ProcessAPINotes(Sema &S, ObjCContainerDecl *D,
+                            const api_notes::ObjCContextInfo &Info,
+                            VersionedInfoMetadata Metadata) {
+  // Handle common type information.
+  ProcessAPINotes(S, D, static_cast<const api_notes::CommonTypeInfo &>(Info),
+                  Metadata);
+}
+
+/// Process API notes for an Objective-C class.
+static void ProcessAPINotes(Sema &S, ObjCInterfaceDecl *D,
+                            const api_notes::ObjCContextInfo &Info,
+                            VersionedInfoMetadata Metadata) {
+  if (auto AsNonGeneric = Info.getSwiftImportAsNonGeneric()) {
+    handleAPINotedAttribute<SwiftImportAsNonGenericAttr>(
+        S, D, *AsNonGeneric, Metadata, [&] {
+          return new (S.Context)
+              SwiftImportAsNonGenericAttr(S.Context, getPlaceholderAttrInfo());
+        });
+  }
+
+  if (auto ObjcMembers = Info.getSwiftObjCMembers()) {
+    handleAPINotedAttribute<SwiftObjCMembersAttr>(
+        S, D, *ObjcMembers, Metadata, [&] {
+          return new (S.Context)
+              SwiftObjCMembersAttr(S.Context, getPlaceholderAttrInfo());
+        });
+  }
+
+  // Handle information common to Objective-C classes and protocols.
+  ProcessAPINotes(S, static_cast<clang::ObjCContainerDecl *>(D), Info,
+                  Metadata);
+}
+
+/// If we're applying API notes with an active, non-default version, and the
+/// versioned API notes have a SwiftName but the declaration normally wouldn't
+/// have one, add a removal attribute to make it clear that the new SwiftName
+/// attribute only applies to the active version of \p D, not to all versions.
+///
+/// This must be run \em before processing API notes for \p D, because otherwise
+/// any existing SwiftName attribute will have been packaged up in a
+/// SwiftVersionedAdditionAttr.
+template <typename SpecificInfo>
+static void maybeAttachUnversionedSwiftName(
+    Sema &S, Decl *D,
+    const api_notes::APINotesReader::VersionedInfo<SpecificInfo> Info) {
+  if (D->hasAttr<SwiftNameAttr>())
+    return;
+  if (!Info.getSelected())
+    return;
+
+  // Is the active slice versioned, and does it set a Swift name?
+  VersionTuple SelectedVersion;
+  SpecificInfo SelectedInfoSlice;
+  std::tie(SelectedVersion, SelectedInfoSlice) = Info[*Info.getSelected()];
+  if (SelectedVersion.empty())
+    return;
+  if (SelectedInfoSlice.SwiftName.empty())
+    return;
+
+  // Does the unversioned slice /not/ set a Swift name?
+  for (const auto &VersionAndInfoSlice : Info) {
+    if (!VersionAndInfoSlice.first.empty())
+      continue;
+    if (!VersionAndInfoSlice.second.SwiftName.empty())
+      return;
+  }
+
+  // Then explicitly call that out with a removal attribute.
+  VersionedInfoMetadata DummyFutureMetadata(
+      SelectedVersion, IsActive_t::Inactive, IsReplacement_t::Replacement);
+  handleAPINotedAttribute<SwiftNameAttr>(
+      S, D, /*add*/ false, DummyFutureMetadata, []() -> SwiftNameAttr * {
+        llvm_unreachable("should not try to add an attribute here");
+      });
+}
+
+/// Processes all versions of versioned API notes.
+///
+/// Just dispatches to the various ProcessAPINotes functions in this file.
+template <typename SpecificDecl, typename SpecificInfo>
+static void ProcessVersionedAPINotes(
+    Sema &S, SpecificDecl *D,
+    const api_notes::APINotesReader::VersionedInfo<SpecificInfo> Info) {
+
+  maybeAttachUnversionedSwiftName(S, D, Info);
+
+  unsigned Selected = Info.getSelected().value_or(Info.size());
+
+  VersionTuple Version;
+  SpecificInfo InfoSlice;
+  for (unsigned i = 0, e = Info.size(); i != e; ++i) {
+    std::tie(Version, InfoSlice) = Info[i];
+    auto Active = (i == Selected) ? IsActive_t::Active : IsActive_t::Inactive;
+    auto Replacement = IsReplacement_t::Original;
+    if (Active == IsActive_t::Inactive && Version.empty()) {
+      Replacement = IsReplacement_t::Replacement;
+      Version = Info[Selected].first;
+    }
+    ProcessAPINotes(S, D, InfoSlice,
+                    VersionedInfoMetadata(Version, Active, Replacement));
+  }
+}
+
+/// Process API notes that are associated with this declaration, mapping them
+/// to attributes as appropriate.
+void Sema::ProcessAPINotes(Decl *D) {
+  if (!D)
+    return;
+
+  // Globals.
+  if (D->getDeclContext()->isFileContext() ||
+      D->getDeclContext()->isNamespace() ||
+      D->getDeclContext()->isExternCContext() ||
+      D->getDeclContext()->isExternCXXContext()) {
+    std::optional<api_notes::Context> APINotesContext;
+    if (auto NamespaceContext = dyn_cast<NamespaceDecl>(D->getDeclContext())) {
+      for (auto Reader :
+           APINotes.findAPINotes(NamespaceContext->getLocation())) {
+        // Retrieve the context ID for the parent namespace of the decl.
+        std::stack<NamespaceDecl *> NamespaceStack;
+        {
+          for (auto CurrentNamespace = NamespaceContext; CurrentNamespace;
+               CurrentNamespace =
+                   dyn_cast<NamespaceDecl>(CurrentNamespace->getParent())) {
+            if (!CurrentNamespace->isInlineNamespace())
+              NamespaceStack.push(CurrentNamespace);
+          }
+        }
+        std::optional<api_notes::ContextID> NamespaceID;
+        while (!NamespaceStack.empty()) {
+          auto CurrentNamespace = NamespaceStack.top();
+          NamespaceStack.pop();
+          NamespaceID = Reader->lookupNamespaceID(CurrentNamespace->getName(),
+                                                  NamespaceID);
+          if (!NamespaceID)
+            break;
+        }
+        if (NamespaceID)
+          APINotesContext = api_notes::Context(
+              *NamespaceID, api_notes::ContextKind::Namespace);
+      }
+    }
+
+    // Global variables.
+    if (auto VD = dyn_cast<VarDecl>(D)) {
+      for (auto Reader : APINotes.findAPINotes(D->getLocation())) {
+        auto Info =
+            Reader->lookupGlobalVariable(VD->getName(), APINotesContext);
+        ProcessVersionedAPINotes(*this, VD, Info);
+      }
+
+      return;
+    }
+
+    // Global functions.
+    if (auto FD = dyn_cast<FunctionDecl>(D)) {
+      if (FD->getDeclName().isIdentifier()) {
+        for (auto Reader : APINotes.findAPINotes(D->getLocation())) {
+          auto Info =
+              Reader->lookupGlobalFunction(FD->getName(), APINotesContext);
+          ProcessVersionedAPINotes(*this, FD, Info);
+        }
+      }
+
+      return;
+    }
+
+    // Objective-C classes.
+    if (auto Class = dyn_cast<ObjCInterfaceDecl>(D)) {
+      for (auto Reader : APINotes.findAPINotes(D->getLocation())) {
+        auto Info = Reader->lookupObjCClassInfo(Class->getName());
+        ProcessVersionedAPINotes(*this, Class, Info);
+      }
+
+      return;
+    }
+
+    // Objective-C protocols.
+    if (auto Protocol = dyn_cast<ObjCProtocolDecl>(D)) {
+      for (auto Reader : APINotes.findAPINotes(D->getLocation())) {
+        auto Info = Reader->lookupObjCProtocolInfo(Protocol->getName());
+        ProcessVersionedAPINotes(*this, Protocol, Info);
+      }
+
+      return;
+    }
+
+    // Tags
+    if (auto Tag = dyn_cast<TagDecl>(D)) {
+      std::string LookupName = Tag->getName().str();
+
+      // Use the source location to discern if this Tag is an OPTIONS macro.
+      // For now we would like to limit this trick of looking up the APINote tag
+      // using the EnumDecl's QualType in the case where the enum is anonymous.
+      // This is only being used to support APINotes lookup for C++
+      // NS/CF_OPTIONS when C++-Interop is enabled.
+      std::string MacroName =
+          LookupName.empty() && Tag->getOuterLocStart().isMacroID()
+              ? clang::Lexer::getImmediateMacroName(
+                    Tag->getOuterLocStart(),
+                    Tag->getASTContext().getSourceManager(), LangOpts)
+                    .str()
+              : "";
+
+      if (LookupName.empty() && isa<clang::EnumDecl>(Tag) &&
+          (MacroName == "CF_OPTIONS" || MacroName == "NS_OPTIONS" ||
+           MacroName == "OBJC_OPTIONS" || MacroName == "SWIFT_OPTIONS")) {
+
+        clang::QualType T = llvm::cast<clang::EnumDecl>(Tag)->getIntegerType();
+        LookupName = clang::QualType::getAsString(
+            T.split(), getASTContext().getPrintingPolicy());
+      }
+
+      for (auto Reader : APINotes.findAPINotes(D->getLocation())) {
+        auto Info = Reader->lookupTag(LookupName, APINotesContext);
+        ProcessVersionedAPINotes(*this, Tag, Info);
+      }
+
+      return;
+    }
+
+    // Typedefs
+    if (auto Typedef = dyn_cast<TypedefNameDecl>(D)) {
+      for (auto Reader : APINotes.findAPINotes(D->getLocation())) {
+        auto Info = Reader->lookupTypedef(Typedef->getName(), APINotesContext);
+        ProcessVersionedAPINotes(*this, Typedef, Info);
+      }
+
+      return;
+    }
+  }
+
+  // Enumerators.
+  if (D->getDeclContext()->getRedeclContext()->isFileContext() ||
+      D->getDeclContext()->getRedeclContext()->isExternCContext()) {
+    if (auto EnumConstant = dyn_cast<EnumConstantDecl>(D)) {
+      for (auto Reader : APINotes.findAPINotes(D->getLocation())) {
+        auto Info = Reader->lookupEnumConstant(EnumConstant->getName());
+        ProcessVersionedAPINotes(*this, EnumConstant, Info);
+      }
+
+      return;
+    }
+  }
+
+  if (auto ObjCContainer = dyn_cast<ObjCContainerDecl>(D->getDeclContext())) {
+    // Location function that looks up an Objective-C context.
+    auto GetContext = [&](api_notes::APINotesReader *Reader)
+        -> std::optional<api_notes::ContextID> {
+      if (auto Protocol = dyn_cast<ObjCProtocolDecl>(ObjCContainer)) {
+        if (auto Found = Reader->lookupObjCProtocolID(Protocol->getName()))
+          return *Found;
+
+        return std::nullopt;
+      }
+
+      if (auto Impl = dyn_cast<ObjCCategoryImplDecl>(ObjCContainer)) {
+        if (auto Cat = Impl->getCategoryDecl())
+          ObjCContainer = Cat;
+        else
+          return std::nullopt;
+      }
+
+      if (auto Category = dyn_cast<ObjCCategoryDecl>(ObjCContainer)) {
+        if (Category->getClassInterface())
+          ObjCContainer = Category->getClassInterface();
+        else
+          return std::nullopt;
+      }
+
+      if (auto Impl = dyn_cast<ObjCImplDecl>(ObjCContainer)) {
+        if (Impl->getClassInterface())
+          ObjCContainer = Impl->getClassInterface();
+        else
+          return std::nullopt;
+      }
+
+      if (auto Class = dyn_cast<ObjCInterfaceDecl>(ObjCContainer)) {
+        if (auto Found = Reader->lookupObjCClassID(Class->getName()))
+          return *Found;
+
+        return std::nullopt;
+      }
+
+      return std::nullopt;
+    };
+
+    // Objective-C methods.
+    if (auto Method = dyn_cast<ObjCMethodDecl>(D)) {
+      for (auto Reader : APINotes.findAPINotes(D->getLocation())) {
+        if (auto Context = GetContext(Reader)) {
+          // Map the selector.
+          Selector Sel = Method->getSelector();
+          SmallVector<StringRef, 2> SelPieces;
+          if (Sel.isUnarySelector()) {
+            SelPieces.push_back(Sel.getNameForSlot(0));
+          } else {
+            for (unsigned i = 0, n = Sel.getNumArgs(); i != n; ++i)
+              SelPieces.push_back(Sel.getNameForSlot(i));
+          }
+
+          api_notes::ObjCSelectorRef SelectorRef;
+          SelectorRef.NumArgs = Sel.getNumArgs();
+          SelectorRef.Identifiers = SelPieces;
+
+          auto Info = Reader->lookupObjCMethod(*Context, SelectorRef,
+                                               Method->isInstanceMethod());
+          ProcessVersionedAPINotes(*this, Method, Info);
+        }
+      }
+    }
+
+    // Objective-C properties.
+    if (auto Property = dyn_cast<ObjCPropertyDecl>(D)) {
+      for (auto Reader : APINotes.findAPINotes(D->getLocation())) {
+        if (auto Context = GetContext(Reader)) {
+          bool isInstanceProperty =
+              (Property->getPropertyAttributesAsWritten() &
+               ObjCPropertyAttribute::kind_class) == 0;
+          auto Info = Reader->lookupObjCProperty(*Context, Property->getName(),
+                                                 isInstanceProperty);
+          ProcessVersionedAPINotes(*this, Property, Info);
+        }
+      }
+
+      return;
+    }
+  }
+}
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 10b5c271f25c10..9fdd8eb236d1ee 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -16424,6 +16424,7 @@ void Sema::ActOnFinishDelayedAttribute(Scope *S, Decl *D,
   if (TemplateDecl *TD = dyn_cast<TemplateDecl>(D))
     D = TD->getTemplatedDecl();
   ProcessDeclAttributeList(S, D, Attrs);
+  ProcessAPINotes(D);
 
   if (CXXMethodDecl *Method = dyn_cast_or_null<CXXMethodDecl>(D))
     if (Method->isStatic())
@@ -19683,6 +19684,7 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
       CDecl->setIvarRBraceLoc(RBrac);
     }
   }
+  ProcessAPINotes(Record);
 }
 
 /// Determine whether the given integral value is representable within
@@ -19997,6 +19999,7 @@ Decl *Sema::ActOnEnumConstant(Scope *S, Decl *theEnumDecl, Decl *lastEnumConst,
   // Process attributes.
   ProcessDeclAttributeList(S, New, Attrs);
   AddPragmaAttributes(S, New);
+  ProcessAPINotes(New);
 
   // Register this decl in the current scope stack.
   New->setAccess(TheEnumDecl->getAccess());
@@ -20195,6 +20198,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceRange BraceRange,
   QualType EnumType = Context.getTypeDeclType(Enum);
 
   ProcessDeclAttributeList(S, Enum, Attrs);
+  ProcessAPINotes(Enum);
 
   if (Enum->isDependentType()) {
     for (unsigned i = 0, e = Elements.size(); i != e; ++i) {
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 8a204b1d3b88d9..c1c28a73fd79ce 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -10146,6 +10146,9 @@ void Sema::ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD) {
 
   // Apply additional attributes specified by '#pragma clang attribute'.
   AddPragmaAttributes(S, D);
+
+  // Look for API notes that map to attributes.
+  ProcessAPINotes(D);
 }
 
 /// Is the given declaration allowed to use a forbidden type?
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 7c009d9c8ec093..d4e1dc67cb50a1 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -11724,6 +11724,7 @@ Decl *Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
 
   ProcessDeclAttributeList(DeclRegionScope, Namespc, AttrList);
   AddPragmaAttributes(DeclRegionScope, Namespc);
+  ProcessAPINotes(Namespc);
 
   // FIXME: Should we be merging attributes?
   if (const VisibilityAttr *Attr = Namespc->getAttr<VisibilityAttr>())
@@ -12270,8 +12271,10 @@ Decl *Sema::ActOnUsingDirective(Scope *S, SourceLocation UsingLoc,
     Diag(IdentLoc, diag::err_expected_namespace_name) << SS.getRange();
   }
 
-  if (UDir)
+  if (UDir) {
     ProcessDeclAttributeList(S, UDir, AttrList);
+    ProcessAPINotes(UDir);
+  }
 
   return UDir;
 }
@@ -13563,6 +13566,7 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S, AccessSpecifier AS,
 
   ProcessDeclAttributeList(S, NewTD, AttrList);
   AddPragmaAttributes(S, NewTD);
+  ProcessAPINotes(NewTD);
 
   CheckTypedefForVariablyModifiedType(S, NewTD);
   Invalid |= NewTD->isInvalidDecl();
diff --git a/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp
index bb0d0cd2030ba8..2011f4084dd2ab 100644
--- a/clang/lib/Sema/SemaDeclObjC.cpp
+++ b/clang/lib/Sema/SemaDeclObjC.cpp
@@ -1072,6 +1072,7 @@ ObjCInterfaceDecl *Sema::ActOnStartClassInterface(
 
   ProcessDeclAttributeList(TUScope, IDecl, AttrList);
   AddPragmaAttributes(TUScope, IDecl);
+  ProcessAPINotes(IDecl);
 
   // Merge attributes from previous declarations.
   if (PrevIDecl)
@@ -1273,6 +1274,7 @@ ObjCProtocolDecl *Sema::ActOnStartProtocolInterface(
 
   ProcessDeclAttributeList(TUScope, PDecl, AttrList);
   AddPragmaAttributes(TUScope, PDecl);
+  ProcessAPINotes(PDecl);
 
   // Merge attributes from previous declarations.
   if (PrevDecl)
@@ -4807,6 +4809,7 @@ Decl *Sema::ActOnMethodDeclaration(
     // Apply the attributes to the parameter.
     ProcessDeclAttributeList(TUScope, Param, ArgInfo[i].ArgAttrs);
     AddPragmaAttributes(TUScope, Param);
+    ProcessAPINotes(Param);
 
     if (Param->hasAttr<BlocksAttr>()) {
       Diag(Param->getLocation(), diag::err_block_on_nonlocal);
@@ -4837,6 +4840,7 @@ Decl *Sema::ActOnMethodDeclaration(
 
   ProcessDeclAttributeList(TUScope, ObjCMethod, AttrList);
   AddPragmaAttributes(TUScope, ObjCMethod);
+  ProcessAPINotes(ObjCMethod);
 
   // Add the method now.
   const ObjCMethodDecl *PrevMethod = nullptr;
diff --git a/clang/lib/Sema/SemaObjCProperty.cpp b/clang/lib/Sema/SemaObjCProperty.cpp
index 349c7fc9c91bdb..4636d89ebf2b84 100644
--- a/clang/lib/Sema/SemaObjCProperty.cpp
+++ b/clang/lib/Sema/SemaObjCProperty.cpp
@@ -2509,6 +2509,8 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property) {
       GetterMethod->addAttr(SectionAttr::CreateImplicit(
           Context, SA->getName(), Loc, SectionAttr::GNU_section));
 
+    ProcessAPINotes(GetterMethod);
+
     if (getLangOpts().ObjCAutoRefCount)
       CheckARCMethodDecl(GetterMethod);
   } else
@@ -2578,6 +2580,9 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property) {
       if (const SectionAttr *SA = property->getAttr<SectionAttr>())
         SetterMethod->addAttr(SectionAttr::CreateImplicit(
             Context, SA->getName(), Loc, SectionAttr::GNU_section));
+
+      ProcessAPINotes(SetterMethod);
+
       // It's possible for the user to have set a very odd custom
       // setter selector that causes it to have a method family.
       if (getLangOpts().ObjCAutoRefCount)
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 1a975a8d0a0df5..649676d5cd9da3 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -2158,6 +2158,7 @@ DeclResult Sema::CheckClassTemplate(
     NewClass->startDefinition();
 
   ProcessDeclAttributeList(S, NewClass, Attr);
+  ProcessAPINotes(NewClass);
 
   if (PrevClassTemplate)
     mergeDeclAttributes(NewClass, PrevClassTemplate->getTemplatedDecl());
@@ -9114,6 +9115,7 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
   }
 
   ProcessDeclAttributeList(S, Specialization, Attr);
+  ProcessAPINotes(Specialization);
 
   // Add alignment attributes if necessary; these attributes are checked when
   // the ASTContext lays out the structure.
@@ -10348,6 +10350,7 @@ DeclResult Sema::ActOnExplicitInstantiation(
 
   bool PreviouslyDLLExported = Specialization->hasAttr<DLLExportAttr>();
   ProcessDeclAttributeList(S, Specialization, Attr);
+  ProcessAPINotes(Specialization);
 
   // Add the explicit instantiation into its lexical context. However,
   // since explicit instantiations are never found by name lookup, we
@@ -10758,6 +10761,9 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
       Prev->setTemplateSpecializationKind(TSK, D.getIdentifierLoc());
       // Merge attributes.
       ProcessDeclAttributeList(S, Prev, D.getDeclSpec().getAttributes());
+      if (PrevTemplate)
+        ProcessAPINotes(Prev);
+
       if (TSK == TSK_ExplicitInstantiationDefinition)
         InstantiateVariableDefinition(D.getIdentifierLoc(), Prev);
     }
@@ -10933,6 +10939,7 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
   }
 
   ProcessDeclAttributeList(S, Specialization, D.getDeclSpec().getAttributes());
+  ProcessAPINotes(Specialization);
 
   // In MSVC mode, dllimported explicit instantiation definitions are treated as
   // instantiation declarations.



More information about the cfe-commits mailing list