Skip to content

Commit

Permalink
[clang][NFC] Refactor clang::Linkage (#71049)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Endilll committed Nov 2, 2023
1 parent 8a3e4b5 commit 8775947
Show file tree
Hide file tree
Showing 28 changed files with 169 additions and 130 deletions.
4 changes: 2 additions & 2 deletions clang-tools-extra/clang-doc/Serialize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
3 changes: 2 additions & 1 deletion clang-tools-extra/clangd/Quality.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
3 changes: 2 additions & 1 deletion clang-tools-extra/clangd/SemanticHighlighting.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
11 changes: 5 additions & 6 deletions clang/include/clang/AST/DeclBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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);
}

Expand All @@ -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);
}

Expand All @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/AST/Type.h
Original file line number Diff line number Diff line change
Expand Up @@ -2043,7 +2043,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::Invalid);
TypeBits.FromAST = false;
}

Expand Down
53 changes: 34 additions & 19 deletions clang/include/clang/Basic/Linkage.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
///
Expand All @@ -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
Expand Down Expand Up @@ -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.
Expand All @@ -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;
}
Expand Down
28 changes: 15 additions & 13 deletions clang/include/clang/Basic/Visibility.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#define LLVM_CLANG_BASIC_VISIBILITY_H

#include "clang/Basic/Linkage.h"
#include "llvm/ADT/STLForwardCompat.h"
#include <cassert>
#include <cstdint>

Expand Down Expand Up @@ -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!");
}
Expand All @@ -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));
Expand All @@ -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);
}
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/APValue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down
28 changes: 20 additions & 8 deletions clang/lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down Expand Up @@ -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());
}

Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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());
}

Expand Down Expand Up @@ -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() {
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/AST/ItaniumMangle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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())
Expand Down Expand Up @@ -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())
Expand Down
5 changes: 2 additions & 3 deletions clang/lib/AST/MicrosoftMangle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down

0 comments on commit 8775947

Please sign in to comment.