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