aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArgyrios Kyrtzidis <akyrtzi@gmail.com>2010-06-29 22:47:00 +0000
committerArgyrios Kyrtzidis <akyrtzi@gmail.com>2010-06-29 22:47:00 +0000
commit6764334dfa73d67cbbb1b1fc8fe00440aad00f2a (patch)
tree2ef6ea36799089d92fdb3102551d0a178d67204d
parentd98a2ab9275f896df49e42ea4e4b8871610e0f45 (diff)
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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@107219 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/AST/DeclBase.h8
-rw-r--r--include/clang/AST/DeclCXX.h3
-rw-r--r--include/clang/AST/DeclFriend.h6
-rw-r--r--lib/AST/DeclFriend.cpp4
-rw-r--r--lib/Frontend/PCHReaderDecl.cpp17
-rw-r--r--lib/Frontend/PCHWriter.cpp15
-rw-r--r--lib/Frontend/PCHWriterDecl.cpp17
-rw-r--r--test/PCH/cxx-friends.cpp13
-rw-r--r--test/PCH/cxx-friends.h6
9 files changed, 80 insertions, 9 deletions
diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h
index fe091ad17b..f4d76f5241 100644
--- a/include/clang/AST/DeclBase.h
+++ b/include/clang/AST/DeclBase.h
@@ -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:
diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h
index b1b8d058f7..33f34fa524 100644
--- a/include/clang/AST/DeclCXX.h
+++ b/include/clang/AST/DeclCXX.h
@@ -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
diff --git a/include/clang/AST/DeclFriend.h b/include/clang/AST/DeclFriend.h
index a20625da56..85085c3080 100644
--- a/include/clang/AST/DeclFriend.h
+++ b/include/clang/AST/DeclFriend.h
@@ -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.
diff --git a/lib/AST/DeclFriend.cpp b/lib/AST/DeclFriend.cpp
index ab3552db28..99bfe40c31 100644
--- a/lib/AST/DeclFriend.cpp
+++ b/lib/AST/DeclFriend.cpp
@@ -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);
+}
diff --git a/lib/Frontend/PCHReaderDecl.cpp b/lib/Frontend/PCHReaderDecl.cpp
index 05cefa9ffe..9f057b0c1d 100644
--- a/lib/Frontend/PCHReaderDecl.cpp
+++ b/lib/Frontend/PCHReaderDecl.cpp
@@ -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");
diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp
index 8b714386c1..d947f7250d 100644
--- a/lib/Frontend/PCHWriter.cpp
+++ b/lib/Frontend/PCHWriter.cpp
@@ -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.
diff --git a/lib/Frontend/PCHWriterDecl.cpp b/lib/Frontend/PCHWriterDecl.cpp
index 42d506953c..309cc3536d 100644
--- a/lib/Frontend/PCHWriterDecl.cpp
+++ b/lib/Frontend/PCHWriterDecl.cpp
@@ -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");
}
diff --git a/test/PCH/cxx-friends.cpp b/test/PCH/cxx-friends.cpp
new file mode 100644
index 0000000000..a8d75586e4
--- /dev/null
+++ b/test/PCH/cxx-friends.cpp
@@ -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;
+ }
+};
diff --git a/test/PCH/cxx-friends.h b/test/PCH/cxx-friends.h
new file mode 100644
index 0000000000..2a33f15a53
--- /dev/null
+++ b/test/PCH/cxx-friends.h
@@ -0,0 +1,6 @@
+// Header for PCH test cxx-friends.cpp
+
+class A {
+ int x;
+ friend class F;
+};