From 1b59e9c3e1780567e30e5ead2b3512f0aa21fcb6 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Thu, 25 Aug 2011 15:28:26 +0000 Subject: [PATCH] Remove a bogus assertion from the AST reader, which assumed that redeclarations of a particular entity would occur in source order. Friend declarations that occur within class templates (or member classes thereof) do not follow this, nor would modules. Big thanks to Erik Verbruggen for reducing this problem from the Very Large Qt preamble testcase he found. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@138557 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Serialization/ASTReaderDecl.cpp | 18 +++----- test/PCH/chain-friend-instantiation.cpp | 61 +++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 12 deletions(-) create mode 100644 test/PCH/chain-friend-instantiation.cpp diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index ab46e0a096..6e7cbbf9b0 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/lib/Serialization/ASTReaderDecl.cpp @@ -123,8 +123,8 @@ namespace clang { ClassTemplateSpecializationDecl *D); void VisitClassTemplatePartialSpecializationDecl( ClassTemplatePartialSpecializationDecl *D); - void VisitClassScopeFunctionSpecializationDecl( - ClassScopeFunctionSpecializationDecl *D); + void VisitClassScopeFunctionSpecializationDecl( + ClassScopeFunctionSpecializationDecl *D); void VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D); void VisitValueDecl(ValueDecl *VD); void VisitEnumConstantDecl(EnumConstantDecl *ECD); @@ -1087,14 +1087,8 @@ void ASTDeclReader::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) { ASTReader::FirstLatestDeclIDMap::iterator I = Reader.FirstLatestDeclIDs.find(ThisDeclID); if (I != Reader.FirstLatestDeclIDs.end()) { - Decl *NewLatest = Reader.GetDecl(I->second); - assert((LatestDecl->getLocation().isInvalid() || - NewLatest->getLocation().isInvalid() || - !Reader.SourceMgr.isBeforeInTranslationUnit( - NewLatest->getLocation(), - LatestDecl->getLocation())) && - "The new latest is supposed to come after the previous latest"); - LatestDecl = cast(NewLatest); + if (Decl *NewLatest = Reader.GetDecl(I->second)) + LatestDecl = cast(NewLatest); } assert(LatestDecl->getKind() == D->getKind() && "Latest kind mismatch"); @@ -1217,8 +1211,8 @@ void ASTDeclReader::VisitClassTemplatePartialSpecializationDecl( } } -void ASTDeclReader::VisitClassScopeFunctionSpecializationDecl( - ClassScopeFunctionSpecializationDecl *D) { +void ASTDeclReader::VisitClassScopeFunctionSpecializationDecl( + ClassScopeFunctionSpecializationDecl *D) { VisitDecl(D); D->Specialization = ReadDeclAs(Record, Idx); } diff --git a/test/PCH/chain-friend-instantiation.cpp b/test/PCH/chain-friend-instantiation.cpp new file mode 100644 index 0000000000..294d979112 --- /dev/null +++ b/test/PCH/chain-friend-instantiation.cpp @@ -0,0 +1,61 @@ +// RUN: %clang_cc1 %s -ast-print -o - -chain-include %s -chain-include %s + +#if !defined(PASS1) +#define PASS1 + +template class TClass; + +namespace NS { + template TClass problematic(X * ptr, const TClass &src); + + template + class TBaseClass + { + protected: + template friend TClass problematic(X * ptr, const TClass &src); + }; +} + +template +class TClass: public NS::TBaseClass +{ +public: + inline TClass() { } +}; + + +namespace NS { + template + TClass problematic(X *ptr, const TClass &src); +} + +template +TClass unconst(const TClass &src); + +#elif !defined(PASS2) +#define PASS2 + +namespace std { +class s {}; +} + + +typedef TClass TStr; + +struct crash { + TStr str; + + crash(const TClass p) + { + unconst(p); + } +}; + +#else + +void f() { + const TStr p; + crash c(p); +} + +#endif -- 2.50.1