diff --git a/clang/include/clang/AST/DeclBase.h b/clang/include/clang/AST/DeclBase.h index 8b3b0b9fb9a4b3932730116fdf18ec620cbefd4a..4c1fefef503e98cdf9966eb75440bab7a396c6fa 100644 --- a/clang/include/clang/AST/DeclBase.h +++ b/clang/include/clang/AST/DeclBase.h @@ -967,6 +967,7 @@ protected: mutable Decl *LastDecl; friend class ExternalASTSource; + friend class ASTWriter; /// \brief Build up a chain of declarations. /// diff --git a/clang/include/clang/Serialization/ASTReader.h b/clang/include/clang/Serialization/ASTReader.h index d0cdbeabbb56f46a15c676b3e1a028962dc832f2..9baaf4bcb52759da1eb4bfb44c10fa7e25cc97e9 100644 --- a/clang/include/clang/Serialization/ASTReader.h +++ b/clang/include/clang/Serialization/ASTReader.h @@ -1466,6 +1466,9 @@ public: void LoadMacroDefinition( llvm::DenseMap::iterator Pos); + /// \brief Load all external visible decls in the given DeclContext. + void completeVisibleDeclsMap(DeclContext *DC); + /// \brief Retrieve the AST context that this AST reader supplements. ASTContext &getContext() { return Context; } diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 4c6c9dc524c4a5e22fa26c60ca13fa0f8fe90e30..9436bfb50bd374e9d955ee4ca26e3ad337644488 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -4972,6 +4972,51 @@ ASTReader::FindExternalVisibleDeclsByName(const DeclContext *DC, return const_cast(DC)->lookup(Name); } +namespace { + /// \brief ModuleFile visitor used to complete the visible decls map of a + /// declaration context. + class DeclContextVisibleDeclMapVisitor { + ASTReader &Reader; + DeclContext *DC; + + public: + DeclContextVisibleDeclMapVisitor(ASTReader &Reader, DeclContext *DC) + : Reader(Reader), DC(DC) { } + + static bool visit(ModuleFile &M, void *UserData) { + return static_cast(UserData)->visit(M); + } + + bool visit(ModuleFile &M) { + // Check whether we have any visible declaration information for + // this context in this module. + ModuleFile::DeclContextInfosMap::iterator + Info = M.DeclContextInfos.find(DC); + if (Info == M.DeclContextInfos.end() || + !Info->second.NameLookupTableData) + return false; + + // Look for this name within this module. + ASTDeclContextNameLookupTable *LookupTable = + (ASTDeclContextNameLookupTable*)Info->second.NameLookupTableData; + for (ASTDeclContextNameLookupTable::key_iterator + I = LookupTable->key_begin(), + E = LookupTable->key_end(); I != E; ++I) { + DC->lookup(*I); // Force loading of the visible decls for the decl name. + } + + return false; + } + }; +} + +void ASTReader::completeVisibleDeclsMap(DeclContext *DC) { + if (!DC->hasExternalVisibleStorage()) + return; + DeclContextVisibleDeclMapVisitor Visitor(*this, DC); + ModuleMgr.visit(&DeclContextVisibleDeclMapVisitor::visit, &Visitor); +} + /// \brief Under non-PCH compilation the consumer receives the objc methods /// before receiving the implementation, and codegen depends on this. /// We simulate this by deserializing and passing to consumer the methods of the diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp index d7cc850a809e1ddda27dcefc285893e33ec0c788..7a4ef63bb3f6c46b74ca1f7550376c59cd7353a9 100644 --- a/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/clang/lib/Serialization/ASTWriterDecl.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "clang/Serialization/ASTWriter.h" +#include "clang/Serialization/ASTReader.h" #include "ASTCommon.h" #include "clang/AST/DeclVisitor.h" #include "clang/AST/DeclCXX.h" @@ -1640,6 +1641,20 @@ void ASTWriter::WriteDecl(ASTContext &Context, Decl *D) { RecordData Record; ASTDeclWriter W(*this, Context, Record); + // Determine the ID for this declaration. + serialization::DeclID ID; + if (D->isFromASTFile()) + ID = getDeclID(D); + else { + serialization::DeclID &IDR = DeclIDs[D]; + if (IDR == 0) + IDR = NextDeclID++; + + ID= IDR; + } + + bool isReplacingADecl = ID < FirstDeclID; + // If this declaration is also a DeclContext, write blocks for the // declarations that lexically stored inside its context and those // declarations that are visible from its context. These blocks @@ -1649,23 +1664,19 @@ void ASTWriter::WriteDecl(ASTContext &Context, Decl *D) { uint64_t VisibleOffset = 0; DeclContext *DC = dyn_cast(D); if (DC) { + if (isReplacingADecl) { + // It is replacing a decl from a chained PCH; make sure that the + // DeclContext is fully loaded. + if (DC->hasExternalLexicalStorage()) + DC->LoadLexicalDeclsFromExternalStorage(); + if (DC->hasExternalVisibleStorage()) + Chain->completeVisibleDeclsMap(DC); + } LexicalOffset = WriteDeclContextLexicalBlock(Context, DC); VisibleOffset = WriteDeclContextVisibleBlock(Context, DC); } - - // Determine the ID for this declaration. - serialization::DeclID ID; - if (D->isFromASTFile()) - ID = getDeclID(D); - else { - serialization::DeclID &IDR = DeclIDs[D]; - if (IDR == 0) - IDR = NextDeclID++; - - ID= IDR; - } - if (ID < FirstDeclID) { + if (isReplacingADecl) { // We're replacing a decl in a previous file. ReplacedDecls.push_back(ReplacedDeclInfo(ID, Stream.GetCurrentBitNo(), D->getLocation())); diff --git a/clang/test/PCH/chain-class-extension.m b/clang/test/PCH/chain-class-extension.m new file mode 100644 index 0000000000000000000000000000000000000000..c99d6d43ae5e280d2fe897108cf3ca82fa3c23a7 --- /dev/null +++ b/clang/test/PCH/chain-class-extension.m @@ -0,0 +1,42 @@ +// Without PCH +// RUN: %clang_cc1 -fsyntax-only -verify -triple x86_64-apple-darwin10 -fobjc-arc %s -include %s -include %s + +// With PCH +// RUN: %clang_cc1 -fsyntax-only -verify -triple x86_64-apple-darwin10 -fobjc-arc %s -chain-include %s -chain-include %s + +#ifndef HEADER1 +#define HEADER1 +//===----------------------------------------------------------------------===// +// Primary header + +@interface I ++(void)meth; +@end + +//===----------------------------------------------------------------------===// +#elif !defined(HEADER2) +#define HEADER2 +#if !defined(HEADER1) +#error Header inclusion order messed up +#endif + +//===----------------------------------------------------------------------===// +// Dependent header + +@interface I() +@property (assign) id prop; ++(void)meth2; +@end + +//===----------------------------------------------------------------------===// +#else +//===----------------------------------------------------------------------===// + +void foo(I *i) { + [I meth]; + [I meth2]; + i.prop = 0; +} + +//===----------------------------------------------------------------------===// +#endif