From e565bfa2d67a3b5e02412b4fde5b28873ff7b8d8 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Thu, 23 May 2013 01:49:11 +0000 Subject: [PATCH] Fix bitcode desynchronization when loading a PCH containing a class template specialization with modules enabled. Just don't merge them at all for now; we'll revisit this when support for template merging is added. In passing, make Decl::dump() a little safer to use with PCH/modules, by making it not deserialize any additional declarations. From a debugger you can call decls_begin() or similar first if you want to dump all child decls. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@182544 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/AST/ASTDumper.cpp | 17 ++++++-- lib/Serialization/ASTReaderDecl.cpp | 53 ++++++++++++++++++------- test/PCH/chain-cxx.cpp | 3 ++ test/PCH/chain-friend-instantiation.cpp | 1 + 4 files changed, 56 insertions(+), 18 deletions(-) diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index 8cf41f5db6..2ed36455bb 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -62,6 +62,9 @@ namespace { // Null statements static const TerminalColor NullColor = { raw_ostream::BLUE, false }; + // Undeserialized entities + static const TerminalColor UndeserializedColor = { raw_ostream::GREEN, true }; + // CastKind from CastExpr's static const TerminalColor CastColor = { raw_ostream::RED, false }; @@ -477,20 +480,28 @@ bool ASTDumper::hasNodes(const DeclContext *DC) { if (!DC) return false; - return DC->decls_begin() != DC->decls_end(); + return DC->hasExternalLexicalStorage() || + DC->noload_decls_begin() != DC->noload_decls_end(); } void ASTDumper::dumpDeclContext(const DeclContext *DC) { if (!DC) return; - for (DeclContext::decl_iterator I = DC->decls_begin(), E = DC->decls_end(); + bool HasUndeserializedDecls = DC->hasExternalLexicalStorage(); + for (DeclContext::decl_iterator I = DC->noload_decls_begin(), E = DC->noload_decls_end(); I != E; ++I) { DeclContext::decl_iterator Next = I; ++Next; - if (Next == E) + if (Next == E && !HasUndeserializedDecls) lastChild(); dumpDecl(*I); } + if (HasUndeserializedDecls) { + lastChild(); + IndentScope Indent(*this); + ColorScope Color(*this, UndeserializedColor); + OS << ""; + } } void ASTDumper::dumpAttr(const Attr *A) { diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index 11c82daaf5..6eed40c951 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/lib/Serialization/ASTReaderDecl.cpp @@ -223,12 +223,18 @@ namespace clang { void VisitTypedefDecl(TypedefDecl *TD); void VisitTypeAliasDecl(TypeAliasDecl *TD); void VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D); - void VisitTagDecl(TagDecl *TD); + RedeclarableResult VisitTagDecl(TagDecl *TD); void VisitEnumDecl(EnumDecl *ED); - void VisitRecordDecl(RecordDecl *RD); - void VisitCXXRecordDecl(CXXRecordDecl *D); - void VisitClassTemplateSpecializationDecl( + RedeclarableResult VisitRecordDeclImpl(RecordDecl *RD); + void VisitRecordDecl(RecordDecl *RD) { VisitRecordDeclImpl(RD); } + RedeclarableResult VisitCXXRecordDeclImpl(CXXRecordDecl *D); + void VisitCXXRecordDecl(CXXRecordDecl *D) { VisitCXXRecordDeclImpl(D); } + RedeclarableResult VisitClassTemplateSpecializationDeclImpl( ClassTemplateSpecializationDecl *D); + void VisitClassTemplateSpecializationDecl( + ClassTemplateSpecializationDecl *D) { + VisitClassTemplateSpecializationDeclImpl(D); + } void VisitClassTemplatePartialSpecializationDecl( ClassTemplatePartialSpecializationDecl *D); void VisitClassScopeFunctionSpecializationDecl( @@ -424,7 +430,7 @@ void ASTDeclReader::VisitTypeAliasDecl(TypeAliasDecl *TD) { VisitTypedefNameDecl(TD); } -void ASTDeclReader::VisitTagDecl(TagDecl *TD) { +ASTDeclReader::RedeclarableResult ASTDeclReader::VisitTagDecl(TagDecl *TD) { RedeclarableResult Redecl = VisitRedeclarable(TD); VisitTypeDecl(TD); @@ -442,7 +448,8 @@ void ASTDeclReader::VisitTagDecl(TagDecl *TD) { } else TD->setTypedefNameForAnonDecl(ReadDeclAs(Record, Idx)); - mergeRedeclarable(TD, Redecl); + mergeRedeclarable(TD, Redecl); + return Redecl; } void ASTDeclReader::VisitEnumDecl(EnumDecl *ED) { @@ -466,12 +473,14 @@ void ASTDeclReader::VisitEnumDecl(EnumDecl *ED) { } } -void ASTDeclReader::VisitRecordDecl(RecordDecl *RD) { - VisitTagDecl(RD); +ASTDeclReader::RedeclarableResult +ASTDeclReader::VisitRecordDeclImpl(RecordDecl *RD) { + RedeclarableResult Redecl = VisitTagDecl(RD); RD->setHasFlexibleArrayMember(Record[Idx++]); RD->setAnonymousStructOrUnion(Record[Idx++]); RD->setHasObjectMember(Record[Idx++]); RD->setHasVolatileMember(Record[Idx++]); + return Redecl; } void ASTDeclReader::VisitValueDecl(ValueDecl *VD) { @@ -1022,6 +1031,7 @@ void ASTDeclReader::VisitNamespaceDecl(NamespaceDecl *D) { D->setInline(Record[Idx++]); D->LocStart = ReadSourceLocation(Record, Idx); D->RBraceLoc = ReadSourceLocation(Record, Idx); + // FIXME: At the point of this call, D->getCanonicalDecl() returns 0. mergeRedeclarable(D, Redecl); if (Redecl.getFirstID() == ThisDeclID) { @@ -1180,8 +1190,9 @@ void ASTDeclReader::ReadCXXDefinitionData( } } -void ASTDeclReader::VisitCXXRecordDecl(CXXRecordDecl *D) { - VisitRecordDecl(D); +ASTDeclReader::RedeclarableResult +ASTDeclReader::VisitCXXRecordDeclImpl(CXXRecordDecl *D) { + RedeclarableResult Redecl = VisitRecordDeclImpl(D); ASTContext &C = Reader.getContext(); if (Record[Idx++]) { @@ -1236,6 +1247,8 @@ void ASTDeclReader::VisitCXXRecordDecl(CXXRecordDecl *D) { if (CXXMethodDecl *Key = ReadDeclAs(Record, Idx)) C.KeyFunctions[D] = Key; } + + return Redecl; } void ASTDeclReader::VisitCXXMethodDecl(CXXMethodDecl *D) { @@ -1391,9 +1404,10 @@ void ASTDeclReader::VisitClassTemplateDecl(ClassTemplateDecl *D) { } } -void ASTDeclReader::VisitClassTemplateSpecializationDecl( - ClassTemplateSpecializationDecl *D) { - VisitCXXRecordDecl(D); +ASTDeclReader::RedeclarableResult +ASTDeclReader::VisitClassTemplateSpecializationDeclImpl( + ClassTemplateSpecializationDecl *D) { + RedeclarableResult Redecl = VisitCXXRecordDeclImpl(D); ASTContext &C = Reader.getContext(); if (Decl *InstD = ReadDecl(Record, Idx)) { @@ -1444,11 +1458,13 @@ void ASTDeclReader::VisitClassTemplateSpecializationDecl( } } } + + return Redecl; } void ASTDeclReader::VisitClassTemplatePartialSpecializationDecl( ClassTemplatePartialSpecializationDecl *D) { - VisitClassTemplateSpecializationDecl(D); + RedeclarableResult Redecl = VisitClassTemplateSpecializationDeclImpl(D); ASTContext &C = Reader.getContext(); D->TemplateParams = Reader.ReadTemplateParameterList(F, Record, Idx); @@ -1464,7 +1480,7 @@ void ASTDeclReader::VisitClassTemplatePartialSpecializationDecl( D->SequenceNumber = Record[Idx++]; // These are read/set from/to the first declaration. - if (D->getPreviousDecl() == 0) { + if (ThisDeclID == Redecl.getFirstID()) { D->InstantiatedFromMember.setPointer( ReadDeclAs(Record, Idx)); D->InstantiatedFromMember.setInt(Record[Idx++]); @@ -1780,6 +1796,13 @@ static bool isSameEntity(NamedDecl *X, NamedDecl *Y) { // Objective-C classes and protocols with the same name always match. if (isa(X) || isa(X)) return true; + + if (isa(X)) { + // FIXME: Deal with merging of template specializations. + // For now, don't merge these; we need to check more than just the name to + // determine if they refer to the same entity. + return false; + } // Compatible tags match. if (TagDecl *TagX = dyn_cast(X)) { diff --git a/test/PCH/chain-cxx.cpp b/test/PCH/chain-cxx.cpp index 4b64f51143..6e9c1743fb 100644 --- a/test/PCH/chain-cxx.cpp +++ b/test/PCH/chain-cxx.cpp @@ -6,6 +6,9 @@ // With PCH // RUN: %clang_cc1 -fsyntax-only -verify %s -chain-include %s -chain-include %s +// With modules +// RUN: %clang_cc1 -fsyntax-only -verify -fmodules %s -chain-include %s -chain-include %s + // expected-no-diagnostics #ifndef HEADER1 diff --git a/test/PCH/chain-friend-instantiation.cpp b/test/PCH/chain-friend-instantiation.cpp index 294d979112..2f042a8341 100644 --- a/test/PCH/chain-friend-instantiation.cpp +++ b/test/PCH/chain-friend-instantiation.cpp @@ -1,4 +1,5 @@ // RUN: %clang_cc1 %s -ast-print -o - -chain-include %s -chain-include %s +// RUN: %clang_cc1 %s -ast-print -o - -fmodules -chain-include %s -chain-include %s #if !defined(PASS1) #define PASS1