aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn McCall <rjmccall@apple.com>2010-10-22 21:05:15 +0000
committerJohn McCall <rjmccall@apple.com>2010-10-22 21:05:15 +0000
commit1fb0caaa7bef765b85972274e3b434af2572c141 (patch)
tree39b9f78902f8581d6749d0d0dc99fc1f2ae1d8d5
parent07ed93f378a8868c9a7c04ca7ae685b85c55e5ea (diff)
Substantially revise how clang computes the visibility of a declaration to
more closely parallel the computation of linkage. This gets us to a state much closer to what gcc emits, modulo bugs, which will undoubtedly arise in abundance. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@117147 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/AST/Decl.h8
-rw-r--r--include/clang/AST/Type.h93
-rw-r--r--include/clang/Basic/LangOptions.h14
-rw-r--r--include/clang/Basic/Visibility.h48
-rw-r--r--lib/AST/Decl.cpp390
-rw-r--r--lib/AST/Type.cpp161
-rw-r--r--lib/CodeGen/CGCXX.cpp2
-rw-r--r--lib/CodeGen/CGObjCMac.cpp10
-rw-r--r--lib/CodeGen/CGRTTI.cpp2
-rw-r--r--lib/CodeGen/CodeGenModule.cpp75
-rw-r--r--lib/CodeGen/CodeGenModule.h5
-rw-r--r--lib/Frontend/CompilerInvocation.cpp12
-rw-r--r--lib/Serialization/ASTReader.cpp2
-rw-r--r--test/CodeGenCXX/member-pointer-type-convert.cpp1
-rw-r--r--test/CodeGenCXX/pointers-to-data-members.cpp9
-rw-r--r--test/CodeGenCXX/visibility.cpp33
-rw-r--r--test/Index/index-templates.cpp2
17 files changed, 555 insertions, 312 deletions
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h
index 7c7ffca994..46cc973a86 100644
--- a/include/clang/AST/Decl.h
+++ b/include/clang/AST/Decl.h
@@ -197,7 +197,13 @@ public:
bool isCXXInstanceMember() const;
/// \brief Determine what kind of linkage this entity has.
- Linkage getLinkage() const;
+ Linkage getLinkage() const { return getLinkageAndVisibility().first; }
+
+ /// \brief Determines the visibility of this entity.
+ Visibility getVisibility() const { return getLinkageAndVisibility().second; }
+
+ /// \brief Determines the linkage and visibility of this entity.
+ std::pair<Linkage,Visibility> getLinkageAndVisibility() const;
/// \brief Looks through UsingDecls and ObjCCompatibleAliasDecls for
/// the underlying named decl.
diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h
index dbf4a38477..9540389aaf 100644
--- a/include/clang/AST/Type.h
+++ b/include/clang/AST/Type.h
@@ -18,6 +18,7 @@
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/Linkage.h"
#include "clang/Basic/PartialDiagnostic.h"
+#include "clang/Basic/Visibility.h"
#include "clang/AST/NestedNameSpecifier.h"
#include "clang/AST/TemplateName.h"
#include "llvm/Support/Casting.h"
@@ -800,9 +801,10 @@ private:
/// \brief Whether this type is a variably-modified type (C99 6.7.5).
unsigned VariablyModified : 1;
- /// \brief Whether the linkage of this type along with the presence of any
- /// local or unnamed types is already known.
- mutable unsigned LinkageKnown : 1;
+ /// \brief Nonzero if the cache (i.e. the bitfields here starting
+ /// with 'Cache') is valid. If so, then this is a
+ /// LangOptions::VisibilityMode+1.
+ mutable unsigned CacheValidAndVisibility : 2;
/// \brief Linkage of this type.
mutable unsigned CachedLinkage : 2;
@@ -813,7 +815,21 @@ private:
/// \brief FromAST - Whether this type comes from an AST file.
mutable unsigned FromAST : 1;
- unsigned SpareBit : 1;
+ bool isCacheValid() const {
+ return (CacheValidAndVisibility != 0);
+ }
+ Visibility getVisibility() const {
+ assert(isCacheValid() && "getting linkage from invalid cache");
+ return static_cast<Visibility>(CacheValidAndVisibility-1);
+ }
+ Linkage getLinkage() const {
+ assert(isCacheValid() && "getting linkage from invalid cache");
+ return static_cast<Linkage>(CachedLinkage);
+ }
+ bool hasLocalOrUnnamedType() const {
+ assert(isCacheValid() && "getting linkage from invalid cache");
+ return CachedLocalOrUnnamed;
+ }
};
enum { NumTypeBits = 16 };
@@ -938,10 +954,35 @@ private:
TypeBits.FromAST = V;
}
+ void ensureCachedProperties() const;
+
protected:
- /// \brief Compute the linkage of this type along with the presence of
- /// any local or unnamed types.
- virtual std::pair<Linkage, bool> getLinkageUnnamedLocalImpl() const;
+ /// \brief Compute the cached properties of this type.
+ class CachedProperties {
+ char linkage;
+ char visibility;
+ bool local;
+
+ public:
+ CachedProperties(Linkage linkage, Visibility visibility, bool local)
+ : linkage(linkage), visibility(visibility), local(local) {}
+
+ Linkage getLinkage() const { return (Linkage) linkage; }
+ Visibility getVisibility() const { return (Visibility) visibility; }
+ bool hasLocalOrUnnamedType() const { return local; }
+
+ friend CachedProperties merge(CachedProperties L, CachedProperties R) {
+ return CachedProperties(minLinkage(L.getLinkage(), R.getLinkage()),
+ minVisibility(L.getVisibility(), R.getVisibility()),
+ L.hasLocalOrUnnamedType() | R.hasLocalOrUnnamedType());
+ }
+ };
+
+ virtual CachedProperties getCachedProperties() const;
+ static CachedProperties getCachedProperties(QualType T) {
+ return getCachedProperties(T.getTypePtr());
+ }
+ static CachedProperties getCachedProperties(const Type *T);
// silence VC++ warning C4355: 'this' : used in base member initializer list
Type *this_() { return this; }
@@ -950,7 +991,7 @@ protected:
TypeBits.TC = tc;
TypeBits.Dependent = Dependent;
TypeBits.VariablyModified = VariablyModified;
- TypeBits.LinkageKnown = false;
+ TypeBits.CacheValidAndVisibility = 0;
TypeBits.CachedLocalOrUnnamed = false;
TypeBits.CachedLinkage = NoLinkage;
TypeBits.FromAST = false;
@@ -1191,6 +1232,12 @@ public:
/// \brief Determine the linkage of this type.
Linkage getLinkage() const;
+
+ /// \brief Determine the visibility of this type.
+ Visibility getVisibility() const;
+
+ /// \brief Determine the linkage and visibility of this type.
+ std::pair<Linkage,Visibility> getLinkageAndVisibility() const;
/// \brief Note that the linkage is no longer known.
void ClearLinkageCache();
@@ -1278,7 +1325,7 @@ public:
};
protected:
- virtual std::pair<Linkage, bool> getLinkageUnnamedLocalImpl() const;
+ virtual CachedProperties getCachedProperties() const;
public:
BuiltinType(Kind K)
@@ -1334,7 +1381,7 @@ class ComplexType : public Type, public llvm::FoldingSetNode {
friend class ASTContext; // ASTContext creates these.
protected:
- virtual std::pair<Linkage, bool> getLinkageUnnamedLocalImpl() const;
+ virtual CachedProperties getCachedProperties() const;
public:
QualType getElementType() const { return ElementType; }
@@ -1366,7 +1413,7 @@ class PointerType : public Type, public llvm::FoldingSetNode {
friend class ASTContext; // ASTContext creates these.
protected:
- virtual std::pair<Linkage, bool> getLinkageUnnamedLocalImpl() const;
+ virtual CachedProperties getCachedProperties() const;
public:
@@ -1400,7 +1447,7 @@ class BlockPointerType : public Type, public llvm::FoldingSetNode {
friend class ASTContext; // ASTContext creates these.
protected:
- virtual std::pair<Linkage, bool> getLinkageUnnamedLocalImpl() const;
+ virtual CachedProperties getCachedProperties() const;
public:
@@ -1437,7 +1484,7 @@ protected:
ReferenceTypeBits.InnerRef = Referencee->isReferenceType();
}
- virtual std::pair<Linkage, bool> getLinkageUnnamedLocalImpl() const;
+ virtual CachedProperties getCachedProperties() const;
public:
bool isSpelledAsLValue() const { return ReferenceTypeBits.SpelledAsLValue; }
@@ -1521,7 +1568,7 @@ class MemberPointerType : public Type, public llvm::FoldingSetNode {
friend class ASTContext; // ASTContext creates these.
protected:
- virtual std::pair<Linkage, bool> getLinkageUnnamedLocalImpl() const;
+ virtual CachedProperties getCachedProperties() const;
public:
QualType getPointeeType() const { return PointeeType; }
@@ -1590,7 +1637,7 @@ protected:
friend class ASTContext; // ASTContext creates these.
- virtual std::pair<Linkage, bool> getLinkageUnnamedLocalImpl() const;
+ virtual CachedProperties getCachedProperties() const;
public:
QualType getElementType() const { return ElementType; }
@@ -1893,7 +1940,7 @@ protected:
}
friend class ASTContext; // ASTContext creates these.
- virtual std::pair<Linkage, bool> getLinkageUnnamedLocalImpl() const;
+ virtual CachedProperties getCachedProperties() const;
public:
@@ -2123,7 +2170,7 @@ class FunctionNoProtoType : public FunctionType, public llvm::FoldingSetNode {
friend class ASTContext; // ASTContext creates these.
protected:
- virtual std::pair<Linkage, bool> getLinkageUnnamedLocalImpl() const;
+ virtual CachedProperties getCachedProperties() const;
public:
// No additional state past what FunctionType provides.
@@ -2179,7 +2226,7 @@ class FunctionProtoType : public FunctionType, public llvm::FoldingSetNode {
friend class ASTContext; // ASTContext creates these.
protected:
- virtual std::pair<Linkage, bool> getLinkageUnnamedLocalImpl() const;
+ virtual CachedProperties getCachedProperties() const;
public:
unsigned getNumArgs() const { return NumArgs; }
@@ -2421,7 +2468,7 @@ class TagType : public Type {
protected:
TagType(TypeClass TC, const TagDecl *D, QualType can);
- virtual std::pair<Linkage, bool> getLinkageUnnamedLocalImpl() const;
+ virtual CachedProperties getCachedProperties() const;
public:
TagDecl *getDecl() const;
@@ -3084,7 +3131,7 @@ protected:
}
protected:
- std::pair<Linkage, bool> getLinkageUnnamedLocalImpl() const; // key function
+ CachedProperties getCachedProperties() const; // key function
public:
/// getBaseType - Gets the base type of this object type. This is
@@ -3192,6 +3239,10 @@ class ObjCInterfaceType : public ObjCObjectType {
: ObjCObjectType(Nonce_ObjCInterface),
Decl(const_cast<ObjCInterfaceDecl*>(D)) {}
friend class ASTContext; // ASTContext creates these.
+
+protected:
+ virtual CachedProperties getCachedProperties() const;
+
public:
/// getDecl - Get the declaration of this interface.
ObjCInterfaceDecl *getDecl() const { return Decl; }
@@ -3242,7 +3293,7 @@ class ObjCObjectPointerType : public Type, public llvm::FoldingSetNode {
friend class ASTContext; // ASTContext creates these.
protected:
- virtual std::pair<Linkage, bool> getLinkageUnnamedLocalImpl() const;
+ virtual CachedProperties getCachedProperties() const;
public:
/// getPointeeType - Gets the type pointed to by this ObjC pointer.
diff --git a/include/clang/Basic/LangOptions.h b/include/clang/Basic/LangOptions.h
index dd1dc20c09..fe69067a6d 100644
--- a/include/clang/Basic/LangOptions.h
+++ b/include/clang/Basic/LangOptions.h
@@ -15,6 +15,7 @@
#define LLVM_CLANG_LANGOPTIONS_H
#include <string>
+#include "clang/Basic/Visibility.h"
namespace clang {
@@ -131,11 +132,6 @@ public:
enum GCMode { NonGC, GCOnly, HybridGC };
enum StackProtectorMode { SSPOff, SSPOn, SSPReq };
- enum VisibilityMode {
- Default,
- Protected,
- Hidden
- };
enum SignedOverflowBehaviorTy {
SOB_Undefined, // Default C standard behavior.
@@ -161,7 +157,7 @@ public:
HeinousExtensions = 0;
AltiVec = OpenCL = StackProtector = 0;
- SymbolVisibility = (unsigned) Default;
+ SymbolVisibility = (unsigned) DefaultVisibility;
ThreadsafeStatics = 1;
POSIXThreads = 0;
@@ -208,10 +204,10 @@ public:
StackProtector = static_cast<unsigned>(m);
}
- VisibilityMode getVisibilityMode() const {
- return (VisibilityMode) SymbolVisibility;
+ Visibility getVisibilityMode() const {
+ return (Visibility) SymbolVisibility;
}
- void setVisibilityMode(VisibilityMode v) { SymbolVisibility = (unsigned) v; }
+ void setVisibilityMode(Visibility v) { SymbolVisibility = (unsigned) v; }
SignedOverflowBehaviorTy getSignedOverflowBehavior() const {
return (SignedOverflowBehaviorTy)SignedOverflowBehavior;
diff --git a/include/clang/Basic/Visibility.h b/include/clang/Basic/Visibility.h
new file mode 100644
index 0000000000..90e288a224
--- /dev/null
+++ b/include/clang/Basic/Visibility.h
@@ -0,0 +1,48 @@
+//===--- Visibility.h - Visibility enumeration and utilities ----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the Visibility enumeration and various utility
+// functions.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_BASIC_VISIBILITY_H
+#define LLVM_CLANG_BASIC_VISIBILITY_H
+
+namespace clang {
+
+/// \link Describes the different kinds of visibility that a
+/// declaration may have. Visibility determines how a declaration
+/// interacts with the dynamic linker. It may also affect whether the
+/// symbol can be found by runtime symbol lookup APIs.
+///
+/// Visibility is not described in any language standard and
+/// (nonetheless) sometimes has odd behavior. Not all platforms
+/// support all visibility kinds.
+enum Visibility {
+ /// Objects with "hidden" visibility are not seen by the dynamic
+ /// linker.
+ HiddenVisibility,
+
+ /// Objects with "protected" visibility are seen by the dynamic
+ /// linker but always dynamically resolve to an object within this
+ /// shared object.
+ ProtectedVisibility,
+
+ /// Objects with "default" visibility are seen by the dynamic linker
+ /// and act like normal objects.
+ DefaultVisibility
+};
+
+inline Visibility minVisibility(Visibility L, Visibility R) {
+ return L < R ? L : R;
+}
+
+}
+
+#endif // LLVM_CLANG_BASIC_VISIBILITY_H
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index 5a1edbd0e6..fc5b57f148 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -32,35 +32,53 @@ using namespace clang;
// NamedDecl Implementation
//===----------------------------------------------------------------------===//
+static Visibility GetVisibilityFromAttr(const VisibilityAttr *A) {
+ switch (A->getVisibility()) {
+ case VisibilityAttr::Default:
+ return DefaultVisibility;
+ case VisibilityAttr::Hidden:
+ return HiddenVisibility;
+ case VisibilityAttr::Protected:
+ return ProtectedVisibility;
+ }
+ return DefaultVisibility;
+}
+
+typedef std::pair<Linkage,Visibility> LVPair;
+static LVPair merge(LVPair L, LVPair R) {
+ return LVPair(minLinkage(L.first, R.first),
+ minVisibility(L.second, R.second));
+}
+
/// \brief Get the most restrictive linkage for the types in the given
/// template parameter list.
-static Linkage
-getLinkageForTemplateParameterList(const TemplateParameterList *Params) {
- Linkage L = ExternalLinkage;
+static LVPair
+getLVForTemplateParameterList(const TemplateParameterList *Params) {
+ LVPair LV(ExternalLinkage, DefaultVisibility);
for (TemplateParameterList::const_iterator P = Params->begin(),
PEnd = Params->end();
P != PEnd; ++P) {
if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*P))
if (!NTTP->getType()->isDependentType()) {
- L = minLinkage(L, NTTP->getType()->getLinkage());
+ LV = merge(LV, NTTP->getType()->getLinkageAndVisibility());
continue;
}
if (TemplateTemplateParmDecl *TTP
= dyn_cast<TemplateTemplateParmDecl>(*P)) {
- L = minLinkage(L,
- getLinkageForTemplateParameterList(TTP->getTemplateParameters()));
+ LV =
+ merge(LV, getLVForTemplateParameterList(TTP->getTemplateParameters()));
}
}
- return L;
+ return LV;
}
/// \brief Get the most restrictive linkage for the types and
/// declarations in the given template argument list.
-static Linkage getLinkageForTemplateArgumentList(const TemplateArgument *Args,
- unsigned NumArgs) {
- Linkage L = ExternalLinkage;
+static LVPair getLVForTemplateArgumentList(const TemplateArgument *Args,
+ unsigned NumArgs) {
+ LVPair LV(ExternalLinkage, DefaultVisibility);
for (unsigned I = 0; I != NumArgs; ++I) {
switch (Args[I].getKind()) {
@@ -70,40 +88,41 @@ static Linkage getLinkageForTemplateArgumentList(const TemplateArgument *Args,
break;
case TemplateArgument::Type:
- L = minLinkage(L, Args[I].getAsType()->getLinkage());
+ LV = merge(LV, Args[I].getAsType()->getLinkageAndVisibility());
break;
case TemplateArgument::Declaration:
- if (NamedDecl *ND = dyn_cast<NamedDecl>(Args[I].getAsDecl()))
- L = minLinkage(L, ND->getLinkage());
- if (ValueDecl *VD = dyn_cast<ValueDecl>(Args[I].getAsDecl()))
- L = minLinkage(L, VD->getType()->getLinkage());
+ // The decl can validly be null as the representation of nullptr
+ // arguments, valid only in C++0x.
+ if (Decl *D = Args[I].getAsDecl()) {
+ if (NamedDecl *ND = dyn_cast<NamedDecl>(D))
+ LV = merge(LV, ND->getLinkageAndVisibility());
+ if (ValueDecl *VD = dyn_cast<ValueDecl>(D))
+ LV = merge(LV, VD->getType()->getLinkageAndVisibility());
+ }
break;
case TemplateArgument::Template:
- if (TemplateDecl *Template
- = Args[I].getAsTemplate().getAsTemplateDecl())
- L = minLinkage(L, Template->getLinkage());
+ if (TemplateDecl *Template = Args[I].getAsTemplate().getAsTemplateDecl())
+ LV = merge(LV, Template->getLinkageAndVisibility());
break;
case TemplateArgument::Pack:
- L = minLinkage(L,
- getLinkageForTemplateArgumentList(Args[I].pack_begin(),
- Args[I].pack_size()));
+ LV = merge(LV, getLVForTemplateArgumentList(Args[I].pack_begin(),
+ Args[I].pack_size()));
break;
}
}
- return L;
+ return LV;
}
-static Linkage
-getLinkageForTemplateArgumentList(const TemplateArgumentList &TArgs) {
- return getLinkageForTemplateArgumentList(TArgs.getFlatArgumentList(),
- TArgs.flat_size());
+static LVPair getLVForTemplateArgumentList(const TemplateArgumentList &TArgs) {
+ return getLVForTemplateArgumentList(TArgs.getFlatArgumentList(),
+ TArgs.flat_size());
}
-static Linkage getLinkageForNamespaceScopeDecl(const NamedDecl *D) {
+static LVPair getLVForNamespaceScopeDecl(const NamedDecl *D) {
assert(D->getDeclContext()->getRedeclContext()->isFileContext() &&
"Not a name having namespace scope");
ASTContext &Context = D->getASTContext();
@@ -117,7 +136,7 @@ static Linkage getLinkageForNamespaceScopeDecl(const NamedDecl *D) {
if (const VarDecl *Var = dyn_cast<VarDecl>(D)) {
// Explicitly declared static.
if (Var->getStorageClass() == SC_Static)
- return InternalLinkage;
+ return LVPair(InternalLinkage, DefaultVisibility);
// - an object or reference that is explicitly declared const
// and neither explicitly declared extern nor previously
@@ -135,7 +154,7 @@ static Linkage getLinkageForNamespaceScopeDecl(const NamedDecl *D) {
FoundExtern = true;
if (!FoundExtern)
- return InternalLinkage;
+ return LVPair(InternalLinkage, DefaultVisibility);
}
} else if (isa<FunctionDecl>(D) || isa<FunctionTemplateDecl>(D)) {
// C++ [temp]p4:
@@ -150,23 +169,63 @@ static Linkage getLinkageForNamespaceScopeDecl(const NamedDecl *D) {
// Explicitly declared static.
if (Function->getStorageClass() == SC_Static)
- return InternalLinkage;
+ return LVPair(InternalLinkage, DefaultVisibility);
} else if (const FieldDecl *Field = dyn_cast<FieldDecl>(D)) {
// - a data member of an anonymous union.
if (cast<RecordDecl>(Field->getDeclContext())->isAnonymousStructOrUnion())
- return InternalLinkage;
+ return LVPair(InternalLinkage, DefaultVisibility);
}
+ if (D->isInAnonymousNamespace())
+ return LVPair(UniqueExternalLinkage, DefaultVisibility);
+
+ // Set up the defaults.
+
+ // C99 6.2.2p5:
+ // If the declaration of an identifier for an object has file
+ // scope and no storage-class specifier, its linkage is
+ // external.
+ LVPair LV(ExternalLinkage, DefaultVisibility);
+
+ // We ignore -fvisibility on non-definitions and explicit
+ // instantiation declarations.
+ bool ConsiderDashFVisibility = true;
+
// C++ [basic.link]p4:
-
+
// A name having namespace scope has external linkage if it is the
// name of
//
// - an object or reference, unless it has internal linkage; or
if (const VarDecl *Var = dyn_cast<VarDecl>(D)) {
+ // Modify the variable's LV by the LV of its type unless this is
+ // C or extern "C". This follows from [basic.link]p9:
+ // A type without linkage shall not be used as the type of a
+ // variable or function with external linkage unless
+ // - the entity has C language linkage, or
+ // - the entity is declared within an unnamed namespace, or
+ // - the entity is not used or is defined in the same
+ // translation unit.
+ // and [basic.link]p10:
+ // ...the types specified by all declarations referring to a
+ // given variable or function shall be identical...
+ // C does not have an equivalent rule.
+ //
+ // Note that we don't want to make the variable non-external
+ // because of this, but unique-external linkage suits us.
+ if (Context.getLangOptions().CPlusPlus && !Var->isExternC()) {
+ LVPair TypeLV = Var->getType()->getLinkageAndVisibility();
+ if (TypeLV.first != ExternalLinkage)
+ return LVPair(UniqueExternalLinkage, DefaultVisibility);
+ LV.second = minVisibility(LV.second, TypeLV.second);
+ }
+
if (!Context.getLangOptions().CPlusPlus &&
(Var->getStorageClass() == SC_Extern ||
Var->getStorageClass() == SC_PrivateExtern)) {
+ if (Var->getStorageClass() == SC_PrivateExtern)
+ LV.second = HiddenVisibility;
+
// C99 6.2.2p4:
// For an identifier declared with the storage-class specifier
// extern in a scope in which a prior declaration of that
@@ -177,23 +236,23 @@ static Linkage getLinkageForNamespaceScopeDecl(const NamedDecl *D) {
// is visible, or if the prior declaration specifies no
// linkage, then the identifier has external linkage.
if (const VarDecl *PrevVar = Var->getPreviousDeclaration()) {
- if (Linkage L = PrevVar->getLinkage())
- return L;
+ LVPair PrevLV = PrevVar->getLinkageAndVisibility();
+ if (PrevLV.first) LV.first = PrevLV.first;
+ LV.second = minVisibility(LV.second, PrevLV.second);
}
}
- // C99 6.2.2p5:
- // If the declaration of an identifier for an object has file
- // scope and no storage-class specifier, its linkage is
- // external.
- if (Var->isInAnonymousNamespace())
- return UniqueExternalLinkage;
-
- return ExternalLinkage;
- }
-
// - a function, unless it has internal linkage; or
- if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) {
+ } else if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) {
+ // Modify the function's LV by the LV of its type unless this is
+ // C or extern "C". See the comment above about variables.
+ if (Context.getLangOptions().CPlusPlus && !Function->isExternC()) {
+ LVPair TypeLV = Function->getType()->getLinkageAndVisibility();
+ if (TypeLV.first != ExternalLinkage)
+ return LVPair(UniqueExternalLinkage, DefaultVisibility);
+ LV.second = minVisibility(LV.second, TypeLV.second);
+ }
+
// C99 6.2.2p5:
// If the declaration of an identifier for a function has no
// storage-class specifier, its linkage is determined exactly
@@ -213,24 +272,25 @@ static Linkage getLinkageForNamespaceScopeDecl(const NamedDecl *D) {
// is visible, or if the prior declaration specifies no
// linkage, then the identifier has external linkage.
if (const FunctionDecl *PrevFunc = Function->getPreviousDeclaration()) {
- if (Linkage L = PrevFunc->getLinkage())
- return L;
+ LVPair PrevLV = PrevFunc->getLinkageAndVisibility();
+ if (PrevLV.first) LV.first = PrevLV.first;
+ LV.second = minVisibility(LV.second, PrevLV.second);
}
}
- if (Function->isInAnonymousNamespace())
- return UniqueExternalLinkage;
-
if (FunctionTemplateSpecializationInfo *SpecInfo
= Function->getTemplateSpecializationInfo()) {
- Linkage L = SpecInfo->getTemplate()->getLinkage();
+ LV = merge(LV, SpecInfo->getTemplate()->getLinkageAndVisibility());
const TemplateArgumentList &TemplateArgs = *SpecInfo->TemplateArguments;
- L = minLinkage(L, getLinkageForTemplateArgumentList(TemplateArgs));
- return L;
+ LV = merge(LV, getLVForTemplateArgumentList(TemplateArgs));
+
+ if (SpecInfo->getTemplateSpecializationKind()
+ == TSK_ExplicitInstantiationDeclaration)
+ ConsiderDashFVisibility = false;
}
- return ExternalLinkage;
- }
+ if (ConsiderDashFVisibility)
+ ConsiderDashFVisibility = Function->hasBody();
// - a named class (Clause 9), or an unnamed class defined in a
// typedef declaration in which the class has the typedef name
@@ -238,116 +298,180 @@ static Linkage getLinkageForNamespaceScopeDecl(const NamedDecl *D) {
// - a named enumeration (7.2), or an unnamed enumeration
// defined in a typedef declaration in which the enumeration
// has the typedef name for linkage purposes (7.1.3); or
- if (const TagDecl *Tag = dyn_cast<TagDecl>(D))
- if (Tag->getDeclName() || Tag->getTypedefForAnonDecl()) {
- if (Tag->isInAnonymousNamespace())
- return UniqueExternalLinkage;
-
- // If this is a class template specialization, consider the
- // linkage of the template and template arguments.
- if (const ClassTemplateSpecializationDecl *Spec
- = dyn_cast<ClassTemplateSpecializationDecl>(Tag)) {
- const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs();
- Linkage L = getLinkageForTemplateArgumentList(TemplateArgs);
- return minLinkage(L, Spec->getSpecializedTemplate()->getLinkage());
- }
+ } else if (const TagDecl *Tag = dyn_cast<TagDecl>(D)) {
+ // Unnamed tags have no linkage.
+ if (!Tag->getDeclName() && !Tag->getTypedefForAnonDecl())
+ return LVPair(NoLinkage, DefaultVisibility);
- return ExternalLinkage;
+ // If this is a class template specialization, consider the
+ // linkage of the template and template arguments.
+ if (const ClassTemplateSpecializationDecl *Spec
+ = dyn_cast<ClassTemplateSpecializationDecl>(Tag)) {
+ // From the template. Note below the restrictions on how we
+ // compute template visibility.
+ LV = merge(LV, Spec->getSpecializedTemplate()->getLinkageAndVisibility());
+
+ // The arguments at which the template was instantiated.
+ const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs();
+ LV = merge(LV, getLVForTemplateArgumentList(TemplateArgs));
+
+ if (Spec->getTemplateSpecializationKind()
+ == TSK_ExplicitInstantiationDeclaration)
+ ConsiderDashFVisibility = false;
}
+ if (ConsiderDashFVisibility)
+ ConsiderDashFVisibility = Tag->isDefinition();
+
// - an enumerator belonging to an enumeration with external linkage;
- if (isa<EnumConstantDecl>(D)) {
- Linkage L = cast<NamedDecl>(D->getDeclContext())->getLinkage();
- if (isExternalLinkage(L))
- return L;
- }
+ } else if (isa<EnumConstantDecl>(D)) {
+ LVPair EnumLV =
+ cast<NamedDecl>(D->getDeclContext())->getLinkageAndVisibility();
+ if (!isExternalLinkage(EnumLV.first))
+ return LVPair(NoLinkage, DefaultVisibility);
+ LV = merge(LV, EnumLV);
// - a template, unless it is a function template that has
// internal linkage (Clause 14);
- if (const TemplateDecl *Template = dyn_cast<TemplateDecl>(D)) {
- if (D->isInAnonymousNamespace())
- return UniqueExternalLinkage;
+ } else if (const TemplateDecl *Template = dyn_cast<TemplateDecl>(D)) {
+ LV = merge(LV, getLVForTemplateParameterList(
+ Template->getTemplateParameters()));
- return getLinkageForTemplateParameterList(
- Template->getTemplateParameters());
- }
+ // We do not want to consider attributes or global settings when
+ // computing template visibility.
+ return LV;
// - a namespace (7.3), unless it is declared within an unnamed
// namespace.
- if (isa<NamespaceDecl>(D) && !D->isInAnonymousNamespace())
- return ExternalLinkage;
+ } else if (isa<NamespaceDecl>(D) && !D->isInAnonymousNamespace()) {
+ return LV;
- return NoLinkage;
+ // By extension, we assign external linkage to Objective-C
+ // interfaces.
+ } else if (isa<ObjCInterfaceDecl>(D)) {
+ // fallout
+
+ // Everything not covered here has no linkage.
+ } else {
+ return LVPair(NoLinkage, DefaultVisibility);
+ }
+
+ // If we ended up with non-external linkage, visibility should
+ // always be default.
+ if (LV.first != ExternalLinkage)
+ return LVPair(LV.first, DefaultVisibility);
+
+ // If we didn't end up with hidden visibility, consider attributes
+ // and -fvisibility.
+ if (LV.second != HiddenVisibility) {
+ Visibility StandardV;
+
+ // If we have an explicit visibility attribute, merge that in.
+ const VisibilityAttr *VA = D->getAttr<VisibilityAttr>();
+ if (VA)
+ StandardV = GetVisibilityFromAttr(VA);
+ else if (ConsiderDashFVisibility)
+ StandardV = Context.getLangOptions().getVisibilityMode();
+ else
+ StandardV = DefaultVisibility; // no-op
+
+ LV.second = minVisibility(LV.second, StandardV);
+ }
+
+ return LV;
}
-static Linkage getLinkageForClassMember(const NamedDecl *D) {
+static LVPair getLVForClassMember(const NamedDecl *D) {
+ // Only certain class members have linkage. Note that fields don't
+ // really have linkage, but it's convenient to say they do for the
+ // purposes of calculating linkage of pointer-to-data-member
+ // template arguments.
if (!(isa<CXXMethodDecl>(D) ||
isa<VarDecl>(D) ||
+ isa<FieldDecl>(D) ||
(isa<TagDecl>(D) &&
(D->getDeclName() || cast<TagDecl>(D)->getTypedefForAnonDecl()))))
- return NoLinkage;
+ return LVPair(NoLinkage, DefaultVisibility);
// Class members only have linkage if their class has external linkage.
- Linkage L = cast<RecordDecl>(D->getDeclContext())->getLinkage();
- if (!isExternalLinkage(L)) return NoLinkage;
+ LVPair ClassLV =
+ cast<RecordDecl>(D->getDeclContext())->getLinkageAndVisibility();
+ if (!isExternalLinkage(ClassLV.first))
+ return LVPair(NoLinkage, DefaultVisibility);
// If the class already has unique-external linkage, we can't improve.
- if (L == UniqueExternalLinkage) return UniqueExternalLinkage;
+ if (ClassLV.first == UniqueExternalLinkage)
+ return LVPair(UniqueExternalLinkage, DefaultVisibility);
+
+ // Start with the class's linkage and visibility.
+ LVPair LV = ClassLV;
+
+ // If we have an explicit visibility attribute, merge that in.
+ const VisibilityAttr *VA = D->getAttr<VisibilityAttr>();
+ if (VA) LV.second = minVisibility(LV.second, GetVisibilityFromAttr(VA));
+
+ // If it's a value declaration, apply the LV from its type.
+ // See the comment about namespace-scope variable decls above.
+ if (isa<ValueDecl>(D)) {
+ LVPair TypeLV = cast<ValueDecl>(D)->getType()->getLinkageAndVisibility();
+ if (TypeLV.first != ExternalLinkage)
+ LV.first = minLinkage(LV.first, UniqueExternalLinkage);
+ LV.second = minVisibility(LV.second, TypeLV.second);
+ }
- // If this is a method template specialization, use the linkage for
- // the template parameters and arguments.
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) {
- if (FunctionTemplateSpecializationInfo *SpecInfo
+ // If this is a method template specialization, use the linkage for
+ // the template parameters and arguments.
+ if (FunctionTemplateSpecializationInfo *Spec
= MD->getTemplateSpecializationInfo()) {
- Linkage ArgLinkage =
- getLinkageForTemplateArgumentList(*SpecInfo->TemplateArguments);
- Linkage ParamLinkage =
- getLinkageForTemplateParameterList(
- SpecInfo->getTemplate()->getTemplateParameters());
- return minLinkage(ArgLinkage, ParamLinkage);
+ LV = merge(LV, getLVForTemplateArgumentList(*Spec->TemplateArguments));
+ LV = merge(LV, getLVForTemplateParameterList(
+ Spec->getTemplate()->getTemplateParameters()));
}
+ // If -fvisibility-inlines-hidden was provided, then inline C++
+ // member functions get "hidden" visibility if they don't have an
+ // explicit visibility attribute.
+ if (!VA && MD->isInlined() && LV.second > HiddenVisibility &&
+ D->getASTContext().getLangOptions().InlineVisibilityHidden)
+ LV.second = HiddenVisibility;
+
// Similarly for member class template specializations.
} else if (const ClassTemplateSpecializationDecl *Spec
= dyn_cast&l