diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index 12b6c4a980703961ddfe0aaa45e6aab450012684..da12a5f5917dad54f5d26d197afdfd21b2062d4e 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -109,6 +109,7 @@ class NamedDecl : public Decl { private: NamedDecl *getUnderlyingDeclImpl(); + void verifyLinkage() const; protected: NamedDecl(Kind DK, DeclContext *DC, SourceLocation L, DeclarationName N) @@ -228,12 +229,6 @@ public: "Enum truncated!"); } - bool operator==(const LinkageInfo &Other) { - return linkage_ == Other.linkage_ && - visibility_ == Other.visibility_ && - explicit_ == Other.explicit_; - } - static LinkageInfo external() { return LinkageInfo(); } @@ -329,7 +324,7 @@ public: /// \brief Clear the linkage cache in response to a change /// to the declaration. - void ClearLVCache(); + void ClearLinkageCache(); /// \brief Looks through UsingDecls and ObjCCompatibleAliasDecls for /// the underlying named decl. @@ -3337,7 +3332,7 @@ void Redeclarable<decl_type>::setPreviousDeclaration(decl_type *PrevDecl) { // First one will point to this one as latest. First->RedeclLink = LatestDeclLink(static_cast<decl_type*>(this)); if (NamedDecl *ND = dyn_cast<NamedDecl>(static_cast<decl_type*>(this))) - ND->ClearLVCache(); + ND->ClearLinkageCache(); } // Inline function definitions. diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h index c91284d54a000a9689b1895027714b3d31bed25b..115edf6d92219571fdb8367717524accb80d7aa4 100644 --- a/include/clang/AST/DeclBase.h +++ b/include/clang/AST/DeclBase.h @@ -242,7 +242,7 @@ private: SourceLocation Loc; /// DeclKind - This indicates which class this is. - unsigned DeclKind : 6; + unsigned DeclKind : 8; /// InvalidDecl - This indicates a semantic error occurred. unsigned InvalidDecl : 1; @@ -284,16 +284,15 @@ protected: /// IdentifierNamespace - This specifies what IDNS_* namespace this lives in. unsigned IdentifierNamespace : 12; - /// These fields are only valid for NamedDecls subclasses. + /// \brief Whether the \c CachedLinkage field is active. + /// + /// This field is only valid for NamedDecls subclasses. + mutable unsigned HasCachedLinkage : 1; + + /// \brief If \c HasCachedLinkage, the linkage of this declaration. /// - /// \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 the linkage of this declaration. + /// This field is only valid for NamedDecls subclasses. mutable unsigned CachedLinkage : 2; - /// \brief true if the visibility is explicit. - mutable unsigned CachedVisibilityExplicit : 1; friend class ASTDeclWriter; friend class ASTDeclReader; @@ -310,7 +309,7 @@ protected: HasAttrs(false), Implicit(false), Used(false), Referenced(false), Access(AS_none), FromASTFile(0), Hidden(0), IdentifierNamespace(getIdentifierNamespaceForKind(DK)), - CacheValidAndVisibility(0) + HasCachedLinkage(0) { if (StatisticsEnabled) add(DK); } @@ -320,7 +319,7 @@ protected: HasAttrs(false), Implicit(false), Used(false), Referenced(false), Access(AS_none), FromASTFile(0), Hidden(0), IdentifierNamespace(getIdentifierNamespaceForKind(DK)), - CacheValidAndVisibility(0) + HasCachedLinkage(0) { if (StatisticsEnabled) add(DK); } diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index 98e2b6fb469c4c54eee2af855214289cf556ce73..2f1b48eb0f44b3cd299c60ceb0fc6343eeb7dfdc 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -1781,7 +1781,7 @@ public: std::pair<Linkage,Visibility> getLinkageAndVisibility() const; /// \brief Note that the linkage is no longer known. - void ClearLVCache(); + void ClearLinkageCache(); const char *getTypeClassName() const; diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 409219a5715633a5f223e417b4ce5b3189db729f..83e6d6bd286d195bb1a7024fe519b5e5bb73eb2b 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -958,7 +958,6 @@ ASTContext::setInstantiatedFromStaticDataMember(VarDecl *Inst, VarDecl *Tmpl, "Already noted what static data member was instantiated from"); InstantiatedFromStaticDataMember[Inst] = new (*this) MemberSpecializationInfo(Tmpl, TSK, PointOfInstantiation); - Inst->ClearLVCache(); } FunctionDecl *ASTContext::getClassScopeSpecializationPattern( diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index bf5bfaaef10b3df043523c7f86ed594b9762a930..986430595bd61e228b2f95d907658e5a2d7a9229 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -104,14 +104,8 @@ getLVForTemplateParameterList(const TemplateParameterList *Params) { return LV; } -/// Compute the linkage and visibility for the given declaration. -static LinkageInfo computeLVForDecl(const NamedDecl *D, bool OnlyTemplate); - -static LinkageInfo getLVForDecl(const NamedDecl *D, bool OnlyTemplate) { - if (!OnlyTemplate) - return D->getLinkageAndVisibility(); - return computeLVForDecl(D, OnlyTemplate); -} +/// getLVForDecl - Get the linkage and visibility for the given declaration. +static LinkageInfo getLVForDecl(const NamedDecl *D, bool OnlyTemplate); /// \brief Get the most restrictive linkage for the types and /// declarations in the given template argument list. @@ -575,18 +569,18 @@ static void clearLinkageForClass(const CXXRecordDecl *record) { i = record->decls_begin(), e = record->decls_end(); i != e; ++i) { Decl *child = *i; if (isa<NamedDecl>(child)) - cast<NamedDecl>(child)->ClearLVCache(); + cast<NamedDecl>(child)->ClearLinkageCache(); } } void NamedDecl::anchor() { } -void NamedDecl::ClearLVCache() { +void NamedDecl::ClearLinkageCache() { // Note that we can't skip clearing the linkage of children just // because the parent doesn't have cached linkage: we don't cache // when computing linkage for parent contexts. - CacheValidAndVisibility = 0; + HasCachedLinkage = 0; // If we're changing the linkage of a class, we need to reset the // linkage of child declarations, too. @@ -597,51 +591,66 @@ void NamedDecl::ClearLVCache() { dyn_cast<ClassTemplateDecl>(const_cast<NamedDecl*>(this))) { // Clear linkage for the template pattern. CXXRecordDecl *record = temp->getTemplatedDecl(); - record->CacheValidAndVisibility = 0; + record->HasCachedLinkage = 0; clearLinkageForClass(record); // We need to clear linkage for specializations, too. for (ClassTemplateDecl::spec_iterator i = temp->spec_begin(), e = temp->spec_end(); i != e; ++i) - i->ClearLVCache(); + i->ClearLinkageCache(); } // Clear cached linkage for function template decls, too. if (FunctionTemplateDecl *temp = dyn_cast<FunctionTemplateDecl>(const_cast<NamedDecl*>(this))) { - temp->getTemplatedDecl()->ClearLVCache(); + temp->getTemplatedDecl()->ClearLinkageCache(); for (FunctionTemplateDecl::spec_iterator i = temp->spec_begin(), e = temp->spec_end(); i != e; ++i) - i->ClearLVCache(); + i->ClearLinkageCache(); } } Linkage NamedDecl::getLinkage() const { - return getLinkageAndVisibility().linkage(); + if (HasCachedLinkage) { + assert(Linkage(CachedLinkage) == + getLVForDecl(this, true).linkage()); + return Linkage(CachedLinkage); + } + + CachedLinkage = getLVForDecl(this, true).linkage(); + HasCachedLinkage = 1; + +#ifndef NDEBUG + verifyLinkage(); +#endif + + return Linkage(CachedLinkage); } LinkageInfo NamedDecl::getLinkageAndVisibility() const { - if (CacheValidAndVisibility) { - Linkage L = static_cast<Linkage>(CachedLinkage); - Visibility V = static_cast<Visibility>(CacheValidAndVisibility - 1); - bool Explicit = CachedVisibilityExplicit; - LinkageInfo LV(L, V, Explicit); - assert(LV == computeLVForDecl(this, false)); - return LV; + LinkageInfo LI = getLVForDecl(this, false); + if (HasCachedLinkage) { + assert(Linkage(CachedLinkage) == LI.linkage()); + return LI; } - LinkageInfo LV = computeLVForDecl(this, false); - CachedLinkage = LV.linkage(); - CacheValidAndVisibility = LV.visibility() + 1; - CachedVisibilityExplicit = LV.visibilityExplicit(); + HasCachedLinkage = 1; + CachedLinkage = LI.linkage(); #ifndef NDEBUG + verifyLinkage(); +#endif + + return LI; +} + +void NamedDecl::verifyLinkage() const { // In C (because of gnu inline) and in c++ with microsoft extensions an // static can follow an extern, so we can have two decls with different // linkages. const LangOptions &Opts = getASTContext().getLangOpts(); if (!Opts.CPlusPlus || Opts.MicrosoftExt) - return LV; + return; // We have just computed the linkage for this decl. By induction we know // that all other computed linkages match, check that the one we just computed @@ -651,15 +660,12 @@ LinkageInfo NamedDecl::getLinkageAndVisibility() const { NamedDecl *T = cast<NamedDecl>(*I); if (T == this) continue; - if (T->CacheValidAndVisibility != 0) { + if (T->HasCachedLinkage != 0) { D = T; break; } } assert(!D || D->CachedLinkage == CachedLinkage); -#endif - - return LV; } llvm::Optional<Visibility> NamedDecl::getExplicitVisibility() const { @@ -723,7 +729,7 @@ llvm::Optional<Visibility> NamedDecl::getExplicitVisibility() const { return llvm::Optional<Visibility>(); } -static LinkageInfo computeLVForDecl(const NamedDecl *D, bool OnlyTemplate) { +static LinkageInfo getLVForDecl(const NamedDecl *D, bool OnlyTemplate) { // Objective-C: treat all Objective-C declarations as having external // linkage. switch (D->getKind()) { @@ -1192,7 +1198,7 @@ VarDecl *VarDecl::CreateDeserialized(ASTContext &C, unsigned ID) { void VarDecl::setStorageClass(StorageClass SC) { assert(isLegalForVariable(SC)); if (getStorageClass() != SC) - ClearLVCache(); + ClearLinkageCache(); VarDeclBits.SClass = SC; } @@ -1714,9 +1720,6 @@ void FunctionDecl::setBody(Stmt *B) { Body = B; if (B) EndRangeLoc = B->getLocEnd(); - for (redecl_iterator R = redecls_begin(), REnd = redecls_end(); R != REnd; - ++R) - R->ClearLVCache(); } void FunctionDecl::setPure(bool P) { @@ -1825,7 +1828,7 @@ FunctionDecl *FunctionDecl::getCanonicalDecl() { void FunctionDecl::setStorageClass(StorageClass SC) { assert(isLegalForFunction(SC)); if (getStorageClass() != SC) - ClearLVCache(); + ClearLinkageCache(); SClass = SC; } @@ -2595,8 +2598,8 @@ TagDecl* TagDecl::getCanonicalDecl() { void TagDecl::setTypedefNameForAnonDecl(TypedefNameDecl *TDD) { TypedefNameDeclOrQualifier = TDD; if (TypeForDecl) - const_cast<Type*>(TypeForDecl)->ClearLVCache(); - ClearLVCache(); + const_cast<Type*>(TypeForDecl)->ClearLinkageCache(); + ClearLinkageCache(); } void TagDecl::startDefinition() { diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index bb79b9b57bf890ffae630ab71af457cf6d48e8b8..45ec4edbc581ece2f0925bda0a819f6ea0844976 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -2190,7 +2190,7 @@ std::pair<Linkage,Visibility> Type::getLinkageAndVisibility() const { return std::make_pair(TypeBits.getLinkage(), TypeBits.getVisibility()); } -void Type::ClearLVCache() { +void Type::ClearLinkageCache() { TypeBits.CacheValidAndVisibility = 0; if (QualType(this, 0) != CanonicalType) CanonicalType->TypeBits.CacheValidAndVisibility = 0; diff --git a/lib/Sema/SemaAttr.cpp b/lib/Sema/SemaAttr.cpp index 3bfb8f22b461aefc4996fdfd272f03e585040724..b212b3fee006603a5de334725a97609ada7fa731 100644 --- a/lib/Sema/SemaAttr.cpp +++ b/lib/Sema/SemaAttr.cpp @@ -321,7 +321,6 @@ void Sema::AddPushedVisibilityAttribute(Decl *D) { = (VisibilityAttr::VisibilityType) rawType; SourceLocation loc = Stack->back().second; - ND->ClearLVCache(); D->addAttr(::new (Context) VisibilityAttr(loc, Context, type)); } diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index c3a2ad11230fe7d325c7bda489d33809ea754964..b9d141bc351aca5c04613d865c638cfe166e1b36 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -1824,18 +1824,14 @@ DeclHasAttr(const Decl *D, const Attr *A) { bool Sema::mergeDeclAttribute(NamedDecl *D, InheritableAttr *Attr) { InheritableAttr *NewAttr = NULL; - if (AvailabilityAttr *AA = dyn_cast<AvailabilityAttr>(Attr)) { + if (AvailabilityAttr *AA = dyn_cast<AvailabilityAttr>(Attr)) NewAttr = mergeAvailabilityAttr(D, AA->getRange(), AA->getPlatform(), AA->getIntroduced(), AA->getDeprecated(), AA->getObsoleted(), AA->getUnavailable(), AA->getMessage()); - if (NewAttr) - D->ClearLVCache(); - } else if (VisibilityAttr *VA = dyn_cast<VisibilityAttr>(Attr)) { + else if (VisibilityAttr *VA = dyn_cast<VisibilityAttr>(Attr)) NewAttr = mergeVisibilityAttr(D, VA->getRange(), VA->getVisibility()); - if (NewAttr) - D->ClearLVCache(); - } else if (DLLImportAttr *ImportA = dyn_cast<DLLImportAttr>(Attr)) + else if (DLLImportAttr *ImportA = dyn_cast<DLLImportAttr>(Attr)) NewAttr = mergeDLLImportAttr(D, ImportA->getRange()); else if (DLLExportAttr *ExportA = dyn_cast<DLLExportAttr>(Attr)) NewAttr = mergeDLLExportAttr(D, ExportA->getRange()); @@ -6695,7 +6691,7 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, } VDecl->setTypeSourceInfo(DeducedType); VDecl->setType(DeducedType->getType()); - VDecl->ClearLVCache(); + VDecl->ClearLinkageCache(); // In ARC, infer lifetime. if (getLangOpts().ObjCAutoRefCount && inferObjCARCLifetime(VDecl)) diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index 225ee24d0fce3e81fc503465bf7bd87b4e8ca523..9c17d6eabdaad09307197319650012ee170807b8 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -2043,7 +2043,6 @@ AvailabilityAttr *Sema::mergeAvailabilityAttr(NamedDecl *D, SourceRange Range, VersionTuple MergedDeprecated = Deprecated; VersionTuple MergedObsoleted = Obsoleted; bool FoundAny = false; - bool DroppedAny = false; if (D->hasAttrs()) { AttrVec &Attrs = D->getAttrs(); @@ -2078,7 +2077,6 @@ AvailabilityAttr *Sema::mergeAvailabilityAttr(NamedDecl *D, SourceRange Range, Diag(OldAA->getLocation(), diag::warn_mismatched_availability); Diag(Range.getBegin(), diag::note_previous_attribute); Attrs.erase(Attrs.begin() + i); - DroppedAny = true; --e; continue; } @@ -2098,7 +2096,6 @@ AvailabilityAttr *Sema::mergeAvailabilityAttr(NamedDecl *D, SourceRange Range, MergedIntroduced2, MergedDeprecated2, MergedObsoleted2)) { Attrs.erase(Attrs.begin() + i); - DroppedAny = true; --e; continue; } @@ -2110,9 +2107,6 @@ AvailabilityAttr *Sema::mergeAvailabilityAttr(NamedDecl *D, SourceRange Range, } } - if (DroppedAny) - D->ClearLVCache(); - if (FoundAny && MergedIntroduced == Introduced && MergedDeprecated == Deprecated && @@ -2159,10 +2153,8 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, Deprecated.Version, Obsoleted.Version, IsUnavailable, Str); - if (NewAttr) { + if (NewAttr) D->addAttr(NewAttr); - ND->ClearLVCache(); - } } VisibilityAttr *Sema::mergeVisibilityAttr(Decl *D, SourceRange Range, @@ -2179,8 +2171,6 @@ VisibilityAttr *Sema::mergeVisibilityAttr(Decl *D, SourceRange Range, Diag(ExistingAttr->getLocation(), diag::err_mismatched_visibility); Diag(Range.getBegin(), diag::note_previous_attribute); D->dropAttr<VisibilityAttr>(); - NamedDecl *ND = cast<NamedDecl>(D); - ND->ClearLVCache(); } return ::new (Context) VisibilityAttr(Range, Context, Vis); } @@ -2224,11 +2214,8 @@ static void handleVisibilityAttr(Sema &S, Decl *D, const AttributeList &Attr) { } VisibilityAttr *NewAttr = S.mergeVisibilityAttr(D, Attr.getRange(), type); - if (NewAttr) { + if (NewAttr) D->addAttr(NewAttr); - NamedDecl *ND = cast<NamedDecl>(D); - ND->ClearLVCache(); - } } static void handleObjCMethodFamilyAttr(Sema &S, Decl *decl, diff --git a/test/CodeGenCXX/visibility-inlines-hidden.cpp b/test/CodeGenCXX/visibility-inlines-hidden.cpp index 0681adda839f64f3f0f44b9c0b7a94cedbad7571..e5bc743e4da9de0ad217f6a1395b4e75f3d8952c 100644 --- a/test/CodeGenCXX/visibility-inlines-hidden.cpp +++ b/test/CodeGenCXX/visibility-inlines-hidden.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -triple i386-unknown-unknown -fvisibility-inlines-hidden -emit-llvm -o - %s -O2 -disable-llvm-optzns | FileCheck %s +// RUN: %clang_cc1 -triple i386-unknown-unknown -std=c++11 -fvisibility-inlines-hidden -emit-llvm -o - %s -O2 -disable-llvm-optzns | FileCheck %s // The trickery with optimization in the run line is to get IR // generation to emit available_externally function bodies, but not @@ -147,3 +147,18 @@ namespace test5 { template <int Idx_nocapture> void Op() { } } + +namespace test6 { + // just don't crash. + template <typename T> + void f(T x) { + } + struct C { + static void g() { + f([](){}); + } + }; + void g() { + C::g(); + } +} diff --git a/test/CodeGenCXX/visibility.cpp b/test/CodeGenCXX/visibility.cpp index 014503911a49853a6bc39a6fd4bb976a41c910f7..a196dda643dcc7ab99b107bde26fcf8702ce5bc8 100644 --- a/test/CodeGenCXX/visibility.cpp +++ b/test/CodeGenCXX/visibility.cpp @@ -1112,3 +1112,47 @@ namespace test60 { // CHECK-HIDDEN: define linkonce_odr hidden void @_ZN6test604testINS_1bENS_1aEEEvv } } + +namespace test61 { + template <typename T1> + struct Class1 + { + void f1() { f2(); } + inline void f2(); + }; + template<> + inline void Class1<int>::f2() + { + } + void g(Class1<int> *x) { + x->f1(); + } +} +namespace test61 { + // Just test that we don't crash. Currently we apply this attribute. Current + // gcc issues a warning about it being unused since "the type is already + // defined". We should probably do the same. + template class __attribute__ ((visibility("hidden"))) Class1<int>; +} + +namespace test62 { + template <typename T1> + struct Class1 + { + void f1() { f2(); } + inline void f2() {} + }; + template<> + inline void Class1<int>::f2() + { + } + void g(Class1<int> *x) { + x->f2(); + } +} +namespace test62 { + template class __attribute__ ((visibility("hidden"))) Class1<int>; + // Just test that we don't crash. Currently we apply this attribute. Current + // gcc issues a warning about it being unused since "the type is already + // defined". We should probably do the same. +}