[clang] D41416: [modules] [pch] Do not deserialize all lazy template specializations when looking for one. (PR #83108)
Chuanqi Xu via cfe-commits
cfe-commits at lists.llvm.org
Sat Apr 6 23:01:28 PDT 2024
https://github.com/ChuanqiXu9 updated https://github.com/llvm/llvm-project/pull/83108
>From 2a9dfdab30467bef5361cea743be0dc215011685 Mon Sep 17 00:00:00 2001
From: Vassil Vassilev <v.g.vassilev at gmail.com>
Date: Sun, 7 Jan 2018 15:16:11 +0200
Subject: [PATCH 1/3] D41416: [modules] [pch] Do not deserialize all lazy
template specializations when looking for one.
---
clang/include/clang/AST/DeclTemplate.h | 36 ++++++++-
clang/lib/AST/DeclTemplate.cpp | 96 +++++++++++++++++------
clang/lib/AST/ODRHash.cpp | 15 ++++
clang/lib/Serialization/ASTReader.cpp | 25 ++++--
clang/lib/Serialization/ASTReaderDecl.cpp | 36 ++++++---
clang/lib/Serialization/ASTWriter.cpp | 21 ++++-
clang/lib/Serialization/ASTWriterDecl.cpp | 74 ++++++++++++++---
7 files changed, 242 insertions(+), 61 deletions(-)
diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h
index e3b6a7efb1127a..4ed9b58d4ff609 100644
--- a/clang/include/clang/AST/DeclTemplate.h
+++ b/clang/include/clang/AST/DeclTemplate.h
@@ -256,6 +256,9 @@ class TemplateArgumentList final
TemplateArgumentList(const TemplateArgumentList &) = delete;
TemplateArgumentList &operator=(const TemplateArgumentList &) = delete;
+ /// Create hash for the given arguments.
+ static unsigned ComputeODRHash(ArrayRef<TemplateArgument> Args);
+
/// Create a new template argument list that copies the given set of
/// template arguments.
static TemplateArgumentList *CreateCopy(ASTContext &Context,
@@ -730,6 +733,26 @@ class RedeclarableTemplateDecl : public TemplateDecl,
}
void anchor() override;
+ struct LazySpecializationInfo {
+ uint32_t DeclID = ~0U;
+ unsigned ODRHash = ~0U;
+ bool IsPartial = false;
+ LazySpecializationInfo(uint32_t ID, unsigned Hash = ~0U,
+ bool Partial = false)
+ : DeclID(ID), ODRHash(Hash), IsPartial(Partial) { }
+ LazySpecializationInfo() { }
+ bool operator<(const LazySpecializationInfo &Other) const {
+ return DeclID < Other.DeclID;
+ }
+ bool operator==(const LazySpecializationInfo &Other) const {
+ assert((DeclID != Other.DeclID || ODRHash == Other.ODRHash) &&
+ "Hashes differ!");
+ assert((DeclID != Other.DeclID || IsPartial == Other.IsPartial) &&
+ "Both must be the same kinds!");
+ return DeclID == Other.DeclID;
+ }
+ };
+
protected:
template <typename EntryType> struct SpecEntryTraits {
using DeclType = EntryType;
@@ -770,7 +793,12 @@ class RedeclarableTemplateDecl : public TemplateDecl,
return SpecIterator<EntryType>(isEnd ? Specs.end() : Specs.begin());
}
- void loadLazySpecializationsImpl() const;
+ void loadLazySpecializationsImpl(bool OnlyPartial = false) const;
+
+ void loadLazySpecializationsImpl(llvm::ArrayRef<TemplateArgument> Args,
+ TemplateParameterList *TPL = nullptr) const;
+
+ Decl *loadLazySpecializationImpl(LazySpecializationInfo &LazySpecInfo) const;
template <class EntryType, typename ...ProfileArguments>
typename SpecEntryTraits<EntryType>::DeclType*
@@ -797,7 +825,7 @@ class RedeclarableTemplateDecl : public TemplateDecl,
///
/// The first value in the array is the number of specializations/partial
/// specializations that follow.
- uint32_t *LazySpecializations = nullptr;
+ LazySpecializationInfo *LazySpecializations = nullptr;
/// The set of "injected" template arguments used within this
/// template.
@@ -2268,7 +2296,7 @@ class ClassTemplateDecl : public RedeclarableTemplateDecl {
friend class TemplateDeclInstantiator;
/// Load any lazily-loaded specializations from the external source.
- void LoadLazySpecializations() const;
+ void LoadLazySpecializations(bool OnlyPartial = false) const;
/// Get the underlying class declarations of the template.
CXXRecordDecl *getTemplatedDecl() const {
@@ -3039,7 +3067,7 @@ class VarTemplateDecl : public RedeclarableTemplateDecl {
friend class ASTDeclWriter;
/// Load any lazily-loaded specializations from the external source.
- void LoadLazySpecializations() const;
+ void LoadLazySpecializations(bool OnlyPartial = false) const;
/// Get the underlying variable declarations of the template.
VarDecl *getTemplatedDecl() const {
diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp
index 3c217d6a6a5ae3..1babe39ee2a7e5 100644
--- a/clang/lib/AST/DeclTemplate.cpp
+++ b/clang/lib/AST/DeclTemplate.cpp
@@ -20,6 +20,8 @@
#include "clang/AST/TemplateBase.h"
#include "clang/AST/TemplateName.h"
#include "clang/AST/Type.h"
+#include "clang/AST/ODRHash.h"
+#include "clang/AST/ExprCXX.h"
#include "clang/AST/TypeLoc.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/LLVM.h"
@@ -331,16 +333,43 @@ RedeclarableTemplateDecl::CommonBase *RedeclarableTemplateDecl::getCommonPtr() c
return Common;
}
-void RedeclarableTemplateDecl::loadLazySpecializationsImpl() const {
+void RedeclarableTemplateDecl::loadLazySpecializationsImpl(
+ bool OnlyPartial/*=false*/) const {
// Grab the most recent declaration to ensure we've loaded any lazy
// redeclarations of this template.
CommonBase *CommonBasePtr = getMostRecentDecl()->getCommonPtr();
- if (CommonBasePtr->LazySpecializations) {
- ASTContext &Context = getASTContext();
- uint32_t *Specs = CommonBasePtr->LazySpecializations;
- CommonBasePtr->LazySpecializations = nullptr;
- for (uint32_t I = 0, N = *Specs++; I != N; ++I)
- (void)Context.getExternalSource()->GetExternalDecl(Specs[I]);
+ if (auto *Specs = CommonBasePtr->LazySpecializations) {
+ if (!OnlyPartial)
+ CommonBasePtr->LazySpecializations = nullptr;
+ for (uint32_t I = 0, N = Specs[0].DeclID; I != N; ++I) {
+ // Skip over already loaded specializations.
+ if (!Specs[I+1].ODRHash)
+ continue;
+ if (!OnlyPartial || Specs[I+1].IsPartial)
+ (void)loadLazySpecializationImpl(Specs[I+1]);
+ }
+ }
+}
+
+Decl *RedeclarableTemplateDecl::loadLazySpecializationImpl(
+ LazySpecializationInfo &LazySpecInfo) const {
+ uint32_t ID = LazySpecInfo.DeclID;
+ assert(ID && "Loading already loaded specialization!");
+ // Note that we loaded the specialization.
+ LazySpecInfo.DeclID = LazySpecInfo.ODRHash = LazySpecInfo.IsPartial = 0;
+ return getASTContext().getExternalSource()->GetExternalDecl(ID);
+}
+
+void
+RedeclarableTemplateDecl::loadLazySpecializationsImpl(ArrayRef<TemplateArgument>
+ Args,
+ TemplateParameterList *TPL) const {
+ CommonBase *CommonBasePtr = getMostRecentDecl()->getCommonPtr();
+ if (auto *Specs = CommonBasePtr->LazySpecializations) {
+ unsigned Hash = TemplateArgumentList::ComputeODRHash(Args);
+ for (uint32_t I = 0, N = Specs[0].DeclID; I != N; ++I)
+ if (Specs[I+1].ODRHash && Specs[I+1].ODRHash == Hash)
+ (void)loadLazySpecializationImpl(Specs[I+1]);
}
}
@@ -351,6 +380,8 @@ RedeclarableTemplateDecl::findSpecializationImpl(
ProfileArguments&&... ProfileArgs) {
using SETraits = SpecEntryTraits<EntryType>;
+ loadLazySpecializationsImpl(std::forward<ProfileArguments>(ProfileArgs)...);
+
llvm::FoldingSetNodeID ID;
EntryType::Profile(ID, std::forward<ProfileArguments>(ProfileArgs)...,
getASTContext());
@@ -366,10 +397,14 @@ void RedeclarableTemplateDecl::addSpecializationImpl(
if (InsertPos) {
#ifndef NDEBUG
+ auto Args = SETraits::getTemplateArgs(Entry);
+ // Due to hash collisions, it can happen that we load another template
+ // specialization with the same hash. This is fine, as long as the next
+ // call to findSpecializationImpl does not find a matching Decl for the
+ // template arguments.
+ loadLazySpecializationsImpl(Args);
void *CorrectInsertPos;
- assert(!findSpecializationImpl(Specializations,
- CorrectInsertPos,
- SETraits::getTemplateArgs(Entry)) &&
+ assert(!findSpecializationImpl(Specializations, CorrectInsertPos, Args) &&
InsertPos == CorrectInsertPos &&
"given incorrect InsertPos for specialization");
#endif
@@ -443,12 +478,14 @@ FunctionTemplateDecl::getSpecializations() const {
FunctionDecl *
FunctionTemplateDecl::findSpecialization(ArrayRef<TemplateArgument> Args,
void *&InsertPos) {
- return findSpecializationImpl(getSpecializations(), InsertPos, Args);
+ auto *Common = getCommonPtr();
+ return findSpecializationImpl(Common->Specializations, InsertPos, Args);
}
void FunctionTemplateDecl::addSpecialization(
FunctionTemplateSpecializationInfo *Info, void *InsertPos) {
- addSpecializationImpl<FunctionTemplateDecl>(getSpecializations(), Info,
+ auto *Common = getCommonPtr();
+ addSpecializationImpl<FunctionTemplateDecl>(Common->Specializations, Info,
InsertPos);
}
@@ -508,8 +545,9 @@ ClassTemplateDecl *ClassTemplateDecl::CreateDeserialized(ASTContext &C,
DeclarationName(), nullptr, nullptr);
}
-void ClassTemplateDecl::LoadLazySpecializations() const {
- loadLazySpecializationsImpl();
+void ClassTemplateDecl::LoadLazySpecializations(
+ bool OnlyPartial/*=false*/) const {
+ loadLazySpecializationsImpl(OnlyPartial);
}
llvm::FoldingSetVector<ClassTemplateSpecializationDecl> &
@@ -520,7 +558,7 @@ ClassTemplateDecl::getSpecializations() const {
llvm::FoldingSetVector<ClassTemplatePartialSpecializationDecl> &
ClassTemplateDecl::getPartialSpecializations() const {
- LoadLazySpecializations();
+ LoadLazySpecializations(/*PartialOnly = */ true);
return getCommonPtr()->PartialSpecializations;
}
@@ -534,12 +572,15 @@ ClassTemplateDecl::newCommon(ASTContext &C) const {
ClassTemplateSpecializationDecl *
ClassTemplateDecl::findSpecialization(ArrayRef<TemplateArgument> Args,
void *&InsertPos) {
- return findSpecializationImpl(getSpecializations(), InsertPos, Args);
+ auto *Common = getCommonPtr();
+ return findSpecializationImpl(Common->Specializations, InsertPos, Args);
}
void ClassTemplateDecl::AddSpecialization(ClassTemplateSpecializationDecl *D,
void *InsertPos) {
- addSpecializationImpl<ClassTemplateDecl>(getSpecializations(), D, InsertPos);
+ auto *Common = getCommonPtr();
+ addSpecializationImpl<ClassTemplateDecl>(Common->Specializations, D,
+ InsertPos);
}
ClassTemplatePartialSpecializationDecl *
@@ -883,6 +924,14 @@ TemplateArgumentList::CreateCopy(ASTContext &Context,
return new (Mem) TemplateArgumentList(Args);
}
+unsigned TemplateArgumentList::ComputeODRHash(ArrayRef<TemplateArgument> Args) {
+ ODRHash Hasher;
+ for (TemplateArgument TA : Args)
+ Hasher.AddTemplateArgument(TA);
+
+ return Hasher.CalculateHash();
+}
+
FunctionTemplateSpecializationInfo *FunctionTemplateSpecializationInfo::Create(
ASTContext &C, FunctionDecl *FD, FunctionTemplateDecl *Template,
TemplateSpecializationKind TSK, const TemplateArgumentList *TemplateArgs,
@@ -1225,8 +1274,9 @@ VarTemplateDecl *VarTemplateDecl::CreateDeserialized(ASTContext &C,
DeclarationName(), nullptr, nullptr);
}
-void VarTemplateDecl::LoadLazySpecializations() const {
- loadLazySpecializationsImpl();
+void VarTemplateDecl::LoadLazySpecializations(
+ bool OnlyPartial/*=false*/) const {
+ loadLazySpecializationsImpl(OnlyPartial);
}
llvm::FoldingSetVector<VarTemplateSpecializationDecl> &
@@ -1237,7 +1287,7 @@ VarTemplateDecl::getSpecializations() const {
llvm::FoldingSetVector<VarTemplatePartialSpecializationDecl> &
VarTemplateDecl::getPartialSpecializations() const {
- LoadLazySpecializations();
+ LoadLazySpecializations(/*PartialOnly = */ true);
return getCommonPtr()->PartialSpecializations;
}
@@ -1251,12 +1301,14 @@ VarTemplateDecl::newCommon(ASTContext &C) const {
VarTemplateSpecializationDecl *
VarTemplateDecl::findSpecialization(ArrayRef<TemplateArgument> Args,
void *&InsertPos) {
- return findSpecializationImpl(getSpecializations(), InsertPos, Args);
+ auto *Common = getCommonPtr();
+ return findSpecializationImpl(Common->Specializations, InsertPos, Args);
}
void VarTemplateDecl::AddSpecialization(VarTemplateSpecializationDecl *D,
void *InsertPos) {
- addSpecializationImpl<VarTemplateDecl>(getSpecializations(), D, InsertPos);
+ auto *Common = getCommonPtr();
+ addSpecializationImpl<VarTemplateDecl>(Common->Specializations, D, InsertPos);
}
VarTemplatePartialSpecializationDecl *
diff --git a/clang/lib/AST/ODRHash.cpp b/clang/lib/AST/ODRHash.cpp
index e159a1b00be552..b59da315dac105 100644
--- a/clang/lib/AST/ODRHash.cpp
+++ b/clang/lib/AST/ODRHash.cpp
@@ -812,6 +812,21 @@ void ODRHash::AddDecl(const Decl *D) {
for (const TemplateArgument &TA : List.asArray())
AddTemplateArgument(TA);
}
+
+ // If this was a specialization we should take into account its template
+ // arguments. This helps to reduce collisions coming when visiting template
+ // specialization types (eg. when processing type template arguments).
+ ArrayRef<TemplateArgument> Args;
+ if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D))
+ Args = CTSD->getTemplateArgs().asArray();
+ else if (auto *VTSD = dyn_cast<VarTemplateSpecializationDecl>(D))
+ Args = VTSD->getTemplateArgs().asArray();
+ else if (auto *FD = dyn_cast<FunctionDecl>(D))
+ if (FD->getTemplateSpecializationArgs())
+ Args = FD->getTemplateSpecializationArgs()->asArray();
+
+ for (auto &TA : Args)
+ AddTemplateArgument(TA);
}
namespace {
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index fa5bb9f2d5435a..fd2be3228c5659 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -7559,14 +7559,23 @@ void ASTReader::CompleteRedeclChain(const Decl *D) {
}
}
- if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D))
- CTSD->getSpecializedTemplate()->LoadLazySpecializations();
- if (auto *VTSD = dyn_cast<VarTemplateSpecializationDecl>(D))
- VTSD->getSpecializedTemplate()->LoadLazySpecializations();
- if (auto *FD = dyn_cast<FunctionDecl>(D)) {
- if (auto *Template = FD->getPrimaryTemplate())
- Template->LoadLazySpecializations();
- }
+ RedeclarableTemplateDecl *Template = nullptr;
+ ArrayRef<TemplateArgument> Args;
+ if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
+ Template = CTSD->getSpecializedTemplate();
+ Args = CTSD->getTemplateArgs().asArray();
+ } else if (auto *VTSD = dyn_cast<VarTemplateSpecializationDecl>(D)) {
+ Template = VTSD->getSpecializedTemplate();
+ Args = VTSD->getTemplateArgs().asArray();
+ } else if (auto *FD = dyn_cast<FunctionDecl>(D)) {
+ if (auto *Tmplt = FD->getPrimaryTemplate()) {
+ Template = Tmplt;
+ Args = FD->getTemplateSpecializationArgs()->asArray();
+ }
+ }
+
+ if (Template)
+ Template->loadLazySpecializationsImpl(Args);
}
CXXCtorInitializer **
diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp
index a22f760408c634..f4f2ff9372a26d 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -88,6 +88,8 @@ namespace clang {
const SourceLocation ThisDeclLoc;
using RecordData = ASTReader::RecordData;
+ using LazySpecializationInfo
+ = RedeclarableTemplateDecl::LazySpecializationInfo;
TypeID DeferredTypeID = 0;
unsigned AnonymousDeclNumber = 0;
@@ -134,9 +136,16 @@ namespace clang {
return Record.readString();
}
- void readDeclIDList(SmallVectorImpl<DeclID> &IDs) {
+ LazySpecializationInfo ReadLazySpecializationInfo() {
+ DeclID ID = readDeclID();
+ unsigned Hash = Record.readInt();
+ bool IsPartial = Record.readInt();
+ return LazySpecializationInfo(ID, Hash, IsPartial);
+ }
+
+ void readDeclIDList(SmallVectorImpl<LazySpecializationInfo> &IDs) {
for (unsigned I = 0, Size = Record.readInt(); I != Size; ++I)
- IDs.push_back(readDeclID());
+ IDs.push_back(ReadLazySpecializationInfo());
}
Decl *readDecl() {
@@ -267,7 +276,7 @@ namespace clang {
template <typename T> static
void AddLazySpecializations(T *D,
- SmallVectorImpl<serialization::DeclID>& IDs) {
+ SmallVectorImpl<LazySpecializationInfo>& IDs) {
if (IDs.empty())
return;
@@ -277,12 +286,11 @@ namespace clang {
auto *&LazySpecializations = D->getCommonPtr()->LazySpecializations;
if (auto &Old = LazySpecializations) {
- IDs.insert(IDs.end(), Old + 1, Old + 1 + Old[0]);
+ IDs.insert(IDs.end(), Old + 1, Old + 1 + Old[0].DeclID);
llvm::sort(IDs);
IDs.erase(std::unique(IDs.begin(), IDs.end()), IDs.end());
}
-
- auto *Result = new (C) serialization::DeclID[1 + IDs.size()];
+ auto *Result = new (C) LazySpecializationInfo[1 + IDs.size()];
*Result = IDs.size();
std::copy(IDs.begin(), IDs.end(), Result + 1);
@@ -320,7 +328,7 @@ namespace clang {
void ReadFunctionDefinition(FunctionDecl *FD);
void Visit(Decl *D);
- void UpdateDecl(Decl *D, SmallVectorImpl<serialization::DeclID> &);
+ void UpdateDecl(Decl *D, llvm::SmallVectorImpl<LazySpecializationInfo>&);
static void setNextObjCCategory(ObjCCategoryDecl *Cat,
ObjCCategoryDecl *Next) {
@@ -2454,7 +2462,7 @@ void ASTDeclReader::VisitClassTemplateDecl(ClassTemplateDecl *D) {
if (ThisDeclID == Redecl.getFirstID()) {
// This ClassTemplateDecl owns a CommonPtr; read it to keep track of all of
// the specializations.
- SmallVector<serialization::DeclID, 32> SpecIDs;
+ SmallVector<LazySpecializationInfo, 32> SpecIDs;
readDeclIDList(SpecIDs);
ASTDeclReader::AddLazySpecializations(D, SpecIDs);
}
@@ -2482,7 +2490,7 @@ void ASTDeclReader::VisitVarTemplateDecl(VarTemplateDecl *D) {
if (ThisDeclID == Redecl.getFirstID()) {
// This VarTemplateDecl owns a CommonPtr; read it to keep track of all of
// the specializations.
- SmallVector<serialization::DeclID, 32> SpecIDs;
+ SmallVector<LazySpecializationInfo, 32> SpecIDs;
readDeclIDList(SpecIDs);
ASTDeclReader::AddLazySpecializations(D, SpecIDs);
}
@@ -2584,7 +2592,7 @@ void ASTDeclReader::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
if (ThisDeclID == Redecl.getFirstID()) {
// This FunctionTemplateDecl owns a CommonPtr; read it.
- SmallVector<serialization::DeclID, 32> SpecIDs;
+ SmallVector<LazySpecializationInfo, 32> SpecIDs;
readDeclIDList(SpecIDs);
ASTDeclReader::AddLazySpecializations(D, SpecIDs);
}
@@ -4195,7 +4203,9 @@ void ASTReader::loadDeclUpdateRecords(PendingUpdateRecord &Record) {
ProcessingUpdatesRAIIObj ProcessingUpdates(*this);
DeclUpdateOffsetsMap::iterator UpdI = DeclUpdateOffsets.find(ID);
- SmallVector<serialization::DeclID, 8> PendingLazySpecializationIDs;
+ using LazySpecializationInfo
+ = RedeclarableTemplateDecl::LazySpecializationInfo;
+ llvm::SmallVector<LazySpecializationInfo, 8> PendingLazySpecializationIDs;
if (UpdI != DeclUpdateOffsets.end()) {
auto UpdateOffsets = std::move(UpdI->second);
@@ -4465,7 +4475,7 @@ static void forAllLaterRedecls(DeclT *D, Fn F) {
}
void ASTDeclReader::UpdateDecl(Decl *D,
- llvm::SmallVectorImpl<serialization::DeclID> &PendingLazySpecializationIDs) {
+ SmallVectorImpl<LazySpecializationInfo> &PendingLazySpecializationIDs) {
while (Record.getIdx() < Record.size()) {
switch ((DeclUpdateKind)Record.readInt()) {
case UPD_CXX_ADDED_IMPLICIT_MEMBER: {
@@ -4478,7 +4488,7 @@ void ASTDeclReader::UpdateDecl(Decl *D,
case UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION:
// It will be added to the template's lazy specialization set.
- PendingLazySpecializationIDs.push_back(readDeclID());
+ PendingLazySpecializationIDs.push_back(ReadLazySpecializationInfo());
break;
case UPD_CXX_ADDED_ANONYMOUS_NAMESPACE: {
diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp
index baf03f69d73065..b2d6d10ebbd516 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -5353,12 +5353,29 @@ void ASTWriter::WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord) {
switch (Kind) {
case UPD_CXX_ADDED_IMPLICIT_MEMBER:
- case UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION:
case UPD_CXX_ADDED_ANONYMOUS_NAMESPACE:
assert(Update.getDecl() && "no decl to add?");
Record.push_back(GetDeclRef(Update.getDecl()));
break;
-
+ case UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION: {
+ const Decl *Spec = Update.getDecl();
+ assert(Spec && "no decl to add?");
+ Record.push_back(GetDeclRef(Spec));
+ ArrayRef<TemplateArgument> Args;
+ if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(Spec))
+ Args = CTSD->getTemplateArgs().asArray();
+ else if (auto *VTSD = dyn_cast<VarTemplateSpecializationDecl>(Spec))
+ Args = VTSD->getTemplateArgs().asArray();
+ else if (auto *FD = dyn_cast<FunctionDecl>(Spec))
+ Args = FD->getTemplateSpecializationArgs()->asArray();
+ assert(Args.size());
+ Record.push_back(TemplateArgumentList::ComputeODRHash(Args));
+ bool IsPartialSpecialization
+ = isa<ClassTemplatePartialSpecializationDecl>(Spec) ||
+ isa<VarTemplatePartialSpecializationDecl>(Spec);
+ Record.push_back(IsPartialSpecialization);
+ break;
+ }
case UPD_CXX_ADDED_FUNCTION_DEFINITION:
case UPD_CXX_ADDED_VAR_DEFINITION:
break;
diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp
index 86f64bf2a24250..f39ec448accfd1 100644
--- a/clang/lib/Serialization/ASTWriterDecl.cpp
+++ b/clang/lib/Serialization/ASTWriterDecl.cpp
@@ -179,11 +179,11 @@ namespace clang {
Record.AddSourceLocation(typeParams->getRAngleLoc());
}
- /// Add to the record the first declaration from each module file that
- /// provides a declaration of D. The intent is to provide a sufficient
- /// set such that reloading this set will load all current redeclarations.
- void AddFirstDeclFromEachModule(const Decl *D, bool IncludeLocal) {
- llvm::MapVector<ModuleFile*, const Decl*> Firsts;
+ /// Collect the first declaration from each module file that provides a
+ /// declaration of D.
+ void CollectFirstDeclFromEachModule(const Decl *D, bool IncludeLocal,
+ llvm::MapVector<ModuleFile*, const Decl*> &Firsts) {
+
// FIXME: We can skip entries that we know are implied by others.
for (const Decl *R = D->getMostRecentDecl(); R; R = R->getPreviousDecl()) {
if (R->isFromASTFile())
@@ -191,10 +191,49 @@ namespace clang {
else if (IncludeLocal)
Firsts[nullptr] = R;
}
+ }
+
+ /// Add to the record the first declaration from each module file that
+ /// provides a declaration of D. The intent is to provide a sufficient
+ /// set such that reloading this set will load all current redeclarations.
+ void AddFirstDeclFromEachModule(const Decl *D, bool IncludeLocal) {
+ llvm::MapVector<ModuleFile*, const Decl*> Firsts;
+ CollectFirstDeclFromEachModule(D, IncludeLocal, Firsts);
+
for (const auto &F : Firsts)
Record.AddDeclRef(F.second);
}
+ /// Add to the record the first template specialization from each module
+ /// file that provides a declaration of D. We store the DeclId and an
+ /// ODRHash of the template arguments of D which should provide enough
+ /// information to load D only if the template instantiator needs it.
+ void AddFirstSpecializationDeclFromEachModule(const Decl *D,
+ bool IncludeLocal) {
+ assert(isa<ClassTemplateSpecializationDecl>(D) ||
+ isa<VarTemplateSpecializationDecl>(D) || isa<FunctionDecl>(D) &&
+ "Must not be called with other decls");
+ llvm::MapVector<ModuleFile*, const Decl*> Firsts;
+ CollectFirstDeclFromEachModule(D, IncludeLocal, Firsts);
+
+ for (const auto &F : Firsts) {
+ Record.AddDeclRef(F.second);
+ ArrayRef<TemplateArgument> Args;
+ if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D))
+ Args = CTSD->getTemplateArgs().asArray();
+ else if (auto *VTSD = dyn_cast<VarTemplateSpecializationDecl>(D))
+ Args = VTSD->getTemplateArgs().asArray();
+ else if (auto *FD = dyn_cast<FunctionDecl>(D))
+ Args = FD->getTemplateSpecializationArgs()->asArray();
+ assert(Args.size());
+ Record.push_back(TemplateArgumentList::ComputeODRHash(Args));
+ bool IsPartialSpecialization
+ = isa<ClassTemplatePartialSpecializationDecl>(D) ||
+ isa<VarTemplatePartialSpecializationDecl>(D);
+ Record.push_back(IsPartialSpecialization);
+ }
+ }
+
/// Get the specialization decl from an entry in the specialization list.
template <typename EntryType>
typename RedeclarableTemplateDecl::SpecEntryTraits<EntryType>::DeclType *
@@ -207,7 +246,8 @@ namespace clang {
decltype(T::PartialSpecializations) &getPartialSpecializations(T *Common) {
return Common->PartialSpecializations;
}
- ArrayRef<Decl> getPartialSpecializations(FunctionTemplateDecl::Common *) {
+ MutableArrayRef<FunctionTemplateSpecializationInfo>
+ getPartialSpecializations(FunctionTemplateDecl::Common *) {
return std::nullopt;
}
@@ -224,9 +264,11 @@ namespace clang {
assert(!Common->LazySpecializations);
}
- ArrayRef<DeclID> LazySpecializations;
+ using LazySpecializationInfo
+ = RedeclarableTemplateDecl::LazySpecializationInfo;
+ ArrayRef<LazySpecializationInfo> LazySpecializations;
if (auto *LS = Common->LazySpecializations)
- LazySpecializations = llvm::ArrayRef(LS + 1, LS[0]);
+ LazySpecializations = llvm::ArrayRef(LS + 1, LS[0].DeclID);
// Add a slot to the record for the number of specializations.
unsigned I = Record.size();
@@ -242,12 +284,20 @@ namespace clang {
for (auto *D : Specs) {
assert(D->isCanonicalDecl() && "non-canonical decl in set");
- AddFirstDeclFromEachModule(D, /*IncludeLocal*/true);
+ AddFirstSpecializationDeclFromEachModule(D, /*IncludeLocal*/true);
+ }
+ for (auto &SpecInfo : LazySpecializations) {
+ Record.push_back(SpecInfo.DeclID);
+ Record.push_back(SpecInfo.ODRHash);
+ Record.push_back(SpecInfo.IsPartial);
}
- Record.append(LazySpecializations.begin(), LazySpecializations.end());
- // Update the size entry we added earlier.
- Record[I] = Record.size() - I - 1;
+ // Update the size entry we added earlier. We linerized the
+ // LazySpecializationInfo members and we need to adjust the size as we
+ // will read them always together.
+ assert ((Record.size() - I - 1) % 3 == 0
+ && "Must be divisible by LazySpecializationInfo count!");
+ Record[I] = (Record.size() - I - 1) / 3;
}
/// Ensure that this template specialization is associated with the specified
>From 718f1ed1b1a1f9937537b6260384b079bd42968c Mon Sep 17 00:00:00 2001
From: Chuanqi Xu <yedeng.yd at linux.alibaba.com>
Date: Tue, 27 Feb 2024 15:45:40 +0800
Subject: [PATCH 2/3] Fix test mismatch failure
---
clang/test/Modules/cxx-templates.cpp | 9 +++++----
clang/test/Modules/odr_hash.cpp | 4 ++--
2 files changed, 7 insertions(+), 6 deletions(-)
diff --git a/clang/test/Modules/cxx-templates.cpp b/clang/test/Modules/cxx-templates.cpp
index b7d5741e69af61..2d285c10ceec59 100644
--- a/clang/test/Modules/cxx-templates.cpp
+++ b/clang/test/Modules/cxx-templates.cpp
@@ -251,7 +251,7 @@ namespace Std {
// CHECK-DUMP: ClassTemplateDecl {{.*}} <{{.*[/\\]}}cxx-templates-common.h:1:1, {{.*}}> col:{{.*}} in cxx_templates_common SomeTemplate
// CHECK-DUMP: ClassTemplateSpecializationDecl {{.*}} prev {{.*}} SomeTemplate
-// CHECK-DUMP-NEXT: TemplateArgument type 'char[2]'
+// CHECK-DUMP-NEXT: TemplateArgument type 'char[1]'
// CHECK-DUMP: ClassTemplateSpecializationDecl {{.*}} SomeTemplate definition
// CHECK-DUMP-NEXT: DefinitionData
// CHECK-DUMP-NEXT: DefaultConstructor
@@ -260,9 +260,9 @@ namespace Std {
// CHECK-DUMP-NEXT: CopyAssignment
// CHECK-DUMP-NEXT: MoveAssignment
// CHECK-DUMP-NEXT: Destructor
-// CHECK-DUMP-NEXT: TemplateArgument type 'char[2]'
-// CHECK-DUMP: ClassTemplateSpecializationDecl {{.*}} prev {{.*}} SomeTemplate
// CHECK-DUMP-NEXT: TemplateArgument type 'char[1]'
+// CHECK-DUMP: ClassTemplateSpecializationDecl {{.*}} prev {{.*}} SomeTemplate
+// CHECK-DUMP-NEXT: TemplateArgument type 'char[2]'
// CHECK-DUMP: ClassTemplateSpecializationDecl {{.*}} SomeTemplate definition
// CHECK-DUMP-NEXT: DefinitionData
// CHECK-DUMP-NEXT: DefaultConstructor
@@ -271,4 +271,5 @@ namespace Std {
// CHECK-DUMP-NEXT: CopyAssignment
// CHECK-DUMP-NEXT: MoveAssignment
// CHECK-DUMP-NEXT: Destructor
-// CHECK-DUMP-NEXT: TemplateArgument type 'char[1]'
+// CHECK-DUMP-NEXT: TemplateArgument type 'char[2]'
+
diff --git a/clang/test/Modules/odr_hash.cpp b/clang/test/Modules/odr_hash.cpp
index fa8b2c81ab46e1..7cea3af3f41bdd 100644
--- a/clang/test/Modules/odr_hash.cpp
+++ b/clang/test/Modules/odr_hash.cpp
@@ -3084,8 +3084,8 @@ struct S5 {
};
#else
S5 s5;
-// expected-error at second.h:* {{'PointersAndReferences::S5::x' from module 'SecondModule' is not present in definition of 'PointersAndReferences::S5' in module 'FirstModule'}}
-// expected-note at first.h:* {{declaration of 'x' does not match}}
+// expected-error at first.h:* {{'PointersAndReferences::S5::x' from module 'FirstModule' is not present in definition of 'PointersAndReferences::S5' in module 'SecondModule'}}
+// expected-note at second.h:* {{declaration of 'x' does not match}}
#endif
#if defined(FIRST)
>From f44d7f8356ff0f858d779283c16c306c9c3df4d2 Mon Sep 17 00:00:00 2001
From: Chuanqi Xu <yedeng.yd at linux.alibaba.com>
Date: Tue, 27 Feb 2024 15:46:39 +0800
Subject: [PATCH 3/3] fmt
---
clang/include/clang/AST/DeclTemplate.h | 4 ++--
clang/lib/AST/DeclTemplate.cpp | 28 ++++++++++------------
clang/lib/Serialization/ASTReaderDecl.cpp | 21 ++++++++--------
clang/lib/Serialization/ASTWriter.cpp | 6 ++---
clang/lib/Serialization/ASTWriterDecl.cpp | 29 ++++++++++++-----------
5 files changed, 44 insertions(+), 44 deletions(-)
diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h
index 4ed9b58d4ff609..51caef54baac26 100644
--- a/clang/include/clang/AST/DeclTemplate.h
+++ b/clang/include/clang/AST/DeclTemplate.h
@@ -739,8 +739,8 @@ class RedeclarableTemplateDecl : public TemplateDecl,
bool IsPartial = false;
LazySpecializationInfo(uint32_t ID, unsigned Hash = ~0U,
bool Partial = false)
- : DeclID(ID), ODRHash(Hash), IsPartial(Partial) { }
- LazySpecializationInfo() { }
+ : DeclID(ID), ODRHash(Hash), IsPartial(Partial) {}
+ LazySpecializationInfo() {}
bool operator<(const LazySpecializationInfo &Other) const {
return DeclID < Other.DeclID;
}
diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp
index 1babe39ee2a7e5..aa2368783df7b5 100644
--- a/clang/lib/AST/DeclTemplate.cpp
+++ b/clang/lib/AST/DeclTemplate.cpp
@@ -16,12 +16,12 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclarationName.h"
#include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExternalASTSource.h"
+#include "clang/AST/ODRHash.h"
#include "clang/AST/TemplateBase.h"
#include "clang/AST/TemplateName.h"
#include "clang/AST/Type.h"
-#include "clang/AST/ODRHash.h"
-#include "clang/AST/ExprCXX.h"
#include "clang/AST/TypeLoc.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/LLVM.h"
@@ -334,7 +334,7 @@ RedeclarableTemplateDecl::CommonBase *RedeclarableTemplateDecl::getCommonPtr() c
}
void RedeclarableTemplateDecl::loadLazySpecializationsImpl(
- bool OnlyPartial/*=false*/) const {
+ bool OnlyPartial /*=false*/) const {
// Grab the most recent declaration to ensure we've loaded any lazy
// redeclarations of this template.
CommonBase *CommonBasePtr = getMostRecentDecl()->getCommonPtr();
@@ -343,16 +343,16 @@ void RedeclarableTemplateDecl::loadLazySpecializationsImpl(
CommonBasePtr->LazySpecializations = nullptr;
for (uint32_t I = 0, N = Specs[0].DeclID; I != N; ++I) {
// Skip over already loaded specializations.
- if (!Specs[I+1].ODRHash)
+ if (!Specs[I + 1].ODRHash)
continue;
- if (!OnlyPartial || Specs[I+1].IsPartial)
- (void)loadLazySpecializationImpl(Specs[I+1]);
+ if (!OnlyPartial || Specs[I + 1].IsPartial)
+ (void)loadLazySpecializationImpl(Specs[I + 1]);
}
}
}
Decl *RedeclarableTemplateDecl::loadLazySpecializationImpl(
- LazySpecializationInfo &LazySpecInfo) const {
+ LazySpecializationInfo &LazySpecInfo) const {
uint32_t ID = LazySpecInfo.DeclID;
assert(ID && "Loading already loaded specialization!");
// Note that we loaded the specialization.
@@ -360,16 +360,14 @@ Decl *RedeclarableTemplateDecl::loadLazySpecializationImpl(
return getASTContext().getExternalSource()->GetExternalDecl(ID);
}
-void
-RedeclarableTemplateDecl::loadLazySpecializationsImpl(ArrayRef<TemplateArgument>
- Args,
- TemplateParameterList *TPL) const {
+void RedeclarableTemplateDecl::loadLazySpecializationsImpl(
+ ArrayRef<TemplateArgument> Args, TemplateParameterList *TPL) const {
CommonBase *CommonBasePtr = getMostRecentDecl()->getCommonPtr();
if (auto *Specs = CommonBasePtr->LazySpecializations) {
unsigned Hash = TemplateArgumentList::ComputeODRHash(Args);
for (uint32_t I = 0, N = Specs[0].DeclID; I != N; ++I)
- if (Specs[I+1].ODRHash && Specs[I+1].ODRHash == Hash)
- (void)loadLazySpecializationImpl(Specs[I+1]);
+ if (Specs[I + 1].ODRHash && Specs[I + 1].ODRHash == Hash)
+ (void)loadLazySpecializationImpl(Specs[I + 1]);
}
}
@@ -546,7 +544,7 @@ ClassTemplateDecl *ClassTemplateDecl::CreateDeserialized(ASTContext &C,
}
void ClassTemplateDecl::LoadLazySpecializations(
- bool OnlyPartial/*=false*/) const {
+ bool OnlyPartial /*=false*/) const {
loadLazySpecializationsImpl(OnlyPartial);
}
@@ -1275,7 +1273,7 @@ VarTemplateDecl *VarTemplateDecl::CreateDeserialized(ASTContext &C,
}
void VarTemplateDecl::LoadLazySpecializations(
- bool OnlyPartial/*=false*/) const {
+ bool OnlyPartial /*=false*/) const {
loadLazySpecializationsImpl(OnlyPartial);
}
diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp
index f4f2ff9372a26d..8075a3c8d3b6a3 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -88,8 +88,8 @@ namespace clang {
const SourceLocation ThisDeclLoc;
using RecordData = ASTReader::RecordData;
- using LazySpecializationInfo
- = RedeclarableTemplateDecl::LazySpecializationInfo;
+ using LazySpecializationInfo =
+ RedeclarableTemplateDecl::LazySpecializationInfo;
TypeID DeferredTypeID = 0;
unsigned AnonymousDeclNumber = 0;
@@ -274,9 +274,9 @@ namespace clang {
: Reader(Reader), Record(Record), Loc(Loc), ThisDeclID(thisDeclID),
ThisDeclLoc(ThisDeclLoc) {}
- template <typename T> static
- void AddLazySpecializations(T *D,
- SmallVectorImpl<LazySpecializationInfo>& IDs) {
+ template <typename T>
+ static void
+ AddLazySpecializations(T *D, SmallVectorImpl<LazySpecializationInfo> &IDs) {
if (IDs.empty())
return;
@@ -328,7 +328,7 @@ namespace clang {
void ReadFunctionDefinition(FunctionDecl *FD);
void Visit(Decl *D);
- void UpdateDecl(Decl *D, llvm::SmallVectorImpl<LazySpecializationInfo>&);
+ void UpdateDecl(Decl *D, llvm::SmallVectorImpl<LazySpecializationInfo> &);
static void setNextObjCCategory(ObjCCategoryDecl *Cat,
ObjCCategoryDecl *Next) {
@@ -4203,8 +4203,8 @@ void ASTReader::loadDeclUpdateRecords(PendingUpdateRecord &Record) {
ProcessingUpdatesRAIIObj ProcessingUpdates(*this);
DeclUpdateOffsetsMap::iterator UpdI = DeclUpdateOffsets.find(ID);
- using LazySpecializationInfo
- = RedeclarableTemplateDecl::LazySpecializationInfo;
+ using LazySpecializationInfo =
+ RedeclarableTemplateDecl::LazySpecializationInfo;
llvm::SmallVector<LazySpecializationInfo, 8> PendingLazySpecializationIDs;
if (UpdI != DeclUpdateOffsets.end()) {
@@ -4474,8 +4474,9 @@ static void forAllLaterRedecls(DeclT *D, Fn F) {
}
}
-void ASTDeclReader::UpdateDecl(Decl *D,
- SmallVectorImpl<LazySpecializationInfo> &PendingLazySpecializationIDs) {
+void ASTDeclReader::UpdateDecl(
+ Decl *D,
+ SmallVectorImpl<LazySpecializationInfo> &PendingLazySpecializationIDs) {
while (Record.getIdx() < Record.size()) {
switch ((DeclUpdateKind)Record.readInt()) {
case UPD_CXX_ADDED_IMPLICIT_MEMBER: {
diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp
index b2d6d10ebbd516..d6ef2fd2ba75c9 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -5370,9 +5370,9 @@ void ASTWriter::WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord) {
Args = FD->getTemplateSpecializationArgs()->asArray();
assert(Args.size());
Record.push_back(TemplateArgumentList::ComputeODRHash(Args));
- bool IsPartialSpecialization
- = isa<ClassTemplatePartialSpecializationDecl>(Spec) ||
- isa<VarTemplatePartialSpecializationDecl>(Spec);
+ bool IsPartialSpecialization =
+ isa<ClassTemplatePartialSpecializationDecl>(Spec) ||
+ isa<VarTemplatePartialSpecializationDecl>(Spec);
Record.push_back(IsPartialSpecialization);
break;
}
diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp
index f39ec448accfd1..4f2711a16e9738 100644
--- a/clang/lib/Serialization/ASTWriterDecl.cpp
+++ b/clang/lib/Serialization/ASTWriterDecl.cpp
@@ -181,8 +181,9 @@ namespace clang {
/// Collect the first declaration from each module file that provides a
/// declaration of D.
- void CollectFirstDeclFromEachModule(const Decl *D, bool IncludeLocal,
- llvm::MapVector<ModuleFile*, const Decl*> &Firsts) {
+ void CollectFirstDeclFromEachModule(
+ const Decl *D, bool IncludeLocal,
+ llvm::MapVector<ModuleFile *, const Decl *> &Firsts) {
// FIXME: We can skip entries that we know are implied by others.
for (const Decl *R = D->getMostRecentDecl(); R; R = R->getPreviousDecl()) {
@@ -197,7 +198,7 @@ namespace clang {
/// provides a declaration of D. The intent is to provide a sufficient
/// set such that reloading this set will load all current redeclarations.
void AddFirstDeclFromEachModule(const Decl *D, bool IncludeLocal) {
- llvm::MapVector<ModuleFile*, const Decl*> Firsts;
+ llvm::MapVector<ModuleFile *, const Decl *> Firsts;
CollectFirstDeclFromEachModule(D, IncludeLocal, Firsts);
for (const auto &F : Firsts)
@@ -211,9 +212,9 @@ namespace clang {
void AddFirstSpecializationDeclFromEachModule(const Decl *D,
bool IncludeLocal) {
assert(isa<ClassTemplateSpecializationDecl>(D) ||
- isa<VarTemplateSpecializationDecl>(D) || isa<FunctionDecl>(D) &&
- "Must not be called with other decls");
- llvm::MapVector<ModuleFile*, const Decl*> Firsts;
+ isa<VarTemplateSpecializationDecl>(D) ||
+ isa<FunctionDecl>(D) && "Must not be called with other decls");
+ llvm::MapVector<ModuleFile *, const Decl *> Firsts;
CollectFirstDeclFromEachModule(D, IncludeLocal, Firsts);
for (const auto &F : Firsts) {
@@ -227,9 +228,9 @@ namespace clang {
Args = FD->getTemplateSpecializationArgs()->asArray();
assert(Args.size());
Record.push_back(TemplateArgumentList::ComputeODRHash(Args));
- bool IsPartialSpecialization
- = isa<ClassTemplatePartialSpecializationDecl>(D) ||
- isa<VarTemplatePartialSpecializationDecl>(D);
+ bool IsPartialSpecialization =
+ isa<ClassTemplatePartialSpecializationDecl>(D) ||
+ isa<VarTemplatePartialSpecializationDecl>(D);
Record.push_back(IsPartialSpecialization);
}
}
@@ -264,8 +265,8 @@ namespace clang {
assert(!Common->LazySpecializations);
}
- using LazySpecializationInfo
- = RedeclarableTemplateDecl::LazySpecializationInfo;
+ using LazySpecializationInfo =
+ RedeclarableTemplateDecl::LazySpecializationInfo;
ArrayRef<LazySpecializationInfo> LazySpecializations;
if (auto *LS = Common->LazySpecializations)
LazySpecializations = llvm::ArrayRef(LS + 1, LS[0].DeclID);
@@ -284,7 +285,7 @@ namespace clang {
for (auto *D : Specs) {
assert(D->isCanonicalDecl() && "non-canonical decl in set");
- AddFirstSpecializationDeclFromEachModule(D, /*IncludeLocal*/true);
+ AddFirstSpecializationDeclFromEachModule(D, /*IncludeLocal*/ true);
}
for (auto &SpecInfo : LazySpecializations) {
Record.push_back(SpecInfo.DeclID);
@@ -295,8 +296,8 @@ namespace clang {
// Update the size entry we added earlier. We linerized the
// LazySpecializationInfo members and we need to adjust the size as we
// will read them always together.
- assert ((Record.size() - I - 1) % 3 == 0
- && "Must be divisible by LazySpecializationInfo count!");
+ assert((Record.size() - I - 1) % 3 == 0 &&
+ "Must be divisible by LazySpecializationInfo count!");
Record[I] = (Record.size() - I - 1) / 3;
}
More information about the cfe-commits
mailing list