diff options
author | Rafael Espindola <rafael.espindola@gmail.com> | 2013-03-14 03:07:35 +0000 |
---|---|---|
committer | Rafael Espindola <rafael.espindola@gmail.com> | 2013-03-14 03:07:35 +0000 |
commit | 2d1b09641ecf2e754bf3fd244dc45dbf3e460c1b (patch) | |
tree | d443e248befdaaff3e66daa89d4ee4c0d87cef3e /lib/AST/Decl.cpp | |
parent | aa778f1e4f024a38cd2085f69f36ab33b98862b0 (diff) |
Avoid computing the linkage too early. Don't invalidate it.
Before this patch we would compute the linkage lazily and cache it. When the
AST was modified in ways that could change the value, we would invalidate the
cache.
That was fairly brittle, since any code could ask for the a linkage before
the correct value was available.
We should change the API to one where the linkage is computed explicitly and
trying to get it when it is not available asserts.
This patch is a first step in that direction. We still compute the linkage
lazily, but instead of invalidating a cache, we assert that the AST
modifications didn't change the result.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@176999 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/AST/Decl.cpp')
-rw-r--r-- | lib/AST/Decl.cpp | 74 |
1 files changed, 30 insertions, 44 deletions
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index da6f03a34c..4b92069762 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -858,49 +858,14 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D, return LV; } -static void clearLinkageForClass(const CXXRecordDecl *record) { - for (CXXRecordDecl::decl_iterator - i = record->decls_begin(), e = record->decls_end(); i != e; ++i) { - Decl *child = *i; - if (isa<NamedDecl>(child)) - cast<NamedDecl>(child)->ClearLinkageCache(); - } -} - void NamedDecl::anchor() { } -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. - - HasCachedLinkage = 0; - - // If we're changing the linkage of a class, we need to reset the - // linkage of child declarations, too. - if (const CXXRecordDecl *record = dyn_cast<CXXRecordDecl>(this)) - clearLinkageForClass(record); - - if (ClassTemplateDecl *temp = dyn_cast<ClassTemplateDecl>(this)) { - // Clear linkage for the template pattern. - CXXRecordDecl *record = temp->getTemplatedDecl(); - 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->ClearLinkageCache(); - } +bool NamedDecl::isLinkageValid() const { + if (!HasCachedLinkage) + return true; - // Clear cached linkage for function template decls, too. - if (FunctionTemplateDecl *temp = dyn_cast<FunctionTemplateDecl>(this)) { - temp->getTemplatedDecl()->ClearLinkageCache(); - for (FunctionTemplateDecl::spec_iterator - i = temp->spec_begin(), e = temp->spec_end(); i != e; ++i) - i->ClearLinkageCache(); - } - + return getLVForDecl(this, LVForExplicitValue).getLinkage() == + Linkage(CachedLinkage); } Linkage NamedDecl::getLinkage() const { @@ -1515,7 +1480,7 @@ VarDecl *VarDecl::CreateDeserialized(ASTContext &C, unsigned ID) { void VarDecl::setStorageClass(StorageClass SC) { assert(isLegalForVariable(SC)); if (getStorageClass() != SC) - ClearLinkageCache(); + assert(isLinkageValid()); VarDeclBits.SClass = SC; } @@ -1560,10 +1525,27 @@ static LanguageLinkage getLanguageLinkageTemplate(const T &D) { return CXXLanguageLinkage; } +template<typename T> +static bool isExternCTemplate(const T &D) { + // Since the context is ignored for class members, they can only have C++ + // language linkage or no language linkage. + const DeclContext *DC = D.getDeclContext(); + if (DC->isRecord()) { + assert(D.getASTContext().getLangOpts().CPlusPlus); + return false; + } + + return D.getLanguageLinkage() == CLanguageLinkage; +} + LanguageLinkage VarDecl::getLanguageLinkage() const { return getLanguageLinkageTemplate(*this); } +bool VarDecl::isExternC() const { + return isExternCTemplate(*this); +} + VarDecl *VarDecl::getCanonicalDecl() { return getFirstDeclaration(); } @@ -2077,6 +2059,10 @@ LanguageLinkage FunctionDecl::getLanguageLinkage() const { return getLanguageLinkageTemplate(*this); } +bool FunctionDecl::isExternC() const { + return isExternCTemplate(*this); +} + bool FunctionDecl::isGlobal() const { if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(this)) return Method->isStatic(); @@ -2129,7 +2115,7 @@ FunctionDecl *FunctionDecl::getCanonicalDecl() { void FunctionDecl::setStorageClass(StorageClass SC) { assert(isLegalForFunction(SC)); if (getStorageClass() != SC) - ClearLinkageCache(); + assert(isLinkageValid()); SClass = SC; } @@ -2867,8 +2853,8 @@ TagDecl* TagDecl::getCanonicalDecl() { void TagDecl::setTypedefNameForAnonDecl(TypedefNameDecl *TDD) { TypedefNameDeclOrQualifier = TDD; if (TypeForDecl) - const_cast<Type*>(TypeForDecl)->ClearLinkageCache(); - ClearLinkageCache(); + assert(TypeForDecl->isLinkageValid()); + assert(isLinkageValid()); } void TagDecl::startDefinition() { |