Re-implement caching for the linkage calculation of declarations.

My previous attempt at solving the compile-time problem with many
redeclarations of the same entity cached both linkage and visibility,
while this patch only tackles linkage. There are several reasons for
this difference:

  - Linkage is a language concept, and is evaluated many times during
    semantic analysis and codegen, while visibility is only a
    code-generation concept that is evaluated only once per (unique)
    declaration. Hence, we *must* optimize linkage calculations but
    don't need to optimize visibility computation.
  - Once we know the linkage of a declaration, subsequent
    redeclarations can't change that linkage. Hence, cache
    invalidation is far simpler than for visibility, where a later
    redeclaration can completely change the visibility.
  - We have 3 spare bits in Decl to store the linkage cache, so the
    cache doesn't increase the size of declarations. With the
    visibility+linkage cache, NamedDecl got larger.

llvm-svn: 121023
This commit is contained in:
Douglas Gregor 2010-12-06 18:36:25 +00:00
parent 9bc2677b8c
commit bf62d647de
5 changed files with 140 additions and 65 deletions

View File

@ -264,7 +264,7 @@ public:
}; };
/// \brief Determine what kind of linkage this entity has. /// \brief Determine what kind of linkage this entity has.
Linkage getLinkage() const { return getLinkageAndVisibility().linkage(); } Linkage getLinkage() const;
/// \brief Determines the visibility of this entity. /// \brief Determines the visibility of this entity.
Visibility getVisibility() const { return getLinkageAndVisibility().visibility(); } Visibility getVisibility() const { return getLinkageAndVisibility().visibility(); }
@ -272,6 +272,10 @@ public:
/// \brief Determines the linkage and visibility of this entity. /// \brief Determines the linkage and visibility of this entity.
LinkageInfo getLinkageAndVisibility() const; LinkageInfo getLinkageAndVisibility() const;
/// \brief Clear the linkage cache in response to a change
/// to the declaration.
void ClearLinkageCache() { HasCachedLinkage = 0; }
/// \brief Looks through UsingDecls and ObjCCompatibleAliasDecls for /// \brief Looks through UsingDecls and ObjCCompatibleAliasDecls for
/// the underlying named decl. /// the underlying named decl.
NamedDecl *getUnderlyingDecl(); NamedDecl *getUnderlyingDecl();
@ -625,6 +629,8 @@ private:
bool NRVOVariable : 1; bool NRVOVariable : 1;
friend class StmtIteratorBase; friend class StmtIteratorBase;
friend class ASTDeclReader;
protected: protected:
VarDecl(Kind DK, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, VarDecl(Kind DK, DeclContext *DC, SourceLocation L, IdentifierInfo *Id,
QualType T, TypeSourceInfo *TInfo, StorageClass SC, QualType T, TypeSourceInfo *TInfo, StorageClass SC,
@ -660,10 +666,7 @@ public:
StorageClass getStorageClassAsWritten() const { StorageClass getStorageClassAsWritten() const {
return (StorageClass) SClassAsWritten; return (StorageClass) SClassAsWritten;
} }
void setStorageClass(StorageClass SC) { void setStorageClass(StorageClass SC);
assert(isLegalForVariable(SC));
SClass = SC;
}
void setStorageClassAsWritten(StorageClass SC) { void setStorageClassAsWritten(StorageClass SC) {
assert(isLegalForVariable(SC)); assert(isLegalForVariable(SC));
SClassAsWritten = SC; SClassAsWritten = SC;
@ -1478,10 +1481,7 @@ public:
} }
StorageClass getStorageClass() const { return StorageClass(SClass); } StorageClass getStorageClass() const { return StorageClass(SClass); }
void setStorageClass(StorageClass SC) { void setStorageClass(StorageClass SC);
assert(isLegalForFunction(SC));
SClass = SC;
}
StorageClass getStorageClassAsWritten() const { StorageClass getStorageClassAsWritten() const {
return StorageClass(SClassAsWritten); return StorageClass(SClassAsWritten);
@ -2558,6 +2558,32 @@ inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
return DB; return DB;
} }
template<typename decl_type>
void Redeclarable<decl_type>::setPreviousDeclaration(decl_type *PrevDecl) {
// Note: This routine is implemented here because we need both NamedDecl
// and Redeclarable to be defined.
decl_type *First;
if (PrevDecl) {
// Point to previous. Make sure that this is actually the most recent
// redeclaration, or we can build invalid chains. If the most recent
// redeclaration is invalid, it won't be PrevDecl, but we want it anyway.
RedeclLink = PreviousDeclLink(llvm::cast<decl_type>(
PrevDecl->getMostRecentDeclaration()));
First = PrevDecl->getFirstDeclaration();
assert(First->RedeclLink.NextIsLatest() && "Expected first");
} else {
// Make this first.
First = static_cast<decl_type*>(this);
}
// 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->ClearLinkageCache();
}
} // end namespace clang } // end namespace clang
#endif #endif

View File

@ -198,7 +198,7 @@ private:
return DeclCtx.get<DeclContext*>(); return DeclCtx.get<DeclContext*>();
} }
/// Loc - The location that this decl. /// Loc - The location of this decl.
SourceLocation Loc; SourceLocation Loc;
/// DeclKind - This indicates which class this is. /// DeclKind - This indicates which class this is.
@ -231,8 +231,19 @@ protected:
unsigned ChangedAfterLoad : 1; unsigned ChangedAfterLoad : 1;
/// IdentifierNamespace - This specifies what IDNS_* namespace this lives in. /// IdentifierNamespace - This specifies what IDNS_* namespace this lives in.
unsigned IdentifierNamespace : 15; unsigned IdentifierNamespace : 12;
/// \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.
///
/// This field is only valid for NamedDecls subclasses.
mutable unsigned CachedLinkage : 2;
private: private:
void CheckAccessDeclContext() const; void CheckAccessDeclContext() const;
@ -243,7 +254,9 @@ protected:
Loc(L), DeclKind(DK), InvalidDecl(0), Loc(L), DeclKind(DK), InvalidDecl(0),
HasAttrs(false), Implicit(false), Used(false), HasAttrs(false), Implicit(false), Used(false),
Access(AS_none), PCHLevel(0), ChangedAfterLoad(false), Access(AS_none), PCHLevel(0), ChangedAfterLoad(false),
IdentifierNamespace(getIdentifierNamespaceForKind(DK)) { IdentifierNamespace(getIdentifierNamespaceForKind(DK)),
HasCachedLinkage(0)
{
if (Decl::CollectingStats()) add(DK); if (Decl::CollectingStats()) add(DK);
} }
@ -251,7 +264,9 @@ protected:
: NextDeclInContext(0), DeclKind(DK), InvalidDecl(0), : NextDeclInContext(0), DeclKind(DK), InvalidDecl(0),
HasAttrs(false), Implicit(false), Used(false), HasAttrs(false), Implicit(false), Used(false),
Access(AS_none), PCHLevel(0), ChangedAfterLoad(false), Access(AS_none), PCHLevel(0), ChangedAfterLoad(false),
IdentifierNamespace(getIdentifierNamespaceForKind(DK)) { IdentifierNamespace(getIdentifierNamespaceForKind(DK)),
HasCachedLinkage(0)
{
if (Decl::CollectingStats()) add(DK); if (Decl::CollectingStats()) add(DK);
} }

