r184904 - Lazily deserialize the "first' friend declaration when deserializing a class

Richard Smith richard-llvm at metafoo.co.uk
Tue Jun 25 19:41:25 PDT 2013


Author: rsmith
Date: Tue Jun 25 21:41:25 2013
New Revision: 184904

URL: http://llvm.org/viewvc/llvm-project?rev=184904&view=rev
Log:
Lazily deserialize the "first' friend declaration when deserializing a class
declaration. This PCH a little lazier, and breaks a deserialization cycle that
causes crashes with modules enabled.

Modified:
    cfe/trunk/include/clang/AST/DeclCXX.h
    cfe/trunk/include/clang/AST/DeclFriend.h
    cfe/trunk/lib/AST/DeclCXX.cpp
    cfe/trunk/lib/AST/DeclFriend.cpp
    cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
    cfe/trunk/lib/Serialization/ASTWriter.cpp
    cfe/trunk/test/PCH/cxx-friends.cpp
    cfe/trunk/test/PCH/cxx-friends.h

Modified: cfe/trunk/include/clang/AST/DeclCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=184904&r1=184903&r2=184904&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclCXX.h (original)
+++ cfe/trunk/include/clang/AST/DeclCXX.h Tue Jun 25 21:41:25 2013
@@ -482,7 +482,7 @@ class CXXRecordDecl : public RecordDecl
     /// FirstFriend - The first friend declaration in this class, or
     /// null if there aren't any.  This is actually currently stored
     /// in reverse order.
-    FriendDecl *FirstFriend;
+    LazyDeclPtr FirstFriend;
 
     /// \brief Retrieve the set of direct base classes.
     CXXBaseSpecifier *getBases() const {
@@ -597,6 +597,10 @@ class CXXRecordDecl : public RecordDecl
 
   friend class ASTNodeImporter;
 
+  /// \brief Get the head of our list of friend declarations, possibly
+  /// deserializing the friends from an external AST source.
+  FriendDecl *getFirstFriend() const;
+
 protected:
   CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC,
                 SourceLocation StartLoc, SourceLocation IdLoc,
@@ -749,7 +753,7 @@ public:
 
   /// Determines whether this record has any friends.
   bool hasFriends() const {
-    return data().FirstFriend != 0;
+    return data().FirstFriend.isValid();
   }
 
   /// \brief \c true if we know for sure that this class has a single,

Modified: cfe/trunk/include/clang/AST/DeclFriend.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclFriend.h?rev=184904&r1=184903&r2=184904&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclFriend.h (original)
+++ cfe/trunk/include/clang/AST/DeclFriend.h Tue Jun 25 21:41:25 2013
@@ -220,7 +220,7 @@ public:
 };
 
 inline CXXRecordDecl::friend_iterator CXXRecordDecl::friend_begin() const {
-  return friend_iterator(data().FirstFriend);
+  return friend_iterator(getFirstFriend());
 }
 
 inline CXXRecordDecl::friend_iterator CXXRecordDecl::friend_end() const {

Modified: cfe/trunk/lib/AST/DeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=184904&r1=184903&r2=184904&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)
+++ cfe/trunk/lib/AST/DeclCXX.cpp Tue Jun 25 21:41:25 2013
@@ -62,7 +62,7 @@ CXXRecordDecl::DefinitionData::Definitio
     HasDeclaredCopyAssignmentWithConstParam(false),
     FailedImplicitMoveConstructor(false), FailedImplicitMoveAssignment(false),
     IsLambda(false), NumBases(0), NumVBases(0), Bases(), VBases(),
