Support C++ friend declarations for PCH.

This commit 'introduces' a slightly different way to restore the state of the AST object.
It makes PCHDeclReader/PCHDeclWriter friends and gives them access to the private members of the object.
The rationale is to avoid using/modifying the AST interfaces for PCH read/write so that to:

-Avoid complications with objects that have side-effects during creation or when using some setters.
-Not 'pollute' the AST interface with methods only used by the PCH reader/writer
-Allow AST objects to be read-only.

llvm-svn: 107219
This commit is contained in:
Argyrios Kyrtzidis 2010-06-29 22:47:00 +00:00
parent 26d7201d5d
commit 74d28bd084
9 changed files with 80 additions and 9 deletions

View File

@ -248,6 +248,14 @@ protected:
if (Decl::CollectingStats()) add(DK);
}
Decl(Kind DK, EmptyShell Empty)
: NextDeclInContext(0), DeclKind(DK), InvalidDecl(0),
HasAttrs(false), Implicit(false), Used(false),
Access(AS_none), PCHLevel(0),
IdentifierNamespace(getIdentifierNamespaceForKind(DK)) {
if (Decl::CollectingStats()) add(DK);
}
virtual ~Decl();
public:

View File

@ -973,6 +973,9 @@ public:
static bool classof(const ClassTemplateSpecializationDecl *D) {
return true;
}
friend class PCHDeclReader;
friend class PCHDeclWriter;
};
/// CXXMethodDecl - Represents a static or instance method of a

View File

@ -59,10 +59,13 @@ private:
FriendLoc(FriendL) {
}
FriendDecl(EmptyShell Empty) : Decl(Decl::Friend, Empty), NextFriend(0) { }
public:
static FriendDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation L, FriendUnion Friend_,
SourceLocation FriendL);
static FriendDecl *Create(ASTContext &C, EmptyShell Empty);
/// If this friend declaration names an (untemplated but
/// possibly dependent) type, return the type; otherwise
@ -87,6 +90,9 @@ public:
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const FriendDecl *D) { return true; }
static bool classofKind(Kind K) { return K == Decl::Friend; }
friend class PCHDeclReader;
friend class PCHDeclWriter;
};
/// An iterator over the friend declarations of a class.

View File

@ -39,3 +39,7 @@ FriendDecl *FriendDecl::Create(ASTContext &C, DeclContext *DC,
cast<CXXRecordDecl>(DC)->pushFriendDecl(FD);
return FD;
}
FriendDecl *FriendDecl::Create(ASTContext &C, EmptyShell Empty) {
return new (C) FriendDecl(Empty);
}

View File

