108 changes: 31 additions & 77 deletions clang/lib/AST/DeclTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,7 @@
#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"
Expand Down Expand Up @@ -350,39 +348,26 @@ RedeclarableTemplateDecl::CommonBase *RedeclarableTemplateDecl::getCommonPtr() c
return Common;
}

void RedeclarableTemplateDecl::loadLazySpecializationsImpl(
bool OnlyPartial /*=false*/) const {
auto *ExternalSource = getASTContext().getExternalSource();
if (!ExternalSource)
return;

ExternalSource->LoadExternalSpecializations(this->getCanonicalDecl(),
OnlyPartial);
return;
}

bool RedeclarableTemplateDecl::loadLazySpecializationsImpl(
ArrayRef<TemplateArgument> Args, TemplateParameterList *TPL) const {
auto *ExternalSource = getASTContext().getExternalSource();
if (!ExternalSource)
return false;

// If TPL is not null, it implies that we're loading specializations for
// partial templates. We need to load all specializations in such cases.
if (TPL)
return ExternalSource->LoadExternalSpecializations(this->getCanonicalDecl(),
/*OnlyPartial=*/false);

return ExternalSource->LoadExternalSpecializations(this->getCanonicalDecl(),
Args);
void RedeclarableTemplateDecl::loadLazySpecializationsImpl() 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();
GlobalDeclID *Specs = CommonBasePtr->LazySpecializations;
CommonBasePtr->LazySpecializations = nullptr;
unsigned SpecSize = (*Specs++).getRawValue();
for (unsigned I = 0; I != SpecSize; ++I)
(void)Context.getExternalSource()->GetExternalDecl(Specs[I]);
}
}

