Simplify and "robust-ify" the way that CXXRecord references point to the definition data when loaded from PCH.

Temporary disable 'test/PCH/chain-cxx.cpp' until a better way to fix it is in place.

llvm-svn: 117234
This commit is contained in:
Argyrios Kyrtzidis 2010-10-24 17:26:31 +00:00
parent 8b200a5ef1
commit ad5f95cc4b
5 changed files with 44 additions and 58 deletions

View File

@ -436,6 +436,14 @@ private:
/// haven't been loaded yet.
DeclContextVisibleUpdatesPending PendingVisibleUpdates;
typedef llvm::SmallVector<CXXRecordDecl *, 4> ForwardRefs;
typedef llvm::DenseMap<const CXXRecordDecl *, ForwardRefs>
PendingForwardRefsMap;
/// \brief Forward references that have a definition but the definition decl
/// is still initializing. When the definition gets read it will update
/// the DefinitionData pointer of all pending references.
PendingForwardRefsMap PendingForwardRefs;
typedef llvm::DenseMap<serialization::DeclID, serialization::DeclID>
FirstLatestDeclIDMap;
/// \brief Map of first declarations from a chained PCH that point to the

View File

@ -4318,6 +4318,9 @@ void ASTReader::FinishedDeserializing() {
// decls to the consumer.
if (Consumer)
PassInterestingDeclsToConsumer();
assert(PendingForwardRefs.size() == 0 &&
"Some forward refs did not get linked to the definition!");
}
--NumCurrentElementsDeserializing;
}

View File

@ -807,50 +807,37 @@ void ASTDeclReader::ReadCXXDefinitionData(
}
void ASTDeclReader::VisitCXXRecordDecl(CXXRecordDecl *D) {
ASTContext &C = *Reader.getContext();
// We need to allocate the DefinitionData struct ahead of VisitRecordDecl
// so that the other CXXRecordDecls can get a pointer even when the owner
// is still initializing.
enum DataOwnership { Data_NoDefData, Data_Owner, Data_NotOwner };
DataOwnership DefOwnership = (DataOwnership)Record[Idx++];
switch (DefOwnership) {
default:
assert(0 && "Out of sync with ASTDeclWriter or messed up reading");
case Data_NoDefData:
break;
case Data_Owner:
D->DefinitionData = new (C) struct CXXRecordDecl::DefinitionData(D);
break;
case Data_NotOwner:
D->DefinitionData
= cast<CXXRecordDecl>(Reader.GetDecl(Record[Idx++]))->DefinitionData;
break;
}
VisitRecordDecl(D);
// Spread the DefinitionData pointer if it's the definition (it may have
// come from a chained PCH and earlier redeclarations don't know it), or
// if it just acquired a pointer that it's not supposed to have (a definition
// from a chained PCH updated it).
if (D->DefinitionData && DefOwnership != Data_NotOwner) {
llvm::SmallPtrSet<CXXRecordDecl *, 16> PrevRedecls;
PrevRedecls.insert(D);
CXXRecordDecl *Redecl = cast<CXXRecordDecl>(D->RedeclLink.getNext());
while (!PrevRedecls.count(Redecl)) {
PrevRedecls.insert(Redecl);
assert((!Redecl->DefinitionData ||
Redecl->DefinitionData == D->DefinitionData) &&
"Multiple definitions in the redeclaration chain ?");
Redecl->DefinitionData = D->DefinitionData;
Redecl = cast<CXXRecordDecl>(Redecl->RedeclLink.getNext());
}
}
ASTContext &C = *Reader.getContext();
if (DefOwnership == Data_Owner) {
assert(D->DefinitionData);
CXXRecordDecl *DefinitionDecl
= cast_or_null<CXXRecordDecl>(Reader.GetDecl(Record[Idx++]));
if (D == DefinitionDecl) {
D->DefinitionData = new (C) struct CXXRecordDecl::DefinitionData(D);
ReadCXXDefinitionData(*D->DefinitionData);
// We read the definition info. Check if there are pending forward
// references that need to point to this DefinitionData pointer.
ASTReader::PendingForwardRefsMap::iterator
FindI = Reader.PendingForwardRefs.find(D);
if (FindI != Reader.PendingForwardRefs.end()) {
ASTReader::ForwardRefs &Refs = FindI->second;
for (ASTReader::ForwardRefs::iterator
I = Refs.begin(), E = Refs.end(); I != E; ++I)
(*I)->DefinitionData = D->DefinitionData;
#ifndef NDEBUG
// We later check whether PendingForwardRefs is empty to make sure all
// pending references were linked.
Reader.PendingForwardRefs.erase(D);
#endif
}
} else if (DefinitionDecl) {
if (DefinitionDecl->DefinitionData) {
D->DefinitionData = DefinitionDecl->DefinitionData;
} else {
// The definition is still initializing.
Reader.PendingForwardRefs[DefinitionDecl].push_back(D);
}
}
enum CXXRecKind {

View File

@ -758,26 +758,13 @@ void ASTDeclWriter::WriteCXXDefinitionData(
}
void ASTDeclWriter::VisitCXXRecordDecl(CXXRecordDecl *D) {
// See comments at ASTDeclReader::VisitCXXRecordDecl about why this happens
// before VisitRecordDecl.
enum { Data_NoDefData, Data_Owner, Data_NotOwner };
bool OwnsDefinitionData = false;
if (D->DefinitionData) {
assert(D->DefinitionData->Definition &&
"DefinitionData don't point to a definition decl!");
OwnsDefinitionData = D->DefinitionData->Definition == D;
if (OwnsDefinitionData) {
Record.push_back(Data_Owner);
} else {
Record.push_back(Data_NotOwner);
Writer.AddDeclRef(D->DefinitionData->Definition, Record);
}
} else
Record.push_back(Data_NoDefData);
VisitRecordDecl(D);
if (OwnsDefinitionData) {
CXXRecordDecl *DefinitionDecl = 0;
if (D->DefinitionData)
DefinitionDecl = D->DefinitionData->Definition;
Writer.AddDeclRef(DefinitionDecl, Record);
if (D == DefinitionDecl) {
assert(D->DefinitionData);
WriteCXXDefinitionData(*D->DefinitionData);
}

View File

@ -7,6 +7,7 @@
// RUN: %clang_cc1 -x c++-header -emit-pch -o %t1 %s
// RUN: %clang_cc1 -x c++-header -emit-pch -o %t2 %s -include-pch %t1 -chained-pch
// RUN: %clang_cc1 -fsyntax-only -verify -include-pch %t2 %s
// XFAIL: *
#ifndef HEADER1
#define HEADER1