diff options
author | John McCall <rjmccall@apple.com> | 2010-10-22 21:05:15 +0000 |
---|---|---|
committer | John McCall <rjmccall@apple.com> | 2010-10-22 21:05:15 +0000 |
commit | 1fb0caaa7bef765b85972274e3b434af2572c141 (patch) | |
tree | 39b9f78902f8581d6749d0d0dc99fc1f2ae1d8d5 | |
parent | 07ed93f378a8868c9a7c04ca7ae685b85c55e5ea (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.h | 8 | ||||
-rw-r--r-- | include/clang/AST/Type.h | 93 | ||||
-rw-r--r-- | include/clang/Basic/LangOptions.h | 14 | ||||
-rw-r--r-- | include/clang/Basic/Visibility.h | 48 | ||||
-rw-r--r-- | lib/AST/Decl.cpp | 390 | ||||
-rw-r--r-- | lib/AST/Type.cpp | 161 | ||||
-rw-r--r-- | lib/CodeGen/CGCXX.cpp | 2 | ||||
-rw-r--r-- | lib/CodeGen/CGObjCMac.cpp | 10 | ||||
-rw-r--r-- | lib/CodeGen/CGRTTI.cpp | 2 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenModule.cpp | 75 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenModule.h | 5 | ||||
-rw-r--r-- | lib/Frontend/CompilerInvocation.cpp | 12 | ||||
-rw-r--r-- | lib/Serialization/ASTReader.cpp | 2 | ||||
-rw-r--r-- | test/CodeGenCXX/member-pointer-type-convert.cpp | 1 | ||||
-rw-r--r-- | test/CodeGenCXX/pointers-to-data-members.cpp | 9 | ||||
-rw-r--r-- | test/CodeGenCXX/visibility.cpp | 33 | ||||
-rw-r--r-- | test/Index/index-templates.cpp | 2 |
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 |