-    Definition(D), FirstFriend(0) {
+    Definition(D), FirstFriend() {
 }
 
 CXXBaseSpecifier *CXXRecordDecl::DefinitionData::getBasesSlowCase() const {

Modified: cfe/trunk/lib/AST/DeclFriend.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclFriend.cpp?rev=184904&r1=184903&r2=184904&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclFriend.cpp (original)
+++ cfe/trunk/lib/AST/DeclFriend.cpp Tue Jun 25 21:41:25 2013
@@ -63,3 +63,8 @@ FriendDecl *FriendDecl::CreateDeserializ
   return new (Mem) FriendDecl(EmptyShell(), FriendTypeNumTPLists);
 }
 
+FriendDecl *CXXRecordDecl::getFirstFriend() const {
+  ExternalASTSource *Source = getParentASTContext().getExternalSource();
+  Decl *First = data().FirstFriend.get(Source);
+  return First ? cast<FriendDecl>(First) : 0;
+}

Modified: cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderDecl.cpp?rev=184904&r1=184903&r2=184904&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReaderDecl.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReaderDecl.cpp Tue Jun 25 21:41:25 2013
@@ -1156,7 +1156,7 @@ void ASTDeclReader::ReadCXXDefinitionDat
   Reader.ReadUnresolvedSet(F, Data.Conversions, Record, Idx);
   Reader.ReadUnresolvedSet(F, Data.VisibleConversions, Record, Idx);
   assert(Data.Definition && "Data.Definition should be already set!");
-  Data.FirstFriend = ReadDeclAs<FriendDecl>(Record, Idx);
+  Data.FirstFriend = Record[Idx++];
   
   if (Data.IsLambda) {
     typedef LambdaExpr::Capture Capture;

Modified: cfe/trunk/lib/Serialization/ASTWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=184904&r1=184903&r2=184904&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTWriter.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTWriter.cpp Tue Jun 25 21:41:25 2013
@@ -5054,7 +5054,7 @@ void ASTWriter::AddCXXDefinitionData(con
   AddUnresolvedSet(Data.Conversions, Record);
   AddUnresolvedSet(Data.VisibleConversions, Record);
   // Data.Definition is the owning decl, no need to write it. 
-  AddDeclRef(Data.FirstFriend, Record);
+  AddDeclRef(D->getFirstFriend(), Record);
   
   // Add lambda-specific data.
   if (Data.IsLambda) {

Modified: cfe/trunk/test/PCH/cxx-friends.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/cxx-friends.cpp?rev=184904&r1=184903&r2=184904&view=diff
==============================================================================
--- cfe/trunk/test/PCH/cxx-friends.cpp (original)
+++ cfe/trunk/test/PCH/cxx-friends.cpp Tue Jun 25 21:41:25 2013
@@ -3,7 +3,11 @@
 
 // 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 
+// RUN: %clang_cc1 -include-pch %t -fsyntax-only -verify %s -error-on-deserialized-decl doNotDeserialize
+
+// Test with modules.
+// RUN: %clang_cc1 -x c++-header -emit-pch -o %t %S/cxx-friends.h -fmodules
+// RUN: %clang_cc1 -include-pch %t -fsyntax-only -verify %s -error-on-deserialized-decl doNotDeserialize -fmodules
 
 // expected-no-diagnostics
 
@@ -21,3 +25,5 @@ public:
   }
 };
 int k = PR12585::future_base::setter<int>().f();
+
+Lazy::S *p;

Modified: cfe/trunk/test/PCH/cxx-friends.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/cxx-friends.h?rev=184904&r1=184903&r2=184904&view=diff
==============================================================================
--- cfe/trunk/test/PCH/cxx-friends.h (original)
+++ cfe/trunk/test/PCH/cxx-friends.h Tue Jun 25 21:41:25 2013
@@ -16,3 +16,28 @@ namespace PR12585 {
     int k;
   };
 }
+
+namespace Lazy {
+  struct S {
+    friend void doNotDeserialize();
+  };
+}
+
+// Reduced testcase from libc++'s <valarray>. Used to crash with modules
+// enabled.
+namespace std {
+
+template <class T> struct valarray;
+
+template <class T> struct valarray {
+  valarray();
+  template <class U> friend struct valarray;
+  template <class U> friend U *begin(valarray<U> &v);
+};
+
+struct gslice {
+  valarray<int> size;
+  gslice() {}
+};
+
+}





More information about the cfe-commits mailing list