View File

@ -109,25 +109,7 @@ public:
/// \brief Set the previous declaration. If PrevDecl is NULL, set this as the /// \brief Set the previous declaration. If PrevDecl is NULL, set this as the
/// first and only declaration. /// first and only declaration.
void setPreviousDeclaration(decl_type *PrevDecl) { void setPreviousDeclaration(decl_type *PrevDecl);
decl_type *First;
if (PrevDecl) {
// Point to previous. Make sure that this is actually the most recent
// redeclaration, or we can build invalid chains. If the most recent
// redeclaration is invalid, it won't be PrevDecl, but we want it anyway.
RedeclLink = PreviousDeclLink(llvm::cast<decl_type>(
PrevDecl->getMostRecentDeclaration()));
First = PrevDecl->getFirstDeclaration();
assert(First->RedeclLink.NextIsLatest() && "Expected first");
} else {
// Make this first.
First = static_cast<decl_type*>(this);
}
// First one will point to this one as latest.
First->RedeclLink = LatestDeclLink(static_cast<decl_type*>(this));
}
/// \brief Iterates through all the redeclarations of the same decl. /// \brief Iterates through all the redeclarations of the same decl.
class redecl_iterator { class redecl_iterator {

View File

@ -85,6 +85,15 @@ struct LVFlags {
ConsiderVisibilityAttributes(true) { ConsiderVisibilityAttributes(true) {
} }
/// \brief Returns a set of flags that is only useful for computing the
/// linkage, not the visibility, of a declaration.
static LVFlags CreateOnlyDeclLinkage() {
LVFlags F;
F.ConsiderGlobalVisibility = false;
F.ConsiderVisibilityAttributes = false;
return F;
}
/// Returns a set of flags, otherwise based on these, which ignores /// Returns a set of flags, otherwise based on these, which ignores
/// off all sources of visibility except template arguments. /// off all sources of visibility except template arguments.
LVFlags onlyTemplateVisibility() const { LVFlags onlyTemplateVisibility() const {
@ -119,10 +128,14 @@ getLVForTemplateParameterList(const TemplateParameterList *Params) {
return LV; return LV;
} }
/// getLVForDecl - Get the linkage and visibility for the given declaration.
static LinkageInfo getLVForDecl(const NamedDecl *D, LVFlags F);
/// \brief Get the most restrictive linkage for the types and /// \brief Get the most restrictive linkage for the types and
/// declarations in the given template argument list. /// declarations in the given template argument list.
static LVPair getLVForTemplateArgumentList(const TemplateArgument *Args, static LVPair getLVForTemplateArgumentList(const TemplateArgument *Args,
unsigned NumArgs) { unsigned NumArgs,
LVFlags &F) {
LVPair LV(ExternalLinkage, DefaultVisibility); LVPair LV(ExternalLinkage, DefaultVisibility);
for (unsigned I = 0; I != NumArgs; ++I) { for (unsigned I = 0; I != NumArgs; ++I) {
@ -140,21 +153,24 @@ static LVPair getLVForTemplateArgumentList(const TemplateArgument *Args,
// The decl can validly be null as the representation of nullptr // The decl can validly be null as the representation of nullptr
// arguments, valid only in C++0x. // arguments, valid only in C++0x.
if (Decl *D = Args[I].getAsDecl()) { if (Decl *D = Args[I].getAsDecl()) {
if (NamedDecl *ND = dyn_cast<NamedDecl>(D)) if (NamedDecl *ND = dyn_cast<NamedDecl>(D)) {
LV = merge(LV, ND->getLinkageAndVisibility()); LinkageInfo LI = getLVForDecl(ND, F);
if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) LV = merge(LV, LVPair(LI.linkage(), LI.visibility()));
LV = merge(LV, VD->getLinkageAndVisibility()); }
} }
break; break;
case TemplateArgument::Template: case TemplateArgument::Template:
if (TemplateDecl *Template = Args[I].getAsTemplate().getAsTemplateDecl()) if (TemplateDecl *Template = Args[I].getAsTemplate().getAsTemplateDecl()){
LV = merge(LV, Template->getLinkageAndVisibility()); LinkageInfo LI = getLVForDecl(Template, F);
LV = merge(LV, LVPair(LI.linkage(), LI.visibility()));
}
break; break;
case TemplateArgument::Pack: case TemplateArgument::Pack:
LV = merge(LV, getLVForTemplateArgumentList(Args[I].pack_begin(), LV = merge(LV, getLVForTemplateArgumentList(Args[I].pack_begin(),
Args[I].pack_size())); Args[I].pack_size(),
F));
break; break;
} }
} }
@ -163,14 +179,11 @@ static LVPair getLVForTemplateArgumentList(const TemplateArgument *Args,
} }
static LVPair static LVPair
getLVForTemplateArgumentList(const TemplateArgumentList &TArgs) { getLVForTemplateArgumentList(const TemplateArgumentList &TArgs,
return getLVForTemplateArgumentList(TArgs.data(), TArgs.size()); LVFlags &F) {
return getLVForTemplateArgumentList(TArgs.data(), TArgs.size(), F);
} }
/// getLVForDecl - Get the cached linkage and visibility for the given
/// declaration.
static LinkageInfo getLVForDecl(const NamedDecl *D, LVFlags F);
static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, LVFlags F) { static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, LVFlags F) {
assert(D->getDeclContext()->getRedeclContext()->isFileContext() && assert(D->getDeclContext()->getRedeclContext()->isFileContext() &&
"Not a name having namespace scope"); "Not a name having namespace scope");
@ -296,7 +309,7 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, LVFlags F) {
// is visible, or if the prior declaration specifies no // is visible, or if the prior declaration specifies no
// linkage, then the identifier has external linkage. // linkage, then the identifier has external linkage.
if (const VarDecl *PrevVar = Var->getPreviousDeclaration()) { if (const VarDecl *PrevVar = Var->getPreviousDeclaration()) {
LinkageInfo PrevLV = PrevVar->getLinkageAndVisibility(); LinkageInfo PrevLV = getLVForDecl(PrevVar, F);
if (PrevLV.linkage()) LV.setLinkage(PrevLV.linkage()); if (PrevLV.linkage()) LV.setLinkage(PrevLV.linkage());
LV.mergeVisibility(PrevLV); LV.mergeVisibility(PrevLV);
} }
@ -331,7 +344,7 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, LVFlags F) {
// is visible, or if the prior declaration specifies no // is visible, or if the prior declaration specifies no
// linkage, then the identifier has external linkage. // linkage, then the identifier has external linkage.
if (const FunctionDecl *PrevFunc = Function->getPreviousDeclaration()) { if (const FunctionDecl *PrevFunc = Function->getPreviousDeclaration()) {
LinkageInfo PrevLV = PrevFunc->getLinkageAndVisibility(); LinkageInfo PrevLV = getLVForDecl(PrevFunc, F);
if (PrevLV.linkage()) LV.setLinkage(PrevLV.linkage()); if (PrevLV.linkage()) LV.setLinkage(PrevLV.linkage());
LV.mergeVisibility(PrevLV); LV.mergeVisibility(PrevLV);
} }
@ -342,7 +355,7 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, LVFlags F) {
LV.merge(getLVForDecl(SpecInfo->getTemplate(), LV.merge(getLVForDecl(SpecInfo->getTemplate(),
F.onlyTemplateVisibility())); F.onlyTemplateVisibility()));
const TemplateArgumentList &TemplateArgs = *SpecInfo->TemplateArguments; const TemplateArgumentList &TemplateArgs = *SpecInfo->TemplateArguments;
LV.merge(getLVForTemplateArgumentList(TemplateArgs)); LV.merge(getLVForTemplateArgumentList(TemplateArgs, F));
} }
// - a named class (Clause 9), or an unnamed class defined in a // - a named class (Clause 9), or an unnamed class defined in a
@ -366,7 +379,7 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, LVFlags F) {
// The arguments at which the template was instantiated. // The arguments at which the template was instantiated.
const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs(); const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs();
LV.merge(getLVForTemplateArgumentList(TemplateArgs)); LV.merge(getLVForTemplateArgumentList(TemplateArgs, F));
} }
// Consider -fvisibility unless the type has C linkage. // Consider -fvisibility unless the type has C linkage.
@ -377,8 +390,7 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, LVFlags F) {
// - an enumerator belonging to an enumeration with external linkage; // - an enumerator belonging to an enumeration with external linkage;
} else if (isa<EnumConstantDecl>(D)) { } else if (isa<EnumConstantDecl>(D)) {
LinkageInfo EnumLV = LinkageInfo EnumLV = getLVForDecl(cast<NamedDecl>(D->getDeclContext()), F);
cast<NamedDecl>(D->getDeclContext())->getLinkageAndVisibility();
if (!isExternalLinkage(EnumLV.linkage())) if (!isExternalLinkage(EnumLV.linkage()))
return LinkageInfo::none(); return LinkageInfo::none();
LV.merge(EnumLV); LV.merge(EnumLV);
@ -464,7 +476,7 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D, LVFlags F) {
// the template parameters and arguments. // the template parameters and arguments.
if (FunctionTemplateSpecializationInfo *Spec if (FunctionTemplateSpecializationInfo *Spec
= MD->getTemplateSpecializationInfo()) { = MD->getTemplateSpecializationInfo()) {
LV.merge(getLVForTemplateArgumentList(*Spec->TemplateArguments)); LV.merge(getLVForTemplateArgumentList(*Spec->TemplateArguments, F));
LV.merge(getLVForTemplateParameterList( LV.merge(getLVForTemplateParameterList(
Spec->getTemplate()->getTemplateParameters())); Spec->getTemplate()->getTemplateParameters()));
@ -499,7 +511,7 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D, LVFlags F) {
= dyn_cast<ClassTemplateSpecializationDecl>(RD)) { = dyn_cast<ClassTemplateSpecializationDecl>(RD)) {
// Merge template argument/parameter information for member // Merge template argument/parameter information for member
// class template specializations. // class template specializations.
LV.merge(getLVForTemplateArgumentList(Spec->getTemplateArgs())); LV.merge(getLVForTemplateArgumentList(Spec->getTemplateArgs(), F));
LV.merge(getLVForTemplateParameterList( LV.merge(getLVForTemplateParameterList(
Spec->getSpecializedTemplate()->getTemplateParameters())); Spec->getSpecializedTemplate()->getTemplateParameters()));
} }
@ -525,8 +537,27 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D, LVFlags F) {
return LV; return LV;
} }
Linkage NamedDecl::getLinkage() const {
if (HasCachedLinkage) {
#ifndef NDEBUG
assert(CachedLinkage == getLVForDecl(this,
LVFlags::CreateOnlyDeclLinkage()).linkage());
#endif
return Linkage(CachedLinkage);
}
CachedLinkage = getLVForDecl(this,
LVFlags::CreateOnlyDeclLinkage()).linkage();
HasCachedLinkage = 1;
return Linkage(CachedLinkage);
}
LinkageInfo NamedDecl::getLinkageAndVisibility() const { LinkageInfo NamedDecl::getLinkageAndVisibility() const {
return getLVForDecl(this, LVFlags()); LinkageInfo LI = getLVForDecl(this, LVFlags());
assert(!HasCachedLinkage || (CachedLinkage == LI.linkage()));
HasCachedLinkage = 1;
CachedLinkage = LI.linkage();
return LI;
} }
static LinkageInfo getLVForDecl(const NamedDecl *D, LVFlags Flags) { static LinkageInfo getLVForDecl(const NamedDecl *D, LVFlags Flags) {
@ -581,11 +612,13 @@ static LinkageInfo getLVForDecl(const NamedDecl *D, LVFlags Flags) {
return LinkageInfo::uniqueExternal(); return LinkageInfo::uniqueExternal();
LinkageInfo LV; LinkageInfo LV;
if (const VisibilityAttr *VA = GetExplicitVisibility(Function)) if (Flags.ConsiderVisibilityAttributes) {
LV.setVisibility(GetVisibilityFromAttr(VA)); if (const VisibilityAttr *VA = GetExplicitVisibility(Function))
LV.setVisibility(GetVisibilityFromAttr(VA));
}
if (const FunctionDecl *Prev = Function->getPreviousDeclaration()) { if (const FunctionDecl *Prev = Function->getPreviousDeclaration()) {
LinkageInfo PrevLV = Prev->getLinkageAndVisibility(); LinkageInfo PrevLV = getLVForDecl(Prev, Flags);
if (PrevLV.linkage()) LV.setLinkage(PrevLV.linkage()); if (PrevLV.linkage()) LV.setLinkage(PrevLV.linkage());
LV.mergeVisibility(PrevLV); LV.mergeVisibility(PrevLV);
} }
@ -602,11 +635,13 @@ static LinkageInfo getLVForDecl(const NamedDecl *D, LVFlags Flags) {
LinkageInfo LV; LinkageInfo LV;
if (Var->getStorageClass() == SC_PrivateExtern) if (Var->getStorageClass() == SC_PrivateExtern)
LV.setVisibility(HiddenVisibility); LV.setVisibility(HiddenVisibility);
else if (const VisibilityAttr *VA = GetExplicitVisibility(Var)) else if (Flags.ConsiderVisibilityAttributes) {
LV.setVisibility(GetVisibilityFromAttr(VA)); if (const VisibilityAttr *VA = GetExplicitVisibility(Var))
LV.setVisibility(GetVisibilityFromAttr(VA));
}
if (const VarDecl *Prev = Var->getPreviousDeclaration()) { if (const VarDecl *Prev = Var->getPreviousDeclaration()) {
LinkageInfo PrevLV = Prev->getLinkageAndVisibility(); LinkageInfo PrevLV = getLVForDecl(Prev, Flags);
if (PrevLV.linkage()) LV.setLinkage(PrevLV.linkage()); if (PrevLV.linkage()) LV.setLinkage(PrevLV.linkage());
LV.mergeVisibility(PrevLV); LV.mergeVisibility(PrevLV);
} }
@ -878,6 +913,14 @@ VarDecl *VarDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L,
return new (C) VarDecl(Var, DC, L, Id, T, TInfo, S, SCAsWritten); return new (C) VarDecl(Var, DC, L, Id, T, TInfo, S, SCAsWritten);
} }
void VarDecl::setStorageClass(StorageClass SC) {
assert(isLegalForVariable(SC));
if (getStorageClass() != SC)
ClearLinkageCache();
SClass = SC;
}
SourceLocation VarDecl::getInnerLocStart() const { SourceLocation VarDecl::getInnerLocStart() const {
SourceLocation Start = getTypeSpecStartLoc(); SourceLocation Start = getTypeSpecStartLoc();
if (Start.isInvalid()) if (Start.isInvalid())
@ -1277,6 +1320,14 @@ FunctionDecl *FunctionDecl::getCanonicalDecl() {
return getFirstDeclaration(); return getFirstDeclaration();
} }
void FunctionDecl::setStorageClass(StorageClass SC) {
assert(isLegalForFunction(SC));
if (getStorageClass() != SC)
ClearLinkageCache();
SClass = SC;
}
/// \brief Returns a value indicating whether this function /// \brief Returns a value indicating whether this function
/// corresponds to a builtin function. /// corresponds to a builtin function.
/// ///
@ -1787,6 +1838,7 @@ void TagDecl::setTypedefForAnonDecl(TypedefDecl *TDD) {
TypedefDeclOrQualifier = TDD; TypedefDeclOrQualifier = TDD;
if (TypeForDecl) if (TypeForDecl)
TypeForDecl->ClearLinkageCache(); TypeForDecl->ClearLinkageCache();
ClearLinkageCache();
} }
void TagDecl::startDefinition() { void TagDecl::startDefinition() {

View File

@ -384,7 +384,7 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
// FunctionDecl's body is handled last at ASTDeclReader::Visit, // FunctionDecl's body is handled last at ASTDeclReader::Visit,
// after everything else is read. // after everything else is read.
FD->setStorageClass((StorageClass)Record[Idx++]); FD->SClass = (StorageClass)Record[Idx++];
FD->setStorageClassAsWritten((StorageClass)Record[Idx++]); FD->setStorageClassAsWritten((StorageClass)Record[Idx++]);
FD->setInlineSpecified(Record[Idx++]); FD->setInlineSpecified(Record[Idx++]);
FD->setVirtualAsWritten(Record[Idx++]); FD->setVirtualAsWritten(Record[Idx++]);
@ -651,7 +651,7 @@ void ASTDeclReader::VisitIndirectFieldDecl(IndirectFieldDecl *FD) {
void ASTDeclReader::VisitVarDecl(VarDecl *VD) { void ASTDeclReader::VisitVarDecl(VarDecl *VD) {
VisitDeclaratorDecl(VD); VisitDeclaratorDecl(VD);
VisitRedeclarable(VD); VisitRedeclarable(VD);
VD->setStorageClass((StorageClass)Record[Idx++]); VD->SClass = (StorageClass)Record[Idx++];
VD->setStorageClassAsWritten((StorageClass)Record[Idx++]); VD->setStorageClassAsWritten((StorageClass)Record[Idx++]);
VD->setThreadSpecified(Record[Idx++]); VD->setThreadSpecified(Record[Idx++]);
VD->setCXXDirectInitializer(Record[Idx++]); VD->setCXXDirectInitializer(Record[Idx++]);