template <class EntryType, typename... ProfileArguments>
template<class EntryType, typename... ProfileArguments>
typename RedeclarableTemplateDecl::SpecEntryTraits<EntryType>::DeclType *
RedeclarableTemplateDecl::findSpecializationLocally(
RedeclarableTemplateDecl::findSpecializationImpl(
llvm::FoldingSetVector<EntryType> &Specs, void *&InsertPos,
ProfileArguments &&...ProfileArgs) {
using SETraits = RedeclarableTemplateDecl::SpecEntryTraits<EntryType>;
ProfileArguments&&... ProfileArgs) {
using SETraits = SpecEntryTraits<EntryType>;

llvm::FoldingSetNodeID ID;
EntryType::Profile(ID, std::forward<ProfileArguments>(ProfileArgs)...,
Expand All @@ -391,24 +376,6 @@ RedeclarableTemplateDecl::findSpecializationLocally(
return Entry ? SETraits::getDecl(Entry)->getMostRecentDecl() : nullptr;
}

template <class EntryType, typename... ProfileArguments>
typename RedeclarableTemplateDecl::SpecEntryTraits<EntryType>::DeclType *
RedeclarableTemplateDecl::findSpecializationImpl(
llvm::FoldingSetVector<EntryType> &Specs, void *&InsertPos,
ProfileArguments &&...ProfileArgs) {

if (auto *Found = findSpecializationLocally(
Specs, InsertPos, std::forward<ProfileArguments>(ProfileArgs)...))
return Found;

if (!loadLazySpecializationsImpl(
std::forward<ProfileArguments>(ProfileArgs)...))
return nullptr;

return findSpecializationLocally(
Specs, InsertPos, std::forward<ProfileArguments>(ProfileArgs)...);
}

template<class Derived, class EntryType>
void RedeclarableTemplateDecl::addSpecializationImpl(
llvm::FoldingSetVector<EntryType> &Specializations, EntryType *Entry,
Expand All @@ -417,14 +384,10 @@ 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, Args) &&
assert(!findSpecializationImpl(Specializations,
CorrectInsertPos,
SETraits::getTemplateArgs(Entry)) &&
InsertPos == CorrectInsertPos &&
"given incorrect InsertPos for specialization");
#endif
Expand Down Expand Up @@ -482,14 +445,12 @@ FunctionTemplateDecl::getSpecializations() const {
FunctionDecl *
FunctionTemplateDecl::findSpecialization(ArrayRef<TemplateArgument> Args,
void *&InsertPos) {
auto *Common = getCommonPtr();
return findSpecializationImpl(Common->Specializations, InsertPos, Args);
return findSpecializationImpl(getSpecializations(), InsertPos, Args);
}

void FunctionTemplateDecl::addSpecialization(
FunctionTemplateSpecializationInfo *Info, void *InsertPos) {
auto *Common = getCommonPtr();
addSpecializationImpl<FunctionTemplateDecl>(Common->Specializations, Info,
addSpecializationImpl<FunctionTemplateDecl>(getSpecializations(), Info,
InsertPos);
}

Expand Down Expand Up @@ -549,9 +510,8 @@ ClassTemplateDecl *ClassTemplateDecl::CreateDeserialized(ASTContext &C,
DeclarationName(), nullptr, nullptr);
}

void ClassTemplateDecl::LoadLazySpecializations(
bool OnlyPartial /*=false*/) const {
loadLazySpecializationsImpl(OnlyPartial);
void ClassTemplateDecl::LoadLazySpecializations() const {
loadLazySpecializationsImpl();
}

llvm::FoldingSetVector<ClassTemplateSpecializationDecl> &
Expand All @@ -562,7 +522,7 @@ ClassTemplateDecl::getSpecializations() const {

llvm::FoldingSetVector<ClassTemplatePartialSpecializationDecl> &
ClassTemplateDecl::getPartialSpecializations() const {
LoadLazySpecializations(/*PartialOnly = */ true);
LoadLazySpecializations();
return getCommonPtr()->PartialSpecializations;
}

Expand All @@ -576,15 +536,12 @@ ClassTemplateDecl::newCommon(ASTContext &C) const {
ClassTemplateSpecializationDecl *
ClassTemplateDecl::findSpecialization(ArrayRef<TemplateArgument> Args,
void *&InsertPos) {
auto *Common = getCommonPtr();
return findSpecializationImpl(Common->Specializations, InsertPos, Args);
return findSpecializationImpl(getSpecializations(), InsertPos, Args);
}

void ClassTemplateDecl::AddSpecialization(ClassTemplateSpecializationDecl *D,
void *InsertPos) {
auto *Common = getCommonPtr();
addSpecializationImpl<ClassTemplateDecl>(Common->Specializations, D,
InsertPos);
addSpecializationImpl<ClassTemplateDecl>(getSpecializations(), D, InsertPos);
}

ClassTemplatePartialSpecializationDecl *
Expand Down Expand Up @@ -1302,9 +1259,8 @@ VarTemplateDecl *VarTemplateDecl::CreateDeserialized(ASTContext &C,
DeclarationName(), nullptr, nullptr);
}

void VarTemplateDecl::LoadLazySpecializations(
bool OnlyPartial /*=false*/) const {
loadLazySpecializationsImpl(OnlyPartial);
void VarTemplateDecl::LoadLazySpecializations() const {
loadLazySpecializationsImpl();
}

llvm::FoldingSetVector<VarTemplateSpecializationDecl> &
Expand All @@ -1315,7 +1271,7 @@ VarTemplateDecl::getSpecializations() const {

llvm::FoldingSetVector<VarTemplatePartialSpecializationDecl> &
VarTemplateDecl::getPartialSpecializations() const {
LoadLazySpecializations(/*PartialOnly = */ true);
LoadLazySpecializations();
return getCommonPtr()->PartialSpecializations;
}

Expand All @@ -1329,14 +1285,12 @@ VarTemplateDecl::newCommon(ASTContext &C) const {
VarTemplateSpecializationDecl *
VarTemplateDecl::findSpecialization(ArrayRef<TemplateArgument> Args,
void *&InsertPos) {
auto *Common = getCommonPtr();
return findSpecializationImpl(Common->Specializations, InsertPos, Args);
return findSpecializationImpl(getSpecializations(), InsertPos, Args);
}

void VarTemplateDecl::AddSpecialization(VarTemplateSpecializationDecl *D,
void *InsertPos) {
auto *Common = getCommonPtr();
addSpecializationImpl<VarTemplateDecl>(Common->Specializations, D, InsertPos);
addSpecializationImpl<VarTemplateDecl>(getSpecializations(), D, InsertPos);
}

VarTemplatePartialSpecializationDecl *
Expand Down
9 changes: 0 additions & 9 deletions clang/lib/AST/ExternalASTSource.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,15 +96,6 @@ ExternalASTSource::FindExternalVisibleDeclsByName(const DeclContext *DC,
return false;
}

bool ExternalASTSource::LoadExternalSpecializations(const Decl *D, bool) {
return false;
}

bool ExternalASTSource::LoadExternalSpecializations(
const Decl *D, ArrayRef<TemplateArgument>) {
return false;
}

void ExternalASTSource::completeVisibleDeclsMap(const DeclContext *DC) {}

void ExternalASTSource::FindExternalLexicalDecls(
Expand Down
23 changes: 9 additions & 14 deletions clang/lib/AST/ODRHash.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -818,20 +818,15 @@ void ODRHash::AddDecl(const Decl *D) {

AddDeclarationName(ND->getDeclName());

// 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);
const auto *Specialization =
dyn_cast<ClassTemplateSpecializationDecl>(D);
AddBoolean(Specialization);
if (Specialization) {
const TemplateArgumentList &List = Specialization->getTemplateArgs();
ID.AddInteger(List.size());
for (const TemplateArgument &TA : List.asArray())
AddTemplateArgument(TA);
}
}

namespace {
Expand Down
17 changes: 0 additions & 17 deletions clang/lib/Sema/MultiplexExternalSemaSource.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,23 +115,6 @@ FindExternalVisibleDeclsByName(const DeclContext *DC, DeclarationName Name) {
return AnyDeclsFound;
}

bool MultiplexExternalSemaSource::LoadExternalSpecializations(
const Decl *D, bool OnlyPartial) {
bool Loaded = false;
for (size_t i = 0; i < Sources.size(); ++i)
Loaded |= Sources[i]->LoadExternalSpecializations(D, OnlyPartial);
return Loaded;
}

bool MultiplexExternalSemaSource::LoadExternalSpecializations(
const Decl *D, ArrayRef<TemplateArgument> TemplateArgs) {
bool AnyNewSpecsLoaded = false;
for (size_t i = 0; i < Sources.size(); ++i)
AnyNewSpecsLoaded |=
Sources[i]->LoadExternalSpecializations(D, TemplateArgs);
return AnyNewSpecsLoaded;
}

void MultiplexExternalSemaSource::completeVisibleDeclsMap(const DeclContext *DC){
for(size_t i = 0; i < Sources.size(); ++i)
Sources[i]->completeVisibleDeclsMap(DC);
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Serialization/ASTCommon.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ namespace serialization {

enum DeclUpdateKind {
UPD_CXX_ADDED_IMPLICIT_MEMBER,
UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION,
UPD_CXX_ADDED_ANONYMOUS_NAMESPACE,
UPD_CXX_ADDED_FUNCTION_DEFINITION,
UPD_CXX_ADDED_VAR_DEFINITION,
Expand Down
237 changes: 9 additions & 228 deletions clang/lib/Serialization/ASTReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@

#include "ASTCommon.h"
#include "ASTReaderInternals.h"
#include "TemplateArgumentHasher.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTMutationListener.h"
Expand Down Expand Up @@ -1296,42 +1295,6 @@ void ASTDeclContextNameLookupTrait::ReadDataInto(internal_key_type,
}
}

ModuleFile *
LazySpecializationInfoLookupTrait::ReadFileRef(const unsigned char *&d) {
using namespace llvm::support;

uint32_t ModuleFileID =
endian::readNext<uint32_t, llvm::endianness::little, unaligned>(d);
return Reader.getLocalModuleFile(F, ModuleFileID);
}

LazySpecializationInfoLookupTrait::internal_key_type
LazySpecializationInfoLookupTrait::ReadKey(const unsigned char *d, unsigned) {
using namespace llvm::support;
return endian::readNext<uint32_t, llvm::endianness::little, unaligned>(d);
}

std::pair<unsigned, unsigned>
LazySpecializationInfoLookupTrait::ReadKeyDataLength(const unsigned char *&d) {
return readULEBKeyDataLength(d);
}

void LazySpecializationInfoLookupTrait::ReadDataInto(internal_key_type,
const unsigned char *d,
unsigned DataLen,
data_type_builder &Val) {
using namespace llvm::support;

for (unsigned NumDecls =
DataLen / sizeof(serialization::reader::LazySpecializationInfo);
NumDecls; --NumDecls) {
LocalDeclID LocalID = LocalDeclID::get(
Reader, F,
endian::readNext<DeclID, llvm::endianness::little, unaligned>(d));
Val.insert(Reader.getGlobalDeclID(F, LocalID));
}
}

bool ASTReader::ReadLexicalDeclContextStorage(ModuleFile &M,
BitstreamCursor &Cursor,
uint64_t Offset,
Expand Down Expand Up @@ -1416,52 +1379,7 @@ bool ASTReader::ReadVisibleDeclContextStorage(ModuleFile &M,
// We can't safely determine the primary context yet, so delay attaching the
// lookup table until we're done with recursive deserialization.
auto *Data = (const unsigned char*)Blob.data();
PendingVisibleUpdates[ID].push_back(UpdateData{&M, Data});
return false;
}

void ASTReader::AddSpecializations(const Decl *D, const unsigned char *Data,
ModuleFile &M, bool IsPartial) {
D = D->getCanonicalDecl();
auto &SpecLookups =
IsPartial ? PartialSpecializationsLookups : SpecializationsLookups;
SpecLookups[D].Table.add(&M, Data,
reader::LazySpecializationInfoLookupTrait(*this, M));
}

bool ASTReader::ReadSpecializations(ModuleFile &M, BitstreamCursor &Cursor,
uint64_t Offset, Decl *D, bool IsPartial) {
assert(Offset != 0);

SavedStreamPosition SavedPosition(Cursor);
if (llvm::Error Err = Cursor.JumpToBit(Offset)) {
Error(std::move(Err));
return true;
}

RecordData Record;
StringRef Blob;
Expected<unsigned> MaybeCode = Cursor.ReadCode();
if (!MaybeCode) {
Error(MaybeCode.takeError());
return true;
}
unsigned Code = MaybeCode.get();

Expected<unsigned> MaybeRecCode = Cursor.readRecord(Code, Record, &Blob);
if (!MaybeRecCode) {
Error(MaybeRecCode.takeError());
return true;
}
unsigned RecCode = MaybeRecCode.get();
if (RecCode != DECL_SPECIALIZATIONS &&
RecCode != DECL_PARTIAL_SPECIALIZATIONS) {
Error("Expected decl specs block");
return true;
}

auto *Data = (const unsigned char *)Blob.data();
AddSpecializations(D, Data, M, IsPartial);
PendingVisibleUpdates[ID].push_back(PendingVisibleUpdate{&M, Data});
return false;
}

Expand Down Expand Up @@ -3540,33 +3458,7 @@ llvm::Error ASTReader::ReadASTBlock(ModuleFile &F,
unsigned Idx = 0;
GlobalDeclID ID = ReadDeclID(F, Record, Idx);
auto *Data = (const unsigned char*)Blob.data();
PendingVisibleUpdates[ID].push_back(UpdateData{&F, Data});
// If we've already loaded the decl, perform the updates when we finish
// loading this block.
if (Decl *D = GetExistingDecl(ID))
PendingUpdateRecords.push_back(
PendingUpdateRecord(ID, D, /*JustLoaded=*/false));
break;
}

case CXX_ADDED_TEMPLATE_SPECIALIZATION: {
unsigned Idx = 0;
GlobalDeclID ID = ReadDeclID(F, Record, Idx);
auto *Data = (const unsigned char *)Blob.data();
PendingSpecializationsUpdates[ID].push_back(UpdateData{&F, Data});
// If we've already loaded the decl, perform the updates when we finish
// loading this block.
if (Decl *D = GetExistingDecl(ID))
PendingUpdateRecords.push_back(
PendingUpdateRecord(ID, D, /*JustLoaded=*/false));
break;
}

case CXX_ADDED_TEMPLATE_PARTIAL_SPECIALIZATION: {
unsigned Idx = 0;
GlobalDeclID ID = ReadDeclID(F, Record, Idx);
auto *Data = (const unsigned char *)Blob.data();
PendingPartialSpecializationsUpdates[ID].push_back(UpdateData{&F, Data});
PendingVisibleUpdates[ID].push_back(PendingVisibleUpdate{&F, Data});
// If we've already loaded the decl, perform the updates when we finish
// loading this block.
if (Decl *D = GetExistingDecl(ID))
Expand Down Expand Up @@ -7762,28 +7654,13 @@ void ASTReader::CompleteRedeclChain(const Decl *D) {
}
}

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) {
// For partitial specialization, load all the specializations for safety.
if (isa<ClassTemplatePartialSpecializationDecl,
VarTemplatePartialSpecializationDecl>(D))
Template->loadLazySpecializationsImpl();
else
Template->loadLazySpecializationsImpl(Args);
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();
}
}

Expand Down Expand Up @@ -8165,86 +8042,6 @@ Stmt *ASTReader::GetExternalDeclStmt(uint64_t Offset) {
return ReadStmtFromStream(*Loc.F);
}

bool ASTReader::LoadExternalSpecializationsImpl(SpecLookupTableTy &SpecLookups,
const Decl *D) {
assert(D);

auto It = SpecLookups.find(D);
if (It == SpecLookups.end())
return false;

// Get Decl may violate the iterator from SpecializationsLookups so we store
// the DeclIDs in ahead.
llvm::SmallVector<serialization::reader::LazySpecializationInfo, 8> Infos =
It->second.Table.findAll();

// Since we've loaded all the specializations, we can erase it from
// the lookup table.
SpecLookups.erase(It);

bool NewSpecsFound = false;
Deserializing LookupResults(this);
for (auto &Info : Infos) {
if (GetExistingDecl(Info))
continue;
NewSpecsFound = true;
GetDecl(Info);
}

return NewSpecsFound;
}

bool ASTReader::LoadExternalSpecializations(const Decl *D, bool OnlyPartial) {
assert(D);

bool NewSpecsFound =
LoadExternalSpecializationsImpl(PartialSpecializationsLookups, D);
if (OnlyPartial)
return NewSpecsFound;

NewSpecsFound |= LoadExternalSpecializationsImpl(SpecializationsLookups, D);
return NewSpecsFound;
}

bool ASTReader::LoadExternalSpecializationsImpl(
SpecLookupTableTy &SpecLookups, const Decl *D,
ArrayRef<TemplateArgument> TemplateArgs) {
assert(D);

auto It = SpecLookups.find(D);
if (It == SpecLookups.end())
return false;

Deserializing LookupResults(this);
auto HashValue = StableHashForTemplateArguments(TemplateArgs);

// Get Decl may violate the iterator from SpecLookups
llvm::SmallVector<serialization::reader::LazySpecializationInfo, 8> Infos =
It->second.Table.find(HashValue);

bool NewSpecsFound = false;
for (auto &Info : Infos) {
if (GetExistingDecl(Info))
continue;
NewSpecsFound = true;
GetDecl(Info);
}

return NewSpecsFound;
}

bool ASTReader::LoadExternalSpecializations(
const Decl *D, ArrayRef<TemplateArgument> TemplateArgs) {
assert(D);

bool NewDeclsFound = LoadExternalSpecializationsImpl(
PartialSpecializationsLookups, D, TemplateArgs);
NewDeclsFound |=
LoadExternalSpecializationsImpl(SpecializationsLookups, D, TemplateArgs);

return NewDeclsFound;
}

void ASTReader::FindExternalLexicalDecls(
const DeclContext *DC, llvm::function_ref<bool(Decl::Kind)> IsKindWeWant,
SmallVectorImpl<Decl *> &Decls) {
Expand Down Expand Up @@ -8424,22 +8221,6 @@ ASTReader::getLoadedLookupTables(DeclContext *Primary) const {
return I == Lookups.end() ? nullptr : &I->second;
}

serialization::reader::LazySpecializationInfoLookupTable *
ASTReader::getLoadedSpecializationsLookupTables(const Decl *D, bool IsPartial) {
assert(D->isCanonicalDecl());
auto &LookupTable =
IsPartial ? PartialSpecializationsLookups : SpecializationsLookups;
auto I = LookupTable.find(D);
return I == LookupTable.end() ? nullptr : &I->second;
}

bool ASTReader::haveUnloadedSpecializations(const Decl *D) const {
assert(D->isCanonicalDecl());
return (PartialSpecializationsLookups.find(D) !=
PartialSpecializationsLookups.end()) ||
(SpecializationsLookups.find(D) != SpecializationsLookups.end());
}

/// Under non-PCH compilation the consumer receives the objc methods
/// before receiving the implementation, and codegen depends on this.
/// We simulate this by deserializing and passing to consumer the methods of the
Expand Down
104 changes: 61 additions & 43 deletions clang/lib/Serialization/ASTReaderDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,11 @@ class ASTDeclReader : public DeclVisitor<ASTDeclReader, void> {

std::string readString() { return Record.readString(); }

void readDeclIDList(SmallVectorImpl<GlobalDeclID> &IDs) {
for (unsigned I = 0, Size = Record.readInt(); I != Size; ++I)
IDs.push_back(readDeclID());
}

Decl *readDecl() { return Record.readDecl(); }

template <typename T> T *readDeclAs() { return Record.readDeclAs<T>(); }
Expand Down Expand Up @@ -279,6 +284,30 @@ class ASTDeclReader : public DeclVisitor<ASTDeclReader, void> {
: Reader(Reader), MergeImpl(Reader), Record(Record), Loc(Loc),
ThisDeclID(thisDeclID), ThisDeclLoc(ThisDeclLoc) {}

template <typename T>
static void AddLazySpecializations(T *D, SmallVectorImpl<GlobalDeclID> &IDs) {
if (IDs.empty())
return;

// FIXME: We should avoid this pattern of getting the ASTContext.
ASTContext &C = D->getASTContext();

auto *&LazySpecializations = D->getCommonPtr()->LazySpecializations;

if (auto &Old = LazySpecializations) {
IDs.insert(IDs.end(), Old + 1, Old + 1 + Old[0].getRawValue());
llvm::sort(IDs);
IDs.erase(std::unique(IDs.begin(), IDs.end()), IDs.end());
}

auto *Result = new (C) GlobalDeclID[1 + IDs.size()];
*Result = GlobalDeclID(IDs.size());

std::copy(IDs.begin(), IDs.end(), Result + 1);

LazySpecializations = Result;
}

template <typename DeclT>
static Decl *getMostRecentDeclImpl(Redeclarable<DeclT> *D);
static Decl *getMostRecentDeclImpl(...);
Expand All @@ -303,13 +332,10 @@ class ASTDeclReader : public DeclVisitor<ASTDeclReader, void> {
static void markIncompleteDeclChainImpl(Redeclarable<DeclT> *D);
static void markIncompleteDeclChainImpl(...);

void ReadSpecializations(ModuleFile &M, Decl *D,
llvm::BitstreamCursor &DeclsCursor, bool IsPartial);

void ReadFunctionDefinition(FunctionDecl *FD);
void Visit(Decl *D);

void UpdateDecl(Decl *D);
void UpdateDecl(Decl *D, SmallVectorImpl<GlobalDeclID> &);

static void setNextObjCCategory(ObjCCategoryDecl *Cat,
ObjCCategoryDecl *Next) {
Expand Down Expand Up @@ -2392,16 +2418,6 @@ void ASTDeclReader::VisitImplicitConceptSpecializationDecl(
void ASTDeclReader::VisitRequiresExprBodyDecl(RequiresExprBodyDecl *D) {
}

void ASTDeclReader::ReadSpecializations(ModuleFile &M, Decl *D,
llvm::BitstreamCursor &DeclsCursor,
bool IsPartial) {
uint64_t Offset = ReadLocalOffset();
bool Failed =
Reader.ReadSpecializations(M, DeclsCursor, Offset, D, IsPartial);
(void)Failed;
assert(!Failed);
}

RedeclarableResult
ASTDeclReader::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) {
RedeclarableResult Redecl = VisitRedeclarable(D);
Expand Down Expand Up @@ -2440,8 +2456,9 @@ void ASTDeclReader::VisitClassTemplateDecl(ClassTemplateDecl *D) {
if (ThisDeclID == Redecl.getFirstID()) {
// This ClassTemplateDecl owns a CommonPtr; read it to keep track of all of
// the specializations.
ReadSpecializations(*Loc.F, D, Loc.F->DeclsCursor, /*IsPartial=*/false);
ReadSpecializations(*Loc.F, D, Loc.F->DeclsCursor, /*IsPartial=*/true);
SmallVector<GlobalDeclID, 32> SpecIDs;
readDeclIDList(SpecIDs);
ASTDeclReader::AddLazySpecializations(D, SpecIDs);
}

if (D->getTemplatedDecl()->TemplateOrInstantiation) {
Expand All @@ -2467,8 +2484,9 @@ void ASTDeclReader::VisitVarTemplateDecl(VarTemplateDecl *D) {
if (ThisDeclID == Redecl.getFirstID()) {
// This VarTemplateDecl owns a CommonPtr; read it to keep track of all of
// the specializations.
ReadSpecializations(*Loc.F, D, Loc.F->DeclsCursor, /*IsPartial=*/false);
ReadSpecializations(*Loc.F, D, Loc.F->DeclsCursor, /*IsPartial=*/true);
SmallVector<GlobalDeclID, 32> SpecIDs;
readDeclIDList(SpecIDs);
ASTDeclReader::AddLazySpecializations(D, SpecIDs);
}
}

Expand Down Expand Up @@ -2567,7 +2585,9 @@ void ASTDeclReader::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {

if (ThisDeclID == Redecl.getFirstID()) {
// This FunctionTemplateDecl owns a CommonPtr; read it.
ReadSpecializations(*Loc.F, D, Loc.F->DeclsCursor, /*IsPartial=*/false);
SmallVector<GlobalDeclID, 32> SpecIDs;
readDeclIDList(SpecIDs);
ASTDeclReader::AddLazySpecializations(D, SpecIDs);
}
}

Expand Down Expand Up @@ -3857,8 +3877,6 @@ Decl *ASTReader::ReadDeclRecord(GlobalDeclID ID) {
switch ((DeclCode)MaybeDeclCode.get()) {
case DECL_CONTEXT_LEXICAL:
case DECL_CONTEXT_VISIBLE:
case DECL_SPECIALIZATIONS:
case DECL_PARTIAL_SPECIALIZATIONS:
llvm_unreachable("Record cannot be de-serialized with readDeclRecord");
case DECL_TYPEDEF:
D = TypedefDecl::CreateDeserialized(Context, ID);
Expand Down Expand Up @@ -4268,6 +4286,8 @@ void ASTReader::loadDeclUpdateRecords(PendingUpdateRecord &Record) {
ProcessingUpdatesRAIIObj ProcessingUpdates(*this);
DeclUpdateOffsetsMap::iterator UpdI = DeclUpdateOffsets.find(ID);

SmallVector<GlobalDeclID, 8> PendingLazySpecializationIDs;

if (UpdI != DeclUpdateOffsets.end()) {
auto UpdateOffsets = std::move(UpdI->second);
DeclUpdateOffsets.erase(UpdI);
Expand Down Expand Up @@ -4304,7 +4324,7 @@ void ASTReader::loadDeclUpdateRecords(PendingUpdateRecord &Record) {

ASTDeclReader Reader(*this, Record, RecordLocation(F, Offset), ID,
SourceLocation());
Reader.UpdateDecl(D);
Reader.UpdateDecl(D, PendingLazySpecializationIDs);

// We might have made this declaration interesting. If so, remember that
// we need to hand it off to the consumer.
Expand All @@ -4314,6 +4334,17 @@ void ASTReader::loadDeclUpdateRecords(PendingUpdateRecord &Record) {
}
}
}
// Add the lazy specializations to the template.
assert((PendingLazySpecializationIDs.empty() || isa<ClassTemplateDecl>(D) ||
isa<FunctionTemplateDecl, VarTemplateDecl>(D)) &&
"Must not have pending specializations");
if (auto *CTD = dyn_cast<ClassTemplateDecl>(D))
ASTDeclReader::AddLazySpecializations(CTD, PendingLazySpecializationIDs);
else if (auto *FTD = dyn_cast<FunctionTemplateDecl>(D))
ASTDeclReader::AddLazySpecializations(FTD, PendingLazySpecializationIDs);
else if (auto *VTD = dyn_cast<VarTemplateDecl>(D))
ASTDeclReader::AddLazySpecializations(VTD, PendingLazySpecializationIDs);
PendingLazySpecializationIDs.clear();

// Load the pending visible updates for this decl context, if it has any.
auto I = PendingVisibleUpdates.find(ID);
Expand All @@ -4338,26 +4369,6 @@ void ASTReader::loadDeclUpdateRecords(PendingUpdateRecord &Record) {
FunctionToLambdasMap.erase(IT);
}
}

// Load the pending specializations update for this decl, if it has any.
if (auto I = PendingSpecializationsUpdates.find(ID);
I != PendingSpecializationsUpdates.end()) {
auto SpecializationUpdates = std::move(I->second);
PendingSpecializationsUpdates.erase(I);

for (const auto &Update : SpecializationUpdates)
AddSpecializations(D, Update.Data, *Update.Mod, /*IsPartial=*/false);
}

// Load the pending specializations update for this decl, if it has any.
if (auto I = PendingPartialSpecializationsUpdates.find(ID);
I != PendingPartialSpecializationsUpdates.end()) {
auto SpecializationUpdates = std::move(I->second);
PendingPartialSpecializationsUpdates.erase(I);

for (const auto &Update : SpecializationUpdates)
AddSpecializations(D, Update.Data, *Update.Mod, /*IsPartial=*/true);
}
}

void ASTReader::loadPendingDeclChain(Decl *FirstLocal, uint64_t LocalOffset) {
Expand Down Expand Up @@ -4550,7 +4561,9 @@ static void forAllLaterRedecls(DeclT *D, Fn F) {
}
}

void ASTDeclReader::UpdateDecl(Decl *D) {
void ASTDeclReader::UpdateDecl(
Decl *D,
llvm::SmallVectorImpl<GlobalDeclID> &PendingLazySpecializationIDs) {
while (Record.getIdx() < Record.size()) {
switch ((DeclUpdateKind)Record.readInt()) {
case UPD_CXX_ADDED_IMPLICIT_MEMBER: {
Expand All @@ -4561,6 +4574,11 @@ void ASTDeclReader::UpdateDecl(Decl *D) {
break;
}

case UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION:
// It will be added to the template's lazy specialization set.
PendingLazySpecializationIDs.push_back(readDeclID());
break;

case UPD_CXX_ADDED_ANONYMOUS_NAMESPACE: {
auto *Anon = readDeclAs<NamespaceDecl>();

Expand Down
82 changes: 0 additions & 82 deletions clang/lib/Serialization/ASTReaderInternals.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,88 +119,6 @@ struct DeclContextLookupTable {
MultiOnDiskHashTable<ASTDeclContextNameLookupTrait> Table;
};

using LazySpecializationInfo = GlobalDeclID;

/// Class that performs lookup to specialized decls.
class LazySpecializationInfoLookupTrait {
ASTReader &Reader;
ModuleFile &F;

public:
// Maximum number of lookup tables we allow before condensing the tables.
static const int MaxTables = 4;

/// The lookup result is a list of global declaration IDs.
using data_type = SmallVector<LazySpecializationInfo, 4>;

struct data_type_builder {
data_type &Data;
llvm::DenseSet<LazySpecializationInfo> Found;

data_type_builder(data_type &D) : Data(D) {}

void insert(LazySpecializationInfo Info) {
// Just use a linear scan unless we have more than a few IDs.
if (Found.empty() && !Data.empty()) {
if (Data.size() <= 4) {
for (auto I : Found)
if (I == Info)
return;
Data.push_back(Info);
return;
}

// Switch to tracking found IDs in the set.
Found.insert(Data.begin(), Data.end());
}

if (Found.insert(Info).second)
Data.push_back(Info);
}
};
using hash_value_type = unsigned;
using offset_type = unsigned;
using file_type = ModuleFile *;

using external_key_type = unsigned;
using internal_key_type = unsigned;

explicit LazySpecializationInfoLookupTrait(ASTReader &Reader, ModuleFile &F)
: Reader(Reader), F(F) {}

static bool EqualKey(const internal_key_type &a, const internal_key_type &b) {
return a == b;
}

static hash_value_type ComputeHash(const internal_key_type &Key) {
return Key;
}

static internal_key_type GetInternalKey(const external_key_type &Name) {
return Name;
}

static std::pair<unsigned, unsigned>
ReadKeyDataLength(const unsigned char *&d);

internal_key_type ReadKey(const unsigned char *d, unsigned);

void ReadDataInto(internal_key_type, const unsigned char *d, unsigned DataLen,
data_type_builder &Val);

static void MergeDataInto(const data_type &From, data_type_builder &To) {
To.Data.reserve(To.Data.size() + From.size());
for (LazySpecializationInfo Info : From)
To.insert(Info);
}

file_type ReadFileRef(const unsigned char *&d);
};

struct LazySpecializationInfoLookupTable {
MultiOnDiskHashTable<LazySpecializationInfoLookupTrait> Table;
};

/// Base class for the trait describing the on-disk hash table for the
/// identifiers in an AST file.
///
Expand Down
209 changes: 3 additions & 206 deletions clang/lib/Serialization/ASTWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
#include "ASTCommon.h"
#include "ASTReaderInternals.h"
#include "MultiOnDiskHashTable.h"
#include "TemplateArgumentHasher.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTUnresolvedSet.h"
#include "clang/AST/AbstractTypeWriter.h"
Expand Down Expand Up @@ -4168,175 +4167,6 @@ class ASTDeclContextNameLookupTrait {

} // namespace

namespace {
class LazySpecializationInfoLookupTrait {
ASTWriter &Writer;
llvm::SmallVector<serialization::reader::LazySpecializationInfo, 64> Specs;

public:
using key_type = unsigned;
using key_type_ref = key_type;

/// A start and end index into Specs, representing a sequence of decls.
using data_type = std::pair<unsigned, unsigned>;
using data_type_ref = const data_type &;

using hash_value_type = unsigned;
using offset_type = unsigned;

explicit LazySpecializationInfoLookupTrait(ASTWriter &Writer)
: Writer(Writer) {}

template <typename Col, typename Col2>
data_type getData(Col &&C, Col2 &ExistingInfo) {
unsigned Start = Specs.size();
for (auto *D : C) {
NamedDecl *ND = getDeclForLocalLookup(Writer.getLangOpts(),
const_cast<NamedDecl *>(D));
Specs.push_back(GlobalDeclID(Writer.GetDeclRef(ND).getRawValue()));
}
for (const serialization::reader::LazySpecializationInfo &Info :
ExistingInfo)
Specs.push_back(Info);
return std::make_pair(Start, Specs.size());
}

data_type ImportData(
const reader::LazySpecializationInfoLookupTrait::data_type &FromReader) {
unsigned Start = Specs.size();
for (auto ID : FromReader)
Specs.push_back(ID);
return std::make_pair(Start, Specs.size());
}

static bool EqualKey(key_type_ref a, key_type_ref b) { return a == b; }

hash_value_type ComputeHash(key_type Name) { return Name; }

void EmitFileRef(raw_ostream &Out, ModuleFile *F) const {
assert(Writer.hasChain() &&
"have reference to loaded module file but no chain?");

using namespace llvm::support;
endian::write<uint32_t>(Out, Writer.getChain()->getModuleFileID(F),
llvm::endianness::little);
}

std::pair<unsigned, unsigned> EmitKeyDataLength(raw_ostream &Out,
key_type HashValue,
data_type_ref Lookup) {
// 4 bytes for each slot.
unsigned KeyLen = 4;
unsigned DataLen = sizeof(serialization::reader::LazySpecializationInfo) *
(Lookup.second - Lookup.first);

return emitULEBKeyDataLength(KeyLen, DataLen, Out);
}

void EmitKey(raw_ostream &Out, key_type HashValue, unsigned) {
using namespace llvm::support;

endian::Writer LE(Out, llvm::endianness::little);
LE.write<uint32_t>(HashValue);
}

void EmitData(raw_ostream &Out, key_type_ref, data_type Lookup,
unsigned DataLen) {
using namespace llvm::support;

endian::Writer LE(Out, llvm::endianness::little);
uint64_t Start = Out.tell();
(void)Start;
for (unsigned I = Lookup.first, N = Lookup.second; I != N; ++I) {
LE.write<DeclID>(Specs[I].getRawValue());
}
assert(Out.tell() - Start == DataLen && "Data length is wrong");
}
};

unsigned CalculateODRHashForSpecs(const Decl *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();
else
llvm_unreachable("New Specialization Kind?");

return StableHashForTemplateArguments(Args);
}
} // namespace

void ASTWriter::GenerateSpecializationInfoLookupTable(
const NamedDecl *D, llvm::SmallVectorImpl<const Decl *> &Specializations,
llvm::SmallVectorImpl<char> &LookupTable, bool IsPartial) {
assert(D->isFirstDecl());

// Create the on-disk hash table representation.
MultiOnDiskHashTableGenerator<reader::LazySpecializationInfoLookupTrait,
LazySpecializationInfoLookupTrait>
Generator;
LazySpecializationInfoLookupTrait Trait(*this);

llvm::DenseMap<unsigned, llvm::SmallVector<const NamedDecl *, 4>>
SpecializationMaps;

for (auto *Specialization : Specializations) {
unsigned HashedValue = CalculateODRHashForSpecs(Specialization);

auto Iter = SpecializationMaps.find(HashedValue);
if (Iter == SpecializationMaps.end())
Iter = SpecializationMaps
.try_emplace(HashedValue,
llvm::SmallVector<const NamedDecl *, 4>())
.first;

Iter->second.push_back(cast<NamedDecl>(Specialization));
}

auto *Lookups =
Chain ? Chain->getLoadedSpecializationsLookupTables(D, IsPartial)
: nullptr;

for (auto &[HashValue, Specs] : SpecializationMaps) {
SmallVector<serialization::reader::LazySpecializationInfo, 16>
ExisitingSpecs;
// We have to merge the lookup table manually here. We can't depend on the
// merge mechanism offered by
// clang::serialization::MultiOnDiskHashTableGenerator since that generator
// assumes the we'll get the same value with the same key.
// And also underlying llvm::OnDiskChainedHashTableGenerator assumes that we
// won't insert the values with the same key twice. So we have to merge the
// lookup table here manually.
if (Lookups)
ExisitingSpecs = Lookups->Table.find(HashValue);

Generator.insert(HashValue, Trait.getData(Specs, ExisitingSpecs), Trait);
}

Generator.emit(LookupTable, Trait, Lookups ? &Lookups->Table : nullptr);
}

uint64_t ASTWriter::WriteSpecializationInfoLookupTable(
const NamedDecl *D, llvm::SmallVectorImpl<const Decl *> &Specializations,
bool IsPartial) {

llvm::SmallString<4096> LookupTable;
GenerateSpecializationInfoLookupTable(D, Specializations, LookupTable,
IsPartial);

uint64_t Offset = Stream.GetCurrentBitNo();
RecordData::value_type Record[] = {IsPartial ? DECL_PARTIAL_SPECIALIZATIONS
: DECL_SPECIALIZATIONS};
Stream.EmitRecordWithBlob(IsPartial ? DeclPartialSpecializationsAbbrev
: DeclSpecializationsAbbrev,
Record, LookupTable);

return Offset;
}

bool ASTWriter::isLookupResultExternal(StoredDeclsList &Result,
DeclContext *DC) {
return Result.hasExternalDecls() &&
Expand Down Expand Up @@ -5918,7 +5748,7 @@ void ASTWriter::WriteDeclAndTypes(ASTContext &Context) {
// Keep writing types, declarations, and declaration update records
// until we've emitted all of them.
RecordData DeclUpdatesOffsetsRecord;
Stream.EnterSubblock(DECLTYPES_BLOCK_ID, /*bits for abbreviations*/ 6);
Stream.EnterSubblock(DECLTYPES_BLOCK_ID, /*bits for abbreviations*/5);
DeclTypesBlockStartOffset = Stream.GetCurrentBitNo();
WriteTypeAbbrevs();
WriteDeclAbbrevs();
Expand Down Expand Up @@ -5992,16 +5822,6 @@ void ASTWriter::WriteDeclAndTypes(ASTContext &Context) {
FunctionToLambdaMapAbbrev);
}

if (!SpecializationsUpdates.empty()) {
WriteSpecializationsUpdates(/*IsPartial=*/false);
SpecializationsUpdates.clear();
}

if (!PartialSpecializationsUpdates.empty()) {
WriteSpecializationsUpdates(/*IsPartial=*/true);
PartialSpecializationsUpdates.clear();
}

const TranslationUnitDecl *TU = Context.getTranslationUnitDecl();
// Create a lexical update block containing all of the declarations in the
// translation unit that do not come from other AST files.
Expand Down Expand Up @@ -6045,31 +5865,6 @@ void ASTWriter::WriteDeclAndTypes(ASTContext &Context) {
WriteDeclContextVisibleUpdate(Context, DC);
}

void ASTWriter::WriteSpecializationsUpdates(bool IsPartial) {
auto RecordType = IsPartial ? CXX_ADDED_TEMPLATE_PARTIAL_SPECIALIZATION
: CXX_ADDED_TEMPLATE_SPECIALIZATION;

auto Abv = std::make_shared<llvm::BitCodeAbbrev>();
Abv->Add(llvm::BitCodeAbbrevOp(RecordType));
Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::VBR, 6));
Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob));
auto UpdateSpecializationAbbrev = Stream.EmitAbbrev(std::move(Abv));

auto &SpecUpdates =
IsPartial ? PartialSpecializationsUpdates : SpecializationsUpdates;
for (auto &SpecializationUpdate : SpecUpdates) {
const NamedDecl *D = SpecializationUpdate.first;

llvm::SmallString<4096> LookupTable;
GenerateSpecializationInfoLookupTable(D, SpecializationUpdate.second,
LookupTable, IsPartial);

// Write the lookup table
RecordData::value_type Record[] = {RecordType, getDeclID(D).getRawValue()};
Stream.EmitRecordWithBlob(UpdateSpecializationAbbrev, Record, LookupTable);
}
}

void ASTWriter::WriteDeclUpdatesBlocks(ASTContext &Context,
RecordDataImpl &OffsetsRecord) {
if (DeclUpdates.empty())
Expand Down Expand Up @@ -6099,10 +5894,12 @@ void ASTWriter::WriteDeclUpdatesBlocks(ASTContext &Context,

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.AddDeclRef(Update.getDecl());
break;

case UPD_CXX_ADDED_FUNCTION_DEFINITION:
case UPD_CXX_ADDED_VAR_DEFINITION:
break;
Expand Down
110 changes: 31 additions & 79 deletions clang/lib/Serialization/ASTWriterDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -177,54 +177,22 @@ namespace clang {
Record.AddSourceLocation(typeParams->getRAngleLoc());
}

/// 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) {

/// 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;
// 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())
Firsts[Writer.Chain->getOwningModuleFile(R)] = R;
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, llvm::SmallVectorImpl<const Decl *> &SpecsInMap,
llvm::SmallVectorImpl<const Decl *> &PartialSpecsInMap) {
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*/ true, Firsts);

for (const auto &F : Firsts) {
if (isa<ClassTemplatePartialSpecializationDecl,
VarTemplatePartialSpecializationDecl>(F.second))
PartialSpecsInMap.push_back(F.second);
else
SpecsInMap.push_back(F.second);
}
}

/// Get the specialization decl from an entry in the specialization list.
template <typename EntryType>
typename RedeclarableTemplateDecl::SpecEntryTraits<EntryType>::DeclType *
Expand All @@ -237,9 +205,8 @@ namespace clang {
decltype(T::PartialSpecializations) &getPartialSpecializations(T *Common) {
return Common->PartialSpecializations;
}
MutableArrayRef<FunctionTemplateSpecializationInfo>
getPartialSpecializations(FunctionTemplateDecl::Common *) {
return std::nullopt;
ArrayRef<Decl> getPartialSpecializations(FunctionTemplateDecl::Common *) {
return {};
}

template<typename DeclTy>
Expand All @@ -250,37 +217,37 @@ namespace clang {
// our chained AST reader, we can just write out the DeclIDs. Otherwise,
// we need to resolve them to actual declarations.
if (Writer.Chain != Record.getASTContext().getExternalSource() &&
Writer.Chain && Writer.Chain->haveUnloadedSpecializations(D)) {
Common->LazySpecializations) {
D->LoadLazySpecializations();
assert(!Writer.Chain->haveUnloadedSpecializations(D));
assert(!Common->LazySpecializations);
}

// AddFirstSpecializationDeclFromEachModule might trigger deserialization,
// invalidating *Specializations iterators.
llvm::SmallVector<const Decl *, 16> AllSpecs;
ArrayRef<GlobalDeclID> LazySpecializations;
if (auto *LS = Common->LazySpecializations)
LazySpecializations = llvm::ArrayRef(LS + 1, LS[0].getRawValue());

// Add a slot to the record for the number of specializations.
unsigned I = Record.size();
Record.push_back(0);

// AddFirstDeclFromEachModule might trigger deserialization, invalidating
// *Specializations iterators.
llvm::SmallVector<const Decl*, 16> Specs;
for (auto &Entry : Common->Specializations)
AllSpecs.push_back(getSpecializationDecl(Entry));
Specs.push_back(getSpecializationDecl(Entry));
for (auto &Entry : getPartialSpecializations(Common))
AllSpecs.push_back(getSpecializationDecl(Entry));
Specs.push_back(getSpecializationDecl(Entry));

llvm::SmallVector<const Decl *, 16> Specs;
llvm::SmallVector<const Decl *, 16> PartialSpecs;
for (auto *D : AllSpecs) {
for (auto *D : Specs) {
assert(D->isCanonicalDecl() && "non-canonical decl in set");
AddFirstSpecializationDeclFromEachModule(D, Specs, PartialSpecs);
}

Record.AddOffset(Writer.WriteSpecializationInfoLookupTable(
D, Specs, /*IsPartial=*/false));

// Function Template Decl doesn't have partial decls.
if (isa<FunctionTemplateDecl>(D)) {
assert(PartialSpecs.empty());
return;
AddFirstDeclFromEachModule(D, /*IncludeLocal*/true);
}
Record.append(
DeclIDIterator<GlobalDeclID, DeclID>(LazySpecializations.begin()),
DeclIDIterator<GlobalDeclID, DeclID>(LazySpecializations.end()));

Record.AddOffset(Writer.WriteSpecializationInfoLookupTable(
D, PartialSpecs, /*IsPartial=*/true));
// Update the size entry we added earlier.
Record[I] = Record.size() - I - 1;
}

/// Ensure that this template specialization is associated with the specified
Expand All @@ -301,13 +268,8 @@ namespace clang {
if (Writer.getFirstLocalDecl(Specialization) != Specialization)
return;

if (isa<ClassTemplatePartialSpecializationDecl,
VarTemplatePartialSpecializationDecl>(Specialization))
Writer.PartialSpecializationsUpdates[cast<NamedDecl>(Template)]
.push_back(cast<NamedDecl>(Specialization));
else
Writer.SpecializationsUpdates[cast<NamedDecl>(Template)].push_back(
cast<NamedDecl>(Specialization));
Writer.DeclUpdates[Template].push_back(ASTWriter::DeclUpdate(
UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION, Specialization));
}
};
}
Expand Down Expand Up @@ -2812,16 +2774,6 @@ void ASTWriter::WriteDeclAbbrevs() {
Abv->Add(BitCodeAbbrevOp(serialization::DECL_CONTEXT_VISIBLE));
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
DeclContextVisibleLookupAbbrev = Stream.EmitAbbrev(std::move(Abv));

Abv = std::make_shared<BitCodeAbbrev>();
Abv->Add(BitCodeAbbrevOp(serialization::DECL_SPECIALIZATIONS));
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
DeclSpecializationsAbbrev = Stream.EmitAbbrev(std::move(Abv));

Abv = std::make_shared<BitCodeAbbrev>();
Abv->Add(BitCodeAbbrevOp(serialization::DECL_PARTIAL_SPECIALIZATIONS));
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
DeclPartialSpecializationsAbbrev = Stream.EmitAbbrev(std::move(Abv));
}

/// isRequiredDecl - Check if this is a "required" Decl, which must be seen by
Expand Down
1 change: 0 additions & 1 deletion clang/lib/Serialization/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ add_clang_library(clangSerialization
ModuleManager.cpp
PCHContainerOperations.cpp
ObjectFilePCHContainerReader.cpp
TemplateArgumentHasher.cpp

ADDITIONAL_HEADERS
ASTCommon.h
Expand Down
409 changes: 0 additions & 409 deletions clang/lib/Serialization/TemplateArgumentHasher.cpp

This file was deleted.

34 changes: 0 additions & 34 deletions clang/lib/Serialization/TemplateArgumentHasher.h

This file was deleted.

4 changes: 2 additions & 2 deletions clang/test/Modules/odr_hash.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3084,8 +3084,8 @@ struct S5 {
};
#else
S5 s5;
// expected-error@first.h:* {{'PointersAndReferences::S5::x' from module 'FirstModule' is not present in definition of 'PointersAndReferences::S5' in module 'SecondModule'}}
// expected-note@second.h:* {{declaration of 'x' does not match}}
// expected-error@second.h:* {{'PointersAndReferences::S5::x' from module 'SecondModule' is not present in definition of 'PointersAndReferences::S5' in module 'FirstModule'}}
// expected-note@first.h:* {{declaration of 'x' does not match}}
#endif

#if defined(FIRST)
Expand Down
40 changes: 0 additions & 40 deletions clang/test/Modules/recursive-instantiations.cppm

This file was deleted.

4 changes: 4 additions & 0 deletions clang/test/OpenMP/target_parallel_ast_print.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ struct S {
// CHECK: static int TS;
// CHECK-NEXT: #pragma omp threadprivate(S<int>::TS)
// CHECK-NEXT: }
// CHECK: template<> struct S<char> {
// CHECK: static char TS;
// CHECK-NEXT: #pragma omp threadprivate(S<char>::TS)
// CHECK-NEXT: }

template <typename T, int C>
T tmain(T argc, T *argv) {
Expand Down
4 changes: 4 additions & 0 deletions clang/test/OpenMP/target_teams_ast_print.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ struct S {
// CHECK: static int TS;
// CHECK-NEXT: #pragma omp threadprivate(S<int>::TS)
// CHECK-NEXT: }
// CHECK: template<> struct S<long> {
// CHECK: static long TS;
// CHECK-NEXT: #pragma omp threadprivate(S<long>::TS)
// CHECK-NEXT: }

template <typename T, int C>
T tmain(T argc, T *argv) {
Expand Down
4 changes: 4 additions & 0 deletions clang/test/OpenMP/task_ast_print.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@ struct S {
// CHECK: static int TS;
// CHECK-NEXT: #pragma omp threadprivate(S<int>::TS)
// CHECK-NEXT: }
// CHECK: template<> struct S<long> {
// CHECK: static long TS;
// CHECK-NEXT: #pragma omp threadprivate(S<long>::TS)
// CHECK-NEXT: }

template <typename T, int C>
T tmain(T argc, T *argv) {
Expand Down
4 changes: 4 additions & 0 deletions clang/test/OpenMP/teams_ast_print.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ struct S {
// CHECK: static int TS;
// CHECK-NEXT: #pragma omp threadprivate(S<int>::TS)
// CHECK-NEXT: }
// CHECK: template<> struct S<long> {
// CHECK: static long TS;
// CHECK-NEXT: #pragma omp threadprivate(S<long>::TS)
// CHECK-NEXT: }

template <typename T, int C>
T tmain(T argc, T *argv) {
Expand Down
1 change: 0 additions & 1 deletion clang/unittests/Serialization/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ add_clang_unittest(SerializationTests
ModuleCacheTest.cpp
NoCommentsTest.cpp
PreambleInNamedModulesTest.cpp
LoadSpecLazilyTest.cpp
SourceLocationEncodingTest.cpp
VarDeclConstantInitTest.cpp
)
Expand Down
262 changes: 0 additions & 262 deletions clang/unittests/Serialization/LoadSpecLazilyTest.cpp

This file was deleted.