]> granicus.if.org Git - clang/commitdiff
Support C++ friend declarations for PCH.
authorArgyrios Kyrtzidis <akyrtzi@gmail.com>
Tue, 29 Jun 2010 22:47:00 +0000 (22:47 +0000)
committerArgyrios Kyrtzidis <akyrtzi@gmail.com>
Tue, 29 Jun 2010 22:47:00 +0000 (22:47 +0000)
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

include/clang/AST/DeclBase.h
include/clang/AST/DeclCXX.h
include/clang/AST/DeclFriend.h
lib/AST/DeclFriend.cpp
lib/Frontend/PCHReaderDecl.cpp
lib/Frontend/PCHWriter.cpp
lib/Frontend/PCHWriterDecl.cpp
test/PCH/cxx-friends.cpp [new file with mode: 0644]
test/PCH/cxx-friends.h [new file with mode: 0644]

index fe091ad17bc4e143095a1d89935b6b7e9f4017cb..f4d76f52419b5cdc15e47f9c69e940a82eccb1cb 100644 (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:
index b1b8d058f77556c675d8ebb99bd99aa7a6dcbc74..33f34fa524da26314f05d5486072a8d70f5c716e 100644 (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
index a20625da56b7def8fb10dc59e22cf68fd4099a0e..85085c3080b5e723c7733ebdccf1b8e31bd646b4 100644 (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.
index ab3552db28e0c58744d1aa062f04ad19e0faeb81..99bfe40c31f4ab440dd76d69d81eb54bb67cdbdf 100644 (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);
+}
index 05cefa9ffeb6f6b43ab6632d73982eec72177707..9f057b0c1dc318e7b4b0c9fd7e1c1587f5c1ecab 100644 (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");
index 8b714386c112711b0e6ffbd7db22433659bb05de..d947f7250d2a44105f278ddff6af6e6ef97b0ea1 100644 (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.
index 42d506953cb54ae9191b1fa316ac4c8d2f6ed3b5..309cc3536d9baa0e99d6e266b61fe78f068b1bc0 100644 (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");
 }
diff --git a/test/PCH/cxx-friends.cpp b/test/PCH/cxx-friends.cpp
new file mode 100644 (file)
index 0000000..a8d7558
--- /dev/null
@@ -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 (file)
index 0000000..2a33f15
--- /dev/null
@@ -0,0 +1,6 @@
+// Header for PCH test cxx-friends.cpp
+
+class A {
+  int x;
+  friend class F;
+};