@ -27,7 +27,7 @@ using namespace clang;
// Declaration deserialization
//===----------------------------------------------------------------------===//
namespace {
namespace clang {
class PCHDeclReader : public DeclVisitor<PCHDeclReader, void> {
PCHReader &Reader;
const PCHReader::RecordData &Record;
@ -81,6 +81,7 @@ namespace {
void VisitLinkageSpecDecl(LinkageSpecDecl *D);
void VisitFileScopeAsmDecl(FileScopeAsmDecl *AD);
void VisitAccessSpecDecl(AccessSpecDecl *D);
void VisitFriendDecl(FriendDecl *D);
void VisitFriendTemplateDecl(FriendTemplateDecl *D);
void VisitStaticAssertDecl(StaticAssertDecl *D);
void VisitBlockDecl(BlockDecl *BD);
@ -673,6 +674,9 @@ void PCHDeclReader::VisitCXXRecordDecl(CXXRecordDecl *D) {
Bases.push_back(ReadCXXBaseSpecifier());
D->setBases(Bases.begin(), NumBases);
D->data().FirstFriend
= cast_or_null<FriendDecl>(Reader.GetDecl(Record[Idx++]));
// FIXME: there's a lot of stuff we do here that's kindof sketchy
// if we're leaving the context incomplete.
D->completeDefinition();
@ -704,6 +708,15 @@ void PCHDeclReader::VisitAccessSpecDecl(AccessSpecDecl *D) {
D->setColonLoc(Reader.ReadSourceLocation(Record, Idx));
}
void PCHDeclReader::VisitFriendDecl(FriendDecl *D) {
if (Record[Idx++])
D->Friend = Reader.GetTypeSourceInfo(Record, Idx);
else
D->Friend = cast<NamedDecl>(Reader.GetDecl(Record[Idx++]));
D->NextFriend = cast_or_null<FriendDecl>(Reader.GetDecl(Record[Idx++]));
D->FriendLoc = Reader.ReadSourceLocation(Record, Idx);
}
void PCHDeclReader::VisitFriendTemplateDecl(FriendTemplateDecl *D) {
assert(false && "cannot read FriendTemplateDecl");
}
@ -1204,7 +1217,7 @@ Decl *PCHReader::ReadDeclRecord(uint64_t Offset, unsigned Index) {
SourceLocation());
break;
case pch::DECL_FRIEND:
assert(false && "cannot read FriendDecl");
D = FriendDecl::Create(*Context, Decl::EmptyShell());
break;
case pch::DECL_FRIEND_TEMPLATE:
assert(false && "cannot read FriendTemplateDecl");

View File

@ -1444,11 +1444,16 @@ uint64_t PCHWriter::WriteDeclContextVisibleBlock(ASTContext &Context,
if (DC->getPrimaryContext() != DC)
return 0;
// Since there is no name lookup into functions or methods, and we
// perform name lookup for the translation unit via the
// IdentifierInfo chains, don't bother to build a
// visible-declarations table for these entities.
if (DC->isFunctionOrMethod() || DC->isTranslationUnit())
// Since there is no name lookup into functions or methods, don't bother to
// build a visible-declarations table for these entities.
if (DC->isFunctionOrMethod())
return 0;
// If not in C++, we perform name lookup for the translation unit via the
// IdentifierInfo chains, don't bother to build a visible-declarations table.
// FIXME: In C++ we need the visible declarations in order to "see" the
// friend declarations, is there a way to do this without writing the table ?
if (DC->isTranslationUnit() && !Context.getLangOptions().CPlusPlus)
return 0;
// Force the DeclContext to build a its name-lookup table.

View File

@ -25,7 +25,7 @@ using namespace clang;
// Declaration serialization
//===----------------------------------------------------------------------===//
namespace {
namespace clang {
class PCHDeclWriter : public DeclVisitor<PCHDeclWriter, void> {
PCHWriter &Writer;
@ -82,6 +82,7 @@ namespace {
void VisitLinkageSpecDecl(LinkageSpecDecl *D);
void VisitFileScopeAsmDecl(FileScopeAsmDecl *D);
void VisitAccessSpecDecl(AccessSpecDecl *D);
void VisitFriendDecl(FriendDecl *D);
void VisitFriendTemplateDecl(FriendTemplateDecl *D);
void VisitStaticAssertDecl(StaticAssertDecl *D);
void VisitBlockDecl(BlockDecl *D);
@ -636,7 +637,6 @@ void PCHDeclWriter::WriteCXXBaseSpecifier(const CXXBaseSpecifier *Base) {
}
void PCHDeclWriter::VisitCXXRecordDecl(CXXRecordDecl *D) {
// assert(false && "cannot write CXXRecordDecl");
VisitRecordDecl(D);
enum {
@ -664,6 +664,8 @@ void PCHDeclWriter::VisitCXXRecordDecl(CXXRecordDecl *D) {
for (CXXRecordDecl::base_class_iterator I = D->bases_begin(),
E = D->bases_end(); I != E; ++I)
WriteCXXBaseSpecifier(&*I);
Writer.AddDeclRef(D->data().FirstFriend, Record);
}
Code = pch::DECL_CXX_RECORD;
}
@ -698,6 +700,17 @@ void PCHDeclWriter::VisitAccessSpecDecl(AccessSpecDecl *D) {
Code = pch::DECL_ACCESS_SPEC;
}
void PCHDeclWriter::VisitFriendDecl(FriendDecl *D) {
Record.push_back(D->Friend.is<TypeSourceInfo*>());
if (D->Friend.is<TypeSourceInfo*>())
Writer.AddTypeSourceInfo(D->Friend.get<TypeSourceInfo*>(), Record);
else
Writer.AddDeclRef(D->Friend.get<NamedDecl*>(), Record);
Writer.AddDeclRef(D->NextFriend, Record);
Writer.AddSourceLocation(D->FriendLoc, Record);
Code = pch::DECL_FRIEND;
}
void PCHDeclWriter::VisitFriendTemplateDecl(FriendTemplateDecl *D) {
assert(false && "cannot write FriendTemplateDecl");
}

View File

@ -0,0 +1,13 @@
// Test this without pch.
// RUN: %clang_cc1 -include %S/cxx-friends.h -fsyntax-only -verify %s
// Test with pch.
// RUN: %clang_cc1 -x c++-header -emit-pch -o %t %S/cxx-friends.h
// RUN: %clang_cc1 -include-pch %t -fsyntax-only -verify %s
class F {
void m() {
A* a;
a->x = 0;
}
};

View File

@ -0,0 +1,6 @@
// Header for PCH test cxx-friends.cpp
class A {
int x;
friend class F;
};