]> granicus.if.org Git - clang/commitdiff
Lazily deserialize the "first' friend declaration when deserializing a class
authorRichard Smith <richard-llvm@metafoo.co.uk>
Wed, 26 Jun 2013 02:41:25 +0000 (02:41 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Wed, 26 Jun 2013 02:41:25 +0000 (02:41 +0000)
declaration. This PCH a little lazier, and breaks a deserialization cycle that
causes crashes with modules enabled.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@184904 91177308-0d34-0410-b5e6-96231b3b80d8

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

index 9722ad8427aab84e289d178b8138e6569073af01..2de99f0925cf617c9fea8e031019a390fea9807f 100644 (file)
@@ -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,
index 589178ec6ec368dedf7290b91e46411e5bdbda96..be6f2eb3e3ad251f2c1ceeeb89951a61c1853db5 100644 (file)
@@ -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 {
index df8a52675be5414e0416afd8bff46e685bd0b41d..910809575b4e01e8570fcf89ae844737ebaf1031 100644 (file)
@@ -62,7 +62,7 @@ CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D)
     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 {
index 37a812e71aae0b1c4b098d69ee09275f141e90fe..1c639d676dc982961cf9ca996bd1f591f0d9138b 100644 (file)
@@ -63,3 +63,8 @@ FriendDecl *FriendDecl::CreateDeserialized(ASTContext &C, unsigned ID,
   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;
+}
index df6abc934f99882b414584f6a0b87af66c500ee3..e93eae81127813c944b10ca1732feb38c1d8a40e 100644 (file)
@@ -1156,7 +1156,7 @@ void ASTDeclReader::ReadCXXDefinitionData(
   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;
index 4a4128b4cfdc062749cec9141a0dca0ee5ce1e23..bf01e9c2f27cac5d0a857862276b235147d12d6d 100644 (file)
@@ -5054,7 +5054,7 @@ void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Rec
   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) {
index f7d45cea8df4abc252c4b3d006bcf202087c8873..9c75f92f34d6d9a5b28b1445b2f342416699b899 100644 (file)
@@ -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;
index 05dcc9606636b4314b5f2e85d2b70482cc8e18d5..2d20a4d26978dc16e8f6f5f96e64820c3ee06fbe 100644 (file)
@@ -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() {}
+};
+
+}