[clang] [clang-tools-extra] [clang] Refactor `clang::Linkage` (PR #71049)

Vlad Serebrennikov via cfe-commits cfe-commits at lists.llvm.org
Thu Nov 2 06:30:28 PDT 2023


https://github.com/Endilll updated https://github.com/llvm/llvm-project/pull/71049

>From 05089e60021c321b4113db7e4bdf59bdaaa19de7 Mon Sep 17 00:00:00 2001
From: Vlad Serebrennikov <serebrennikov.vladislav at gmail.com>
Date: Thu, 2 Nov 2023 14:40:12 +0300
Subject: [PATCH 1/4] [clang][NFC] Refactor `clang::Linkage`

This patch introduces a new enumerator `Invalid = 0`, shifting other enumerators by +1. Contrary to how it might sound, this actually affirms status quo of how this enum is stored in `clang::Decl`:
```
  /// If 0, we have not computed the linkage of this declaration.
  /// Otherwise, it is the linkage + 1.
  mutable unsigned CacheValidAndLinkage : 3;
```
This patch makes debuggers to not be mistaken about enumerator stored in this bit-field. It also converts `clang::Linkage` to a scoped enum.
---
 clang-tools-extra/clang-doc/Serialize.cpp     |  4 +-
 clang-tools-extra/clangd/Quality.cpp          |  3 +-
 .../clangd/SemanticHighlighting.cpp           |  3 +-
 clang/include/clang/AST/DeclBase.h            | 11 ++--
 clang/include/clang/AST/Type.h                |  2 +-
 clang/include/clang/Basic/Linkage.h           | 53 +++++++++++-------
 clang/include/clang/Basic/Visibility.h        | 28 +++++-----
 clang/lib/AST/APValue.cpp                     |  2 +-
 clang/lib/AST/Decl.cpp                        | 28 +++++++---
 clang/lib/AST/ItaniumMangle.cpp               |  4 +-
 clang/lib/AST/MicrosoftMangle.cpp             |  5 +-
 clang/lib/AST/Type.cpp                        |  8 +--
 clang/lib/CodeGen/CodeGenModule.cpp           |  4 +-
 clang/lib/CodeGen/ItaniumCXXABI.cpp           | 15 +++--
 clang/lib/CodeGen/MicrosoftCXXABI.cpp         | 15 +++--
 clang/lib/Index/IndexSymbol.cpp               | 20 ++++---
 clang/lib/Sema/SemaChecking.cpp               |  2 +-
 clang/lib/Sema/SemaDecl.cpp                   | 24 ++++----
 clang/lib/Sema/SemaExpr.cpp                   |  2 +-
 clang/lib/Sema/SemaModule.cpp                 |  6 +-
 clang/lib/Sema/SemaOverload.cpp               |  2 +-
 clang/lib/Sema/SemaTemplate.cpp               |  4 +-
 clang/lib/Serialization/ASTReaderDecl.cpp     |  4 +-
 clang/lib/Serialization/ASTWriterDecl.cpp     |  6 +-
 .../ClangExtDefMapGen.cpp                     |  8 ++-
 clang/tools/libclang/CIndex.cpp               | 14 +++--
 clang/tools/libclang/CXIndexDataConsumer.cpp  | 56 +++++++++----------
 clang/unittests/AST/DeclTest.cpp              |  8 +--
 28 files changed, 189 insertions(+), 152 deletions(-)

diff --git a/clang-tools-extra/clang-doc/Serialize.cpp b/clang-tools-extra/clang-doc/Serialize.cpp
index ac8e253ac06ea0b..3b074d849e8a9cf 100644
--- a/clang-tools-extra/clang-doc/Serialize.cpp
+++ b/clang-tools-extra/clang-doc/Serialize.cpp
@@ -257,8 +257,8 @@ static bool isPublic(const clang::AccessSpecifier AS,
                      const clang::Linkage Link) {
   if (AS == clang::AccessSpecifier::AS_private)
     return false;
-  else if ((Link == clang::Linkage::ModuleLinkage) ||
-           (Link == clang::Linkage::ExternalLinkage))
+  else if ((Link == clang::Linkage::Module) ||
+           (Link == clang::Linkage::External))
     return true;
   return false; // otherwise, linkage is some form of internal linkage
 }
diff --git a/clang-tools-extra/clangd/Quality.cpp b/clang-tools-extra/clangd/Quality.cpp
index 8840f805f0e87c7..7371d95fbf27547 100644
--- a/clang-tools-extra/clangd/Quality.cpp
+++ b/clang-tools-extra/clangd/Quality.cpp
@@ -274,7 +274,8 @@ computeScope(const NamedDecl *D) {
     return SymbolRelevanceSignals::ClassScope;
   // ExternalLinkage threshold could be tweaked, e.g. module-visible as global.
   // Avoid caching linkage if it may change after enclosing code completion.
-  if (hasUnstableLinkage(D) || D->getLinkageInternal() < ExternalLinkage)
+  if (hasUnstableLinkage(D) || llvm::to_underlying(D->getLinkageInternal()) <
+                                   llvm::to_underlying(Linkage::External))
     return SymbolRelevanceSignals::FileScope;
   return SymbolRelevanceSignals::GlobalScope;
 }
diff --git a/clang-tools-extra/clangd/SemanticHighlighting.cpp b/clang-tools-extra/clangd/SemanticHighlighting.cpp
index 7649e37e1f96663..49e479abf456210 100644
--- a/clang-tools-extra/clangd/SemanticHighlighting.cpp
+++ b/clang-tools-extra/clangd/SemanticHighlighting.cpp
@@ -617,7 +617,8 @@ std::optional<HighlightingModifier> scopeModifier(const NamedDecl *D) {
   if (DC->isTranslationUnit() && D->isTemplateParameter())
     return std::nullopt;
   // ExternalLinkage threshold could be tweaked, e.g. module-visible as global.
-  if (D->getLinkageInternal() < ExternalLinkage)
+  if (llvm::to_underlying(D->getLinkageInternal()) <
+      llvm::to_underlying(Linkage::External))
     return HighlightingModifier::FileScope;
   return HighlightingModifier::GlobalScope;
 }
diff --git a/clang/include/clang/AST/DeclBase.h b/clang/include/clang/AST/DeclBase.h
index df1d6e8a3b5af72..f784fa73af5bad5 100644
--- a/clang/include/clang/AST/DeclBase.h
+++ b/clang/include/clang/AST/DeclBase.h
@@ -49,7 +49,7 @@ class ExternalSourceSymbolAttr;
 class FunctionDecl;
 class FunctionType;
 class IdentifierInfo;
-enum Linkage : unsigned char;
+enum class Linkage : unsigned char;
 class LinkageSpecDecl;
 class Module;
 class NamedDecl;
@@ -335,7 +335,6 @@ class alignas(8) Decl {
   unsigned IdentifierNamespace : 14;
 
   /// If 0, we have not computed the linkage of this declaration.
-  /// Otherwise, it is the linkage + 1.
   mutable unsigned CacheValidAndLinkage : 3;
 
   /// Allocate memory for a deserialized declaration.
@@ -386,7 +385,7 @@ class alignas(8) Decl {
         Implicit(false), Used(false), Referenced(false),
         TopLevelDeclInObjCContainer(false), Access(AS_none), FromASTFile(0),
         IdentifierNamespace(getIdentifierNamespaceForKind(DK)),
-        CacheValidAndLinkage(0) {
+        CacheValidAndLinkage(llvm::to_underlying(Linkage::Invalid)) {
     if (StatisticsEnabled) add(DK);
   }
 
@@ -395,7 +394,7 @@ class alignas(8) Decl {
         Used(false), Referenced(false), TopLevelDeclInObjCContainer(false),
         Access(AS_none), FromASTFile(0),
         IdentifierNamespace(getIdentifierNamespaceForKind(DK)),
-        CacheValidAndLinkage(0) {
+        CacheValidAndLinkage(llvm::to_underlying(Linkage::Invalid)) {
     if (StatisticsEnabled) add(DK);
   }
 
@@ -405,11 +404,11 @@ class alignas(8) Decl {
   void updateOutOfDate(IdentifierInfo &II) const;
 
   Linkage getCachedLinkage() const {
-    return Linkage(CacheValidAndLinkage - 1);
+    return static_cast<Linkage>(CacheValidAndLinkage);
   }
 
   void setCachedLinkage(Linkage L) const {
-    CacheValidAndLinkage = L + 1;
+    CacheValidAndLinkage = llvm::to_underlying(L);
   }
 
   bool hasCachedLinkage() const {
diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index 23022d7e1a72928..96c12a84e139f40 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -1996,7 +1996,7 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase {
     TypeBits.Dependence = static_cast<unsigned>(Dependence);
     TypeBits.CacheValid = false;
     TypeBits.CachedLocalOrUnnamed = false;
-    TypeBits.CachedLinkage = NoLinkage;
+    TypeBits.CachedLinkage = llvm::to_underlying(Linkage::None);
     TypeBits.FromAST = false;
   }
 
diff --git a/clang/include/clang/Basic/Linkage.h b/clang/include/clang/Basic/Linkage.h
index 0b7b61954a075ae..9cf36e522947fa8 100644
--- a/clang/include/clang/Basic/Linkage.h
+++ b/clang/include/clang/Basic/Linkage.h
@@ -14,21 +14,25 @@
 #ifndef LLVM_CLANG_BASIC_LINKAGE_H
 #define LLVM_CLANG_BASIC_LINKAGE_H
 
+#include "llvm/Support/ErrorHandling.h"
 #include <utility>
 
 namespace clang {
 
 /// Describes the different kinds of linkage
 /// (C++ [basic.link], C99 6.2.2) that an entity may have.
-enum Linkage : unsigned char {
+enum class Linkage : unsigned char {
+  // Linkage hasn't been computed.
+  Invalid = 0,
+
   /// No linkage, which means that the entity is unique and
   /// can only be referred to from within its scope.
-  NoLinkage = 0,
+  None,
 
   /// Internal linkage, which indicates that the entity can
   /// be referred to from within the translation unit (but not other
   /// translation units).
-  InternalLinkage,
+  Internal,
 
   /// External linkage within a unique namespace.
   ///
@@ -37,21 +41,21 @@ enum Linkage : unsigned char {
   /// their names are unique to this translation unit, which is
   /// equivalent to having internal linkage from the code-generation
   /// point of view.
-  UniqueExternalLinkage,
+  UniqueExternal,
 
   /// No linkage according to the standard, but is visible from other
   /// translation units because of types defined in a inline function.
-  VisibleNoLinkage,
+  VisibleNone,
 
   /// Module linkage, which indicates that the entity can be referred
   /// to from other translation units within the same module, and indirectly
   /// from arbitrary other translation units through inline functions and
   /// templates in the module interface.
-  ModuleLinkage,
+  Module,
 
   /// External linkage, which indicates that the entity can
   /// be referred to from other translation units.
-  ExternalLinkage
+  External
 };
 
 /// Describes the different kinds of language linkage
@@ -84,22 +88,33 @@ inline bool isUniqueGVALinkage(GVALinkage L) {
 }
 
 inline bool isExternallyVisible(Linkage L) {
-  return L >= VisibleNoLinkage;
+  switch (L) {
+  case Linkage::Invalid:
+    llvm_unreachable("Linkage hasn't been computed!");
+  case Linkage::None:
+  case Linkage::Internal:
+  case Linkage::UniqueExternal:
+    return false;
+  case Linkage::VisibleNone:
+  case Linkage::Module:
+  case Linkage::External:
+    return true;
+  }
 }
 
 inline Linkage getFormalLinkage(Linkage L) {
   switch (L) {
-  case UniqueExternalLinkage:
-    return ExternalLinkage;
-  case VisibleNoLinkage:
-    return NoLinkage;
+  case Linkage::UniqueExternal:
+    return Linkage::External;
+  case Linkage::VisibleNone:
+    return Linkage::None;
   default:
     return L;
   }
 }
 
 inline bool isExternalFormalLinkage(Linkage L) {
-  return getFormalLinkage(L) == ExternalLinkage;
+  return getFormalLinkage(L) == Linkage::External;
 }
 
 /// Compute the minimum linkage given two linkages.
@@ -111,13 +126,13 @@ inline bool isExternalFormalLinkage(Linkage L) {
 /// special cases for when VisibleNoLinkage would lose the visible bit and
 /// become NoLinkage.
 inline Linkage minLinkage(Linkage L1, Linkage L2) {
-  if (L2 == VisibleNoLinkage)
+  if (L2 == Linkage::VisibleNone)
     std::swap(L1, L2);
-  if (L1 == VisibleNoLinkage) {
-    if (L2 == InternalLinkage)
-      return NoLinkage;
-    if (L2 == UniqueExternalLinkage)
-      return NoLinkage;
+  if (L1 == Linkage::VisibleNone) {
+    if (L2 == Linkage::Internal)
+      return Linkage::None;
+    if (L2 == Linkage::UniqueExternal)
+      return Linkage::None;
   }
   return L1 < L2 ? L1 : L2;
 }
diff --git a/clang/include/clang/Basic/Visibility.h b/clang/include/clang/Basic/Visibility.h
index 57d9754ae4a9858..1e196300be421eb 100644
--- a/clang/include/clang/Basic/Visibility.h
+++ b/clang/include/clang/Basic/Visibility.h
@@ -15,6 +15,7 @@
 #define LLVM_CLANG_BASIC_VISIBILITY_H
 
 #include "clang/Basic/Linkage.h"
+#include "llvm/ADT/STLForwardCompat.h"
 #include <cassert>
 #include <cstdint>
 
@@ -56,10 +57,11 @@ class LinkageInfo {
 
   void setVisibility(Visibility V, bool E) { visibility_ = V; explicit_ = E; }
 public:
-  LinkageInfo() : linkage_(ExternalLinkage), visibility_(DefaultVisibility),
-                  explicit_(false) {}
+  LinkageInfo()
+      : linkage_(llvm::to_underlying(Linkage::External)),
+        visibility_(DefaultVisibility), explicit_(false) {}
   LinkageInfo(Linkage L, Visibility V, bool E)
-    : linkage_(L), visibility_(V), explicit_(E) {
+      : linkage_(llvm::to_underlying(L)), visibility_(V), explicit_(E) {
     assert(getLinkage() == L && getVisibility() == V &&
            isVisibilityExplicit() == E && "Enum truncated!");
   }
@@ -68,23 +70,23 @@ class LinkageInfo {
     return LinkageInfo();
   }
   static LinkageInfo internal() {
-    return LinkageInfo(InternalLinkage, DefaultVisibility, false);
+    return LinkageInfo(Linkage::Internal, DefaultVisibility, false);
   }
   static LinkageInfo uniqueExternal() {
-    return LinkageInfo(UniqueExternalLinkage, DefaultVisibility, false);
+    return LinkageInfo(Linkage::UniqueExternal, DefaultVisibility, false);
   }
   static LinkageInfo none() {
-    return LinkageInfo(NoLinkage, DefaultVisibility, false);
+    return LinkageInfo(Linkage::None, DefaultVisibility, false);
   }
   static LinkageInfo visible_none() {
-    return LinkageInfo(VisibleNoLinkage, DefaultVisibility, false);
+    return LinkageInfo(Linkage::VisibleNone, DefaultVisibility, false);
   }
 
-  Linkage getLinkage() const { return (Linkage)linkage_; }
+  Linkage getLinkage() const { return static_cast<Linkage>(linkage_); }
   Visibility getVisibility() const { return (Visibility)visibility_; }
   bool isVisibilityExplicit() const { return explicit_; }
 
-  void setLinkage(Linkage L) { linkage_ = L; }
+  void setLinkage(Linkage L) { linkage_ = llvm::to_underlying(L); }
 
   void mergeLinkage(Linkage L) {
     setLinkage(minLinkage(getLinkage(), L));
@@ -96,10 +98,10 @@ class LinkageInfo {
   void mergeExternalVisibility(Linkage L) {
     Linkage ThisL = getLinkage();
     if (!isExternallyVisible(L)) {
-      if (ThisL == VisibleNoLinkage)
-        ThisL = NoLinkage;
-      else if (ThisL == ExternalLinkage)
-        ThisL = UniqueExternalLinkage;
+      if (ThisL == Linkage::VisibleNone)
+        ThisL = Linkage::None;
+      else if (ThisL == Linkage::External)
+        ThisL = Linkage::UniqueExternal;
     }
     setLinkage(ThisL);
   }
diff --git a/clang/lib/AST/APValue.cpp b/clang/lib/AST/APValue.cpp
index d08c2936b56dd45..4eae308ef5b34c6 100644
--- a/clang/lib/AST/APValue.cpp
+++ b/clang/lib/AST/APValue.cpp
@@ -1115,7 +1115,7 @@ LinkageInfo LinkageComputer::getLVForValue(const APValue &V,
 
   auto MergeLV = [&](LinkageInfo MergeLV) {
     LV.merge(MergeLV);
-    return LV.getLinkage() == InternalLinkage;
+    return LV.getLinkage() == Linkage::Internal;
   };
   auto Merge = [&](const APValue &V) {
     return MergeLV(getLVForValue(V, computation));
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index 6efc177d61c03ba..e8062b680fbc3ab 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -1204,12 +1204,11 @@ Linkage NamedDecl::getFormalLinkage() const {
   // [basic.namespace.general]/p2
   //   A namespace is never attached to a named module and never has a name with
   //   module linkage.
-  if (isInModulePurview(this) &&
-      InternalLinkage == ExternalLinkage &&
+  if (isInModulePurview(this) && InternalLinkage == Linkage::External &&
       !isExportedFromModuleInterfaceUnit(
           cast<NamedDecl>(this->getCanonicalDecl())) &&
       !isa<NamespaceDecl>(this))
-    InternalLinkage = ModuleLinkage;
+    InternalLinkage = Linkage::Module;
 
   return clang::getFormalLinkage(InternalLinkage);
 }
@@ -1337,7 +1336,7 @@ LinkageInfo LinkageComputer::getLVForClosure(const DeclContext *DC,
   // visible, then the lambda is too. We apply the same rules to blocks.
   if (!isExternallyVisible(OwnerLV.getLinkage()))
     return LinkageInfo::none();
-  return LinkageInfo(VisibleNoLinkage, OwnerLV.getVisibility(),
+  return LinkageInfo(Linkage::VisibleNone, OwnerLV.getVisibility(),
                      OwnerLV.isVisibilityExplicit());
 }
 
@@ -1382,7 +1381,7 @@ LinkageInfo LinkageComputer::getLVForLocalDecl(const NamedDecl *D,
 
       if (const VarDecl *Prev = Var->getPreviousDecl()) {
         LinkageInfo PrevLV = getLVForDecl(Prev, computation);
-        if (PrevLV.getLinkage())
+        if (PrevLV.getLinkage() != Linkage::Invalid)
           LV.setLinkage(PrevLV.getLinkage());
         LV.mergeVisibility(PrevLV);
       }
@@ -1433,14 +1432,14 @@ LinkageInfo LinkageComputer::getLVForLocalDecl(const NamedDecl *D,
             computation.isValueVisibility()
                 ? Context.getLangOpts().getValueVisibilityMode()
                 : Context.getLangOpts().getTypeVisibilityMode();
-        return LinkageInfo(VisibleNoLinkage, globalVisibility,
+        return LinkageInfo(Linkage::VisibleNone, globalVisibility,
                            /*visibilityExplicit=*/false);
       }
     }
   }
   if (!isExternallyVisible(LV.getLinkage()))
     return LinkageInfo::none();
-  return LinkageInfo(VisibleNoLinkage, LV.getVisibility(),
+  return LinkageInfo(Linkage::VisibleNone, LV.getVisibility(),
                      LV.isVisibilityExplicit());
 }
 
@@ -1921,7 +1920,20 @@ bool NamedDecl::declarationReplaces(NamedDecl *OldD, bool IsKnownNewer) const {
 }
 
 bool NamedDecl::hasLinkage() const {
-  return getFormalLinkage() != NoLinkage;
+  switch (getFormalLinkage()) {
+  case Linkage::Invalid:
+    llvm_unreachable("Linkage hasn't been computed!");
+  case Linkage::None:
+    return false;
+  case Linkage::Internal:
+    return true;
+  case Linkage::UniqueExternal:
+  case Linkage::VisibleNone:
+    llvm_unreachable("Non-formal linkage is not allowed here!");
+  case Linkage::Module:
+  case Linkage::External:
+    return true;
+  }
 }
 
 NamedDecl *NamedDecl::getUnderlyingDeclImpl() {
diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index 261a56c4b666ae5..8530675ca2a1ce2 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -708,7 +708,7 @@ ItaniumMangleContextImpl::getEffectiveDeclContext(const Decl *D) {
 }
 
 bool ItaniumMangleContextImpl::isInternalLinkageDecl(const NamedDecl *ND) {
-  if (ND && ND->getFormalLinkage() == InternalLinkage &&
+  if (ND && ND->getFormalLinkage() == Linkage::Internal &&
       !ND->isExternallyVisible() &&
       getEffectiveDeclContext(ND)->isFileContext() &&
       !ND->isInAnonymousNamespace())
@@ -790,7 +790,7 @@ bool ItaniumMangleContextImpl::shouldMangleCXXName(const NamedDecl *D) {
     if (DC->isFunctionOrMethod() && D->hasLinkage())
       while (!DC->isFileContext())
         DC = getEffectiveParentContext(DC);
-    if (DC->isTranslationUnit() && D->getFormalLinkage() != InternalLinkage &&
+    if (DC->isTranslationUnit() && D->getFormalLinkage() != Linkage::Internal &&
         !CXXNameMangler::shouldHaveAbiTags(*this, VD) &&
         !isa<VarTemplateSpecializationDecl>(VD) &&
         !VD->getOwningModuleForLinkage())
diff --git a/clang/lib/AST/MicrosoftMangle.cpp b/clang/lib/AST/MicrosoftMangle.cpp
index f6d8cdee8443d59..b7cfcbc9dfa4677 100644
--- a/clang/lib/AST/MicrosoftMangle.cpp
+++ b/clang/lib/AST/MicrosoftMangle.cpp
@@ -539,9 +539,8 @@ bool MicrosoftMangleContextImpl::shouldMangleCXXName(const NamedDecl *D) {
       while (!DC->isNamespace() && !DC->isTranslationUnit())
         DC = getEffectiveParentContext(DC);
 
-    if (DC->isTranslationUnit() && D->getFormalLinkage() == InternalLinkage &&
-        !isa<VarTemplateSpecializationDecl>(D) &&
-        D->getIdentifier() != nullptr)
+    if (DC->isTranslationUnit() && D->getFormalLinkage() == Linkage::Internal &&
+        !isa<VarTemplateSpecializationDecl>(D) && D->getIdentifier() != nullptr)
       return false;
   }
 
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index 98a4f12c4f574fa..d1cbfbd150ba53f 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -4175,7 +4175,7 @@ template <class Private> class TypePropertyCache {
     // Compute the cached properties and then set the cache.
     CachedProperties Result = computeCachedProperties(T);
     T->TypeBits.CacheValid = true;
-    T->TypeBits.CachedLinkage = Result.getLinkage();
+    T->TypeBits.CachedLinkage = llvm::to_underlying(Result.getLinkage());
     T->TypeBits.CachedLocalOrUnnamed = Result.hasLocalOrUnnamedType();
   }
 };
@@ -4207,20 +4207,20 @@ static CachedProperties computeCachedProperties(const Type *T) {
     // Treat instantiation-dependent types as external.
     if (!T->isInstantiationDependentType()) T->dump();
     assert(T->isInstantiationDependentType());
-    return CachedProperties(ExternalLinkage, false);
+    return CachedProperties(Linkage::External, false);
 
   case Type::Auto:
   case Type::DeducedTemplateSpecialization:
     // Give non-deduced 'auto' types external linkage. We should only see them
     // here in error recovery.
-    return CachedProperties(ExternalLinkage, false);
+    return CachedProperties(Linkage::External, false);
 
   case Type::BitInt:
   case Type::Builtin:
     // C++ [basic.link]p8:
     //   A type is said to have linkage if and only if:
     //     - it is a fundamental type (3.9.1); or
-    return CachedProperties(ExternalLinkage, false);
+    return CachedProperties(Linkage::External, false);
 
   case Type::Record:
   case Type::Enum: {
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index cc81a68b15c4324..35f651b39f6748a 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -3997,7 +3997,7 @@ TargetMVPriority(const TargetInfo &TI,
 llvm::GlobalValue::LinkageTypes getMultiversionLinkage(CodeGenModule &CGM,
                                                        GlobalDecl GD) {
   const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl());
-  if (FD->getFormalLinkage() == InternalLinkage)
+  if (FD->getFormalLinkage() == Linkage::Internal)
     return llvm::GlobalValue::InternalLinkage;
   return llvm::GlobalValue::WeakODRLinkage;
 }
@@ -5051,7 +5051,7 @@ void CodeGenModule::MaybeHandleStaticInExternC(const SomeDecl *D,
     return;
 
   // Must have internal linkage and an ordinary name.
-  if (!D->getIdentifier() || D->getFormalLinkage() != InternalLinkage)
+  if (!D->getIdentifier() || D->getFormalLinkage() != Linkage::Internal)
     return;
 
   // Must be in an extern "C" context. Entities declared directly within
diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp
index c7295b3144ed16e..55d2696750ae7a0 100644
--- a/clang/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp
@@ -3706,14 +3706,17 @@ static llvm::GlobalVariable::LinkageTypes getTypeInfoLinkage(CodeGenModule &CGM,
     return llvm::GlobalValue::InternalLinkage;
 
   switch (Ty->getLinkage()) {
-  case NoLinkage:
-  case InternalLinkage:
-  case UniqueExternalLinkage:
+  case Linkage::Invalid:
+    llvm_unreachable("Linkage hasn't been computed!");
+
+  case Linkage::None:
+  case Linkage::Internal:
+  case Linkage::UniqueExternal:
     return llvm::GlobalValue::InternalLinkage;
 
-  case VisibleNoLinkage:
-  case ModuleLinkage:
-  case ExternalLinkage:
+  case Linkage::VisibleNone:
+  case Linkage::Module:
+  case Linkage::External:
     // RTTI is not enabled, which means that this type info struct is going
     // to be used for exception handling. Give it linkonce_odr linkage.
     if (!CGM.getLangOpts().RTTI)
diff --git a/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/clang/lib/CodeGen/MicrosoftCXXABI.cpp
index b6f941052abee85..4e55d6be376a517 100644
--- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp
+++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp
@@ -3644,14 +3644,17 @@ uint32_t MSRTTIClass::initialize(const MSRTTIClass *Parent,
 
 static llvm::GlobalValue::LinkageTypes getLinkageForRTTI(QualType Ty) {
   switch (Ty->getLinkage()) {
-  case NoLinkage:
-  case InternalLinkage:
-  case UniqueExternalLinkage:
+  case Linkage::Invalid:
+    llvm_unreachable("Linkage hasn't been computed!");
+
+  case Linkage::None:
+  case Linkage::Internal:
+  case Linkage::UniqueExternal:
     return llvm::GlobalValue::InternalLinkage;
 
-  case VisibleNoLinkage:
-  case ModuleLinkage:
-  case ExternalLinkage:
+  case Linkage::VisibleNone:
+  case Linkage::Module:
+  case Linkage::External:
     return llvm::GlobalValue::LinkOnceODRLinkage;
   }
   llvm_unreachable("Invalid linkage!");
diff --git a/clang/lib/Index/IndexSymbol.cpp b/clang/lib/Index/IndexSymbol.cpp
index cfdffeed834e687..10384660d2cb683 100644
--- a/clang/lib/Index/IndexSymbol.cpp
+++ b/clang/lib/Index/IndexSymbol.cpp
@@ -66,15 +66,17 @@ bool index::isFunctionLocalSymbol(const Decl *D) {
 
   if (const NamedDecl *ND = dyn_cast<NamedDecl>(D)) {
     switch (ND->getFormalLinkage()) {
-      case NoLinkage:
-      case InternalLinkage:
-        return true;
-      case VisibleNoLinkage:
-      case UniqueExternalLinkage:
-        llvm_unreachable("Not a sema linkage");
-      case ModuleLinkage:
-      case ExternalLinkage:
-        return false;
+    case Linkage::Invalid:
+      llvm_unreachable("Linkage hasn't been computed!");
+    case Linkage::None:
+    case Linkage::Internal:
+      return true;
+    case Linkage::VisibleNone:
+    case Linkage::UniqueExternal:
+      llvm_unreachable("Not a sema linkage");
+    case Linkage::Module:
+    case Linkage::External:
+      return false;
     }
   }
 
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 1842a783dc29aaa..12915a32d02ea08 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -7336,7 +7336,7 @@ void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto,
 
         if (Context.getTargetInfo().getTriple().isOSAIX() && FDecl && Arg &&
             FDecl->hasLinkage() &&
-            FDecl->getFormalLinkage() != InternalLinkage &&
+            FDecl->getFormalLinkage() != Linkage::Internal &&
             CallType == VariadicDoesNotApply)
           checkAIXMemberAlignment((Arg->getExprLoc()), Arg);
 
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index a8bad12b670fc75..b4affa7277f6b2b 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -1730,9 +1730,9 @@ bool Sema::CheckRedeclarationExported(NamedDecl *New, NamedDecl *Old) {
 
   auto Lk = Old->getFormalLinkage();
   int S = 0;
-  if (Lk == Linkage::InternalLinkage)
+  if (Lk == Linkage::Internal)
     S = 1;
-  else if (Lk == Linkage::ModuleLinkage)
+  else if (Lk == Linkage::Module)
     S = 2;
   Diag(New->getLocation(), diag::err_redeclaration_non_exported) << New << S;
   Diag(Old->getLocation(), diag::note_previous_declaration);
@@ -4843,11 +4843,9 @@ void Sema::notePreviousDefinition(const NamedDecl *Old, SourceLocation New) {
 /// of the same variable. Either diagnose or fix the problem.
 bool Sema::checkVarDeclRedefinition(VarDecl *Old, VarDecl *New) {
   if (!hasVisibleDefinition(Old) &&
-      (New->getFormalLinkage() == InternalLinkage ||
-       New->isInline() ||
+      (New->getFormalLinkage() == Linkage::Internal || New->isInline() ||
        isa<VarTemplateSpecializationDecl>(New) ||
-       New->getDescribedVarTemplate() ||
-       New->getNumTemplateParameterLists() ||
+       New->getDescribedVarTemplate() || New->getNumTemplateParameterLists() ||
        New->getDeclContext()->isDependentContext())) {
     // The previous definition is hidden, and multiple definitions are
     // permitted (in separate TUs). Demote this to a declaration.
@@ -13413,9 +13411,8 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) {
   // units.
   if (getLangOpts().CPlusPlusModules && currentModuleIsHeaderUnit() &&
       !VDecl->isInvalidDecl() && VDecl->isThisDeclarationADefinition() &&
-      VDecl->getFormalLinkage() == Linkage::ExternalLinkage &&
-      !VDecl->isInline() && !VDecl->isTemplated() &&
-      !isa<VarTemplateSpecializationDecl>(VDecl)) {
+      VDecl->getFormalLinkage() == Linkage::External && !VDecl->isInline() &&
+      !VDecl->isTemplated() && !isa<VarTemplateSpecializationDecl>(VDecl)) {
     Diag(VDecl->getLocation(), diag::err_extern_def_in_header_unit);
     VDecl->setInvalidDecl();
   }
@@ -15394,9 +15391,8 @@ Sema::CheckForFunctionRedefinition(FunctionDecl *FD,
   // If we don't have a visible definition of the function, and it's inline or
   // a template, skip the new definition.
   if (SkipBody && !hasVisibleDefinition(Definition) &&
-      (Definition->getFormalLinkage() == InternalLinkage ||
-       Definition->isInlined() ||
-       Definition->getDescribedFunctionTemplate() ||
+      (Definition->getFormalLinkage() == Linkage::Internal ||
+       Definition->isInlined() || Definition->getDescribedFunctionTemplate() ||
        Definition->getNumTemplateParameterLists())) {
     SkipBody->ShouldSkip = true;
     SkipBody->Previous = const_cast<FunctionDecl*>(Definition);
@@ -15652,8 +15648,8 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D,
   if (getLangOpts().CPlusPlusModules && currentModuleIsHeaderUnit() &&
       !FD->isInvalidDecl() && !FD->isInlined() &&
       BodyKind != FnBodyKind::Delete && BodyKind != FnBodyKind::Default &&
-      FD->getFormalLinkage() == Linkage::ExternalLinkage &&
-      !FD->isTemplated() && !FD->isTemplateInstantiation()) {
+      FD->getFormalLinkage() == Linkage::External && !FD->isTemplated() &&
+      !FD->isTemplateInstantiation()) {
     assert(FD->isThisDeclarationADefinition());
     Diag(FD->getLocation(), diag::err_extern_def_in_header_unit);
     FD->setInvalidDecl();
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 2a3cd7a00806d3a..4a4cb02b0e4a6d7 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -173,7 +173,7 @@ static void diagnoseUseOfInternalDeclInInlineFunction(Sema &S,
     return;
 
   // Check if the decl has internal linkage.
-  if (D->getFormalLinkage() != InternalLinkage)
+  if (D->getFormalLinkage() != Linkage::Internal)
     return;
 
   // Downgrade from ExtWarn to Extension if
diff --git a/clang/lib/Sema/SemaModule.cpp b/clang/lib/Sema/SemaModule.cpp
index 5582afb119047bc..8a296837e2a192c 100644
--- a/clang/lib/Sema/SemaModule.cpp
+++ b/clang/lib/Sema/SemaModule.cpp
@@ -844,7 +844,7 @@ static bool checkExportedDecl(Sema &S, Decl *D, SourceLocation BlockStart) {
     // Don't diagnose anonymous union objects; we'll diagnose their members
     // instead.
     HasName = (bool)ND->getDeclName();
-    if (HasName && ND->getFormalLinkage() == InternalLinkage) {
+    if (HasName && ND->getFormalLinkage() == Linkage::Internal) {
       S.Diag(ND->getLocation(), diag::err_export_internal) << ND;
       if (BlockStart.isValid())
         S.Diag(BlockStart, diag::note_export);
@@ -858,9 +858,9 @@ static bool checkExportedDecl(Sema &S, Decl *D, SourceLocation BlockStart) {
   if (auto *USD = dyn_cast<UsingShadowDecl>(D)) {
     NamedDecl *Target = USD->getUnderlyingDecl();
     Linkage Lk = Target->getFormalLinkage();
-    if (Lk == InternalLinkage || Lk == ModuleLinkage) {
+    if (Lk == Linkage::Internal || Lk == Linkage::Module) {
       S.Diag(USD->getLocation(), diag::err_export_using_internal)
-          << (Lk == InternalLinkage ? 0 : 1) << Target;
+          << (Lk == Linkage::Internal ? 0 : 1) << Target;
       S.Diag(Target->getLocation(), diag::note_using_decl_target);
       if (BlockStart.isValid())
         S.Diag(BlockStart, diag::note_export);
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index d3d2dfed2ce0cc2..f97e244120612e3 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -6795,7 +6795,7 @@ void Sema::AddOverloadCandidate(
     if (auto *SpecInfo = Function->getTemplateSpecializationInfo())
       ND = SpecInfo->getTemplate();
 
-    if (ND->getFormalLinkage() == Linkage::InternalLinkage) {
+    if (ND->getFormalLinkage() == Linkage::Internal) {
       Candidate.Viable = false;
       Candidate.FailureKind = ovl_fail_module_mismatched;
       return;
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 59721c8dc664aa9..b09237f0112989c 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -6898,7 +6898,7 @@ static bool CheckTemplateArgumentAddressOfObjectOrFunction(
   }
 
   // Address / reference template args must have external linkage in C++98.
-  if (Entity->getFormalLinkage() == InternalLinkage) {
+  if (Entity->getFormalLinkage() == Linkage::Internal) {
     S.Diag(Arg->getBeginLoc(),
            S.getLangOpts().CPlusPlus11
                ? diag::warn_cxx98_compat_template_arg_object_internal
@@ -9920,7 +9920,7 @@ static bool CheckExplicitInstantiation(Sema &S, NamedDecl *D,
   //   An explicit instantiation declaration shall not name a specialization of
   //   a template with internal linkage.
   if (TSK == TSK_ExplicitInstantiationDeclaration &&
-      D->getFormalLinkage() == InternalLinkage) {
+      D->getFormalLinkage() == Linkage::Internal) {
     S.Diag(InstLoc, diag::err_explicit_instantiation_internal_linkage) << D;
     return true;
   }
diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp
index 319a45108c6ab66..00f57f88781e632 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -1606,11 +1606,11 @@ ASTDeclReader::RedeclarableResult ASTDeclReader::VisitVarDeclImpl(VarDecl *VD) {
     VD->setType(Reader.GetType(DeferredTypeID));
   DeferredTypeID = 0;
 
-  auto VarLinkage = Linkage(Record.readInt());
+  auto VarLinkage = static_cast<Linkage>(Record.readInt());
   VD->setCachedLinkage(VarLinkage);
 
   // Reconstruct the one piece of the IdentifierNamespace that we need.
-  if (VD->getStorageClass() == SC_Extern && VarLinkage != NoLinkage &&
+  if (VD->getStorageClass() == SC_Extern && VarLinkage != Linkage::None &&
       VD->getLexicalDeclContext()->isFunctionOrMethod())
     VD->setLocalExternDecl();
 
diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp
index 78c5e1750dbca64..d50aa7e336099d3 100644
--- a/clang/lib/Serialization/ASTWriterDecl.cpp
+++ b/clang/lib/Serialization/ASTWriterDecl.cpp
@@ -683,7 +683,7 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
   Record.push_back(D->isMultiVersion());
   Record.push_back(D->isLateTemplateParsed());
   Record.push_back(D->FriendConstraintRefersToEnclosingTemplate());
-  Record.push_back(D->getLinkageInternal());
+  Record.push_back(llvm::to_underlying(D->getLinkageInternal()));
   Record.AddSourceLocation(D->getEndLoc());
   Record.AddSourceLocation(D->getDefaultLoc());
 
@@ -1067,7 +1067,7 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) {
     HasDeducedType = D->getType()->getContainedDeducedType();
     Record.push_back(HasDeducedType);
   }
-  Record.push_back(D->getLinkageInternal());
+  Record.push_back(llvm::to_underlying(D->getLinkageInternal()));
 
   if (D->hasAttr<BlocksAttr>()) {
     BlockVarCopyInit Init = Writer.Context->getBlockVarCopyInit(D);
@@ -2214,7 +2214,7 @@ void ASTWriter::WriteDeclAbbrevs() {
   Abv->Add(BitCodeAbbrevOp(0));                       // TSCSpec
   Abv->Add(BitCodeAbbrevOp(0));                       // InitStyle
   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isARCPseudoStrong
-  Abv->Add(BitCodeAbbrevOp(0));                       // Linkage
+  Abv->Add(BitCodeAbbrevOp(1));                         // Linkage
   Abv->Add(BitCodeAbbrevOp(0));                       // ModulesCodegen
   Abv->Add(BitCodeAbbrevOp(0));                       // VarKind (local enum)
   // ParmVarDecl
diff --git a/clang/tools/clang-extdef-mapping/ClangExtDefMapGen.cpp b/clang/tools/clang-extdef-mapping/ClangExtDefMapGen.cpp
index 2d4f398f76f6d7e..769727eedec7216 100644
--- a/clang/tools/clang-extdef-mapping/ClangExtDefMapGen.cpp
+++ b/clang/tools/clang-extdef-mapping/ClangExtDefMapGen.cpp
@@ -98,12 +98,14 @@ void MapExtDefNamesConsumer::addIfInMain(const DeclaratorDecl *DD,
   }
 
   switch (DD->getLinkageInternal()) {
-  case ExternalLinkage:
-  case VisibleNoLinkage:
-  case UniqueExternalLinkage:
+  case Linkage::External:
+  case Linkage::VisibleNone:
+  case Linkage::UniqueExternal:
     if (SM.isInMainFile(defStart))
       Index[*LookupName] = CurrentFileName;
     break;
+  case Linkage::Invalid:
+    llvm_unreachable("Linkage has not been computed!");
   default:
     break;
   }
diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp
index 169ce4f9b7c6a4d..df630f66f0b946a 100644
--- a/clang/tools/libclang/CIndex.cpp
+++ b/clang/tools/libclang/CIndex.cpp
@@ -8246,15 +8246,17 @@ CXLinkageKind clang_getCursorLinkage(CXCursor cursor) {
   const Decl *D = cxcursor::getCursorDecl(cursor);
   if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(D))
     switch (ND->getLinkageInternal()) {
-    case NoLinkage:
-    case VisibleNoLinkage:
+    case Linkage::Invalid:
+      return CXLinkage_Invalid;
+    case Linkage::None:
+    case Linkage::VisibleNone:
       return CXLinkage_NoLinkage;
-    case InternalLinkage:
+    case Linkage::Internal:
       return CXLinkage_Internal;
-    case UniqueExternalLinkage:
+    case Linkage::UniqueExternal:
       return CXLinkage_UniqueExternal;
-    case ModuleLinkage:
-    case ExternalLinkage:
+    case Linkage::Module:
+    case Linkage::External:
       return CXLinkage_External;
     };
 
diff --git a/clang/tools/libclang/CXIndexDataConsumer.cpp b/clang/tools/libclang/CXIndexDataConsumer.cpp
index cb9c81328b397e7..92b33719a523e83 100644
--- a/clang/tools/libclang/CXIndexDataConsumer.cpp
+++ b/clang/tools/libclang/CXIndexDataConsumer.cpp
@@ -431,14 +431,16 @@ bool CXIndexDataConsumer::isFunctionLocalDecl(const Decl *D) {
 
   if (const NamedDecl *ND = dyn_cast<NamedDecl>(D)) {
     switch (ND->getFormalLinkage()) {
-    case NoLinkage:
-    case InternalLinkage:
+    case Linkage::Invalid:
+      llvm_unreachable("Linkage hasn't been computed!");
+    case Linkage::None:
+    case Linkage::Internal:
       return true;
-    case VisibleNoLinkage:
-    case UniqueExternalLinkage:
+    case Linkage::VisibleNone:
+    case Linkage::UniqueExternal:
       llvm_unreachable("Not a sema linkage");
-    case ModuleLinkage:
-    case ExternalLinkage:
+    case Linkage::Module:
+    case Linkage::External:
       return false;
     }
   }
@@ -560,7 +562,7 @@ bool CXIndexDataConsumer::handleDecl(const NamedDecl *D,
 
   if (shouldSuppressRefs())
     markEntityOccurrenceInFile(D, Loc);
-  
+
   DInfo.entityInfo = &DInfo.EntInfo;
   DInfo.cursor = Cursor;
   DInfo.loc = getIndexLoc(Loc);
@@ -664,10 +666,9 @@ bool CXIndexDataConsumer::handleObjCInterface(const ObjCInterfaceDecl *D) {
     bool isRedeclaration = D->hasDefinition() || D->getPreviousDecl();
     ObjCContainerDeclInfo ContDInfo(/*isForwardRef=*/true, isRedeclaration,
                                     /*isImplementation=*/false);
-    return handleObjCContainer(D, D->getLocation(),
-                               MakeCursorObjCClassRef(D, D->getLocation(),
-                                                      CXTU), 
-                               ContDInfo);
+    return handleObjCContainer(
+        D, D->getLocation(), MakeCursorObjCClassRef(D, D->getLocation(), CXTU),
+        ContDInfo);
   }
 
   ScratchAlloc SA(*this);
@@ -685,13 +686,13 @@ bool CXIndexDataConsumer::handleObjCInterface(const ObjCInterfaceDecl *D) {
     if (shouldSuppressRefs())
       markEntityOccurrenceInFile(SuperD, SuperLoc);
   }
-  
+
   ObjCProtocolList EmptyProtoList;
-  ObjCProtocolListInfo ProtInfo(D->isThisDeclarationADefinition() 
-                                  ? D->getReferencedProtocols()
-                                  : EmptyProtoList, 
+  ObjCProtocolListInfo ProtInfo(D->isThisDeclarationADefinition()
+                                    ? D->getReferencedProtocols()
+                                    : EmptyProtoList,
                                 *this, SA);
-  
+
   ObjCInterfaceDeclInfo InterInfo(D);
   InterInfo.ObjCProtoListInfo = ProtInfo.getListInfo();
   InterInfo.ObjCInterDeclInfo.containerInfo = &InterInfo.ObjCContDeclInfo;
@@ -714,25 +715,24 @@ bool CXIndexDataConsumer::handleObjCProtocol(const ObjCProtocolDecl *D) {
   if (!D->isThisDeclarationADefinition()) {
     if (shouldSuppressRefs() && markEntityOccurrenceInFile(D, D->getLocation()))
       return false; // already occurred.
-    
+
     // FIXME: This seems like the wrong definition for redeclaration.
     bool isRedeclaration = D->hasDefinition() || D->getPreviousDecl();
     ObjCContainerDeclInfo ContDInfo(/*isForwardRef=*/true,
                                     isRedeclaration,
                                     /*isImplementation=*/false);
-    return handleObjCContainer(D, D->getLocation(), 
-                               MakeCursorObjCProtocolRef(D, D->getLocation(),
-                                                         CXTU),
-                               ContDInfo);    
+    return handleObjCContainer(
+        D, D->getLocation(),
+        MakeCursorObjCProtocolRef(D, D->getLocation(), CXTU), ContDInfo);
   }
-  
+
   ScratchAlloc SA(*this);
   ObjCProtocolList EmptyProtoList;
   ObjCProtocolListInfo ProtListInfo(D->isThisDeclarationADefinition()
                                       ? D->getReferencedProtocols()
                                       : EmptyProtoList,
                                     *this, SA);
-  
+
   ObjCProtocolDeclInfo ProtInfo(D);
   ProtInfo.ObjCProtoRefListInfo = ProtListInfo.getListInfo();
 
@@ -754,7 +754,7 @@ bool CXIndexDataConsumer::handleObjCCategory(const ObjCCategoryDecl *D) {
     markEntityOccurrenceInFile(IFaceD, ClassLoc);
 
   ObjCProtocolListInfo ProtInfo(D->getReferencedProtocols(), *this, SA);
-  
+
   CatDInfo.ObjCCatDeclInfo.containerInfo = &CatDInfo.ObjCContDeclInfo;
   if (IFaceD) {
     CatDInfo.ObjCCatDeclInfo.objcClass = &ClassEntity;
@@ -1014,12 +1014,12 @@ bool CXIndexDataConsumer::markEntityOccurrenceInFile(const NamedDecl *D,
 
   SourceManager &SM = Ctx->getSourceManager();
   D = getEntityDecl(D);
-  
+
   std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(SM.getFileLoc(Loc));
   FileID FID = LocInfo.first;
   if (FID.isInvalid())
     return true;
-  
+
   const FileEntry *FE = SM.getFileEntryForID(FID);
   if (!FE)
     return true;
@@ -1102,7 +1102,7 @@ void CXIndexDataConsumer::translateLoc(SourceLocation Loc,
 
   if (FID.isInvalid())
     return;
-  
+
   OptionalFileEntryRefDegradesToFileEntryPtr FE = SM.getFileEntryRefForID(FID);
   if (indexFile)
     *indexFile = getIndexFile(FE);
@@ -1196,7 +1196,7 @@ CXCursor CXIndexDataConsumer::getRefCursor(const NamedDecl *D, SourceLocation Lo
     return MakeCursorMemberRef(Field, Loc, CXTU);
   if (const VarDecl *Var = dyn_cast<VarDecl>(D))
     return MakeCursorVariableRef(Var, Loc, CXTU);
-  
+
   return clang_getNullCursor();
 }
 
diff --git a/clang/unittests/AST/DeclTest.cpp b/clang/unittests/AST/DeclTest.cpp
index 474d3dadb5a52c6..cef0f8711416b69 100644
--- a/clang/unittests/AST/DeclTest.cpp
+++ b/clang/unittests/AST/DeclTest.cpp
@@ -247,16 +247,16 @@ TEST(Decl, ModuleAndInternalLinkage) {
   const auto *f = selectFirst<FunctionDecl>(
       "f", match(functionDecl(hasName("f")).bind("f"), Ctx));
 
-  EXPECT_EQ(a->getFormalLinkage(), InternalLinkage);
-  EXPECT_EQ(f->getFormalLinkage(), InternalLinkage);
+  EXPECT_EQ(a->getFormalLinkage(), Linkage::Internal);
+  EXPECT_EQ(f->getFormalLinkage(), Linkage::Internal);
 
   const auto *b =
       selectFirst<VarDecl>("b", match(varDecl(hasName("b")).bind("b"), Ctx));
   const auto *g = selectFirst<FunctionDecl>(
       "g", match(functionDecl(hasName("g")).bind("g"), Ctx));
 
-  EXPECT_EQ(b->getFormalLinkage(), ModuleLinkage);
-  EXPECT_EQ(g->getFormalLinkage(), ModuleLinkage);
+  EXPECT_EQ(b->getFormalLinkage(), Linkage::Module);
+  EXPECT_EQ(g->getFormalLinkage(), Linkage::Module);
 }
 
 TEST(Decl, GetNonTransparentDeclContext) {

>From a466e79da1af6eaf75a68e80114b5be078056726 Mon Sep 17 00:00:00 2001
From: Vlad Serebrennikov <serebrennikov.vladislav at gmail.com>
Date: Thu, 2 Nov 2023 15:56:19 +0300
Subject: [PATCH 2/4] Revert formatting changes to CXIndexDataConsumer.cpp

---
 clang/tools/libclang/CXIndexDataConsumer.cpp | 42 ++++++++++----------
 1 file changed, 22 insertions(+), 20 deletions(-)

diff --git a/clang/tools/libclang/CXIndexDataConsumer.cpp b/clang/tools/libclang/CXIndexDataConsumer.cpp
index 92b33719a523e83..5ca484fbc8cd82b 100644
--- a/clang/tools/libclang/CXIndexDataConsumer.cpp
+++ b/clang/tools/libclang/CXIndexDataConsumer.cpp
@@ -562,7 +562,7 @@ bool CXIndexDataConsumer::handleDecl(const NamedDecl *D,
 
   if (shouldSuppressRefs())
     markEntityOccurrenceInFile(D, Loc);
-
+  
   DInfo.entityInfo = &DInfo.EntInfo;
   DInfo.cursor = Cursor;
   DInfo.loc = getIndexLoc(Loc);
@@ -666,9 +666,10 @@ bool CXIndexDataConsumer::handleObjCInterface(const ObjCInterfaceDecl *D) {
     bool isRedeclaration = D->hasDefinition() || D->getPreviousDecl();
     ObjCContainerDeclInfo ContDInfo(/*isForwardRef=*/true, isRedeclaration,
                                     /*isImplementation=*/false);
-    return handleObjCContainer(
-        D, D->getLocation(), MakeCursorObjCClassRef(D, D->getLocation(), CXTU),
-        ContDInfo);
+    return handleObjCContainer(D, D->getLocation(),
+                               MakeCursorObjCClassRef(D, D->getLocation(),
+                                                      CXTU), 
+                               ContDInfo);
   }
 
   ScratchAlloc SA(*this);
@@ -686,13 +687,13 @@ bool CXIndexDataConsumer::handleObjCInterface(const ObjCInterfaceDecl *D) {
     if (shouldSuppressRefs())
       markEntityOccurrenceInFile(SuperD, SuperLoc);
   }
-
+  
   ObjCProtocolList EmptyProtoList;
-  ObjCProtocolListInfo ProtInfo(D->isThisDeclarationADefinition()
-                                    ? D->getReferencedProtocols()
-                                    : EmptyProtoList,
+  ObjCProtocolListInfo ProtInfo(D->isThisDeclarationADefinition() 
+                                  ? D->getReferencedProtocols()
+                                  : EmptyProtoList, 
                                 *this, SA);
-
+  
   ObjCInterfaceDeclInfo InterInfo(D);
   InterInfo.ObjCProtoListInfo = ProtInfo.getListInfo();
   InterInfo.ObjCInterDeclInfo.containerInfo = &InterInfo.ObjCContDeclInfo;
@@ -715,24 +716,25 @@ bool CXIndexDataConsumer::handleObjCProtocol(const ObjCProtocolDecl *D) {
   if (!D->isThisDeclarationADefinition()) {
     if (shouldSuppressRefs() && markEntityOccurrenceInFile(D, D->getLocation()))
       return false; // already occurred.
-
+    
     // FIXME: This seems like the wrong definition for redeclaration.
     bool isRedeclaration = D->hasDefinition() || D->getPreviousDecl();
     ObjCContainerDeclInfo ContDInfo(/*isForwardRef=*/true,
                                     isRedeclaration,
                                     /*isImplementation=*/false);
-    return handleObjCContainer(
-        D, D->getLocation(),
-        MakeCursorObjCProtocolRef(D, D->getLocation(), CXTU), ContDInfo);
+    return handleObjCContainer(D, D->getLocation(), 
+                               MakeCursorObjCProtocolRef(D, D->getLocation(),
+                                                         CXTU),
+                               ContDInfo);    
   }
-
+  
   ScratchAlloc SA(*this);
   ObjCProtocolList EmptyProtoList;
   ObjCProtocolListInfo ProtListInfo(D->isThisDeclarationADefinition()
                                       ? D->getReferencedProtocols()
                                       : EmptyProtoList,
                                     *this, SA);
-
+  
   ObjCProtocolDeclInfo ProtInfo(D);
   ProtInfo.ObjCProtoRefListInfo = ProtListInfo.getListInfo();
 
@@ -754,7 +756,7 @@ bool CXIndexDataConsumer::handleObjCCategory(const ObjCCategoryDecl *D) {
     markEntityOccurrenceInFile(IFaceD, ClassLoc);
 
   ObjCProtocolListInfo ProtInfo(D->getReferencedProtocols(), *this, SA);
-
+  
   CatDInfo.ObjCCatDeclInfo.containerInfo = &CatDInfo.ObjCContDeclInfo;
   if (IFaceD) {
     CatDInfo.ObjCCatDeclInfo.objcClass = &ClassEntity;
@@ -1014,12 +1016,12 @@ bool CXIndexDataConsumer::markEntityOccurrenceInFile(const NamedDecl *D,
 
   SourceManager &SM = Ctx->getSourceManager();
   D = getEntityDecl(D);
-
+  
   std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(SM.getFileLoc(Loc));
   FileID FID = LocInfo.first;
   if (FID.isInvalid())
     return true;
-
+  
   const FileEntry *FE = SM.getFileEntryForID(FID);
   if (!FE)
     return true;
@@ -1102,7 +1104,7 @@ void CXIndexDataConsumer::translateLoc(SourceLocation Loc,
 
   if (FID.isInvalid())
     return;
-
+  
   OptionalFileEntryRefDegradesToFileEntryPtr FE = SM.getFileEntryRefForID(FID);
   if (indexFile)
     *indexFile = getIndexFile(FE);
@@ -1196,7 +1198,7 @@ CXCursor CXIndexDataConsumer::getRefCursor(const NamedDecl *D, SourceLocation Lo
     return MakeCursorMemberRef(Field, Loc, CXTU);
   if (const VarDecl *Var = dyn_cast<VarDecl>(D))
     return MakeCursorVariableRef(Var, Loc, CXTU);
-
+  
   return clang_getNullCursor();
 }
 

>From 633a2ef979056653e88ce42ce14284781ec2fbbd Mon Sep 17 00:00:00 2001
From: Vlad Serebrennikov <serebrennikov.vladislav at gmail.com>
Date: Thu, 2 Nov 2023 16:29:31 +0300
Subject: [PATCH 3/4] Change default linkage in `Type` constructor to `Invalid`

---
 clang/include/clang/AST/Type.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index 96c12a84e139f40..553db9d7803dce6 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -1996,7 +1996,7 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase {
     TypeBits.Dependence = static_cast<unsigned>(Dependence);
     TypeBits.CacheValid = false;
     TypeBits.CachedLocalOrUnnamed = false;
-    TypeBits.CachedLinkage = llvm::to_underlying(Linkage::None);
+    TypeBits.CachedLinkage = llvm::to_underlying(Linkage::Invalid);
     TypeBits.FromAST = false;
   }
 

>From 390752140139fca07ec78a100e8f49acb3df5293 Mon Sep 17 00:00:00 2001
From: Vlad Serebrennikov <serebrennikov.vladislav at gmail.com>
Date: Thu, 2 Nov 2023 16:30:05 +0300
Subject: [PATCH 4/4] Apply Chuanqi's suggestion

---
 clang/lib/Serialization/ASTWriterDecl.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp
index d50aa7e336099d3..ef28e69abc4e166 100644
--- a/clang/lib/Serialization/ASTWriterDecl.cpp
+++ b/clang/lib/Serialization/ASTWriterDecl.cpp
@@ -2214,7 +2214,7 @@ void ASTWriter::WriteDeclAbbrevs() {
   Abv->Add(BitCodeAbbrevOp(0));                       // TSCSpec
   Abv->Add(BitCodeAbbrevOp(0));                       // InitStyle
   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isARCPseudoStrong
-  Abv->Add(BitCodeAbbrevOp(1));                         // Linkage
+  Abv->Add(BitCodeAbbrevOp(1));                         // Linkage::None
   Abv->Add(BitCodeAbbrevOp(0));                       // ModulesCodegen
   Abv->Add(BitCodeAbbrevOp(0));                       // VarKind (local enum)
   // ParmVarDecl



More information about the cfe-commits mailing list