diff options
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/AST/ASTContext.cpp | 18 | ||||
-rw-r--r-- | clang/lib/AST/DeclBase.cpp | 112 | ||||
-rw-r--r-- | clang/lib/Frontend/PCHReader.cpp | 602 | ||||
-rw-r--r-- | clang/lib/Frontend/PCHWriter.cpp | 636 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 6 | ||||
-rw-r--r-- | clang/lib/Sema/SemaLookup.cpp | 11 |
6 files changed, 1384 insertions, 1 deletions
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index deeb7631917..7da1bf080c4 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -16,6 +16,7 @@ #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" +#include "clang/AST/ExternalASTSource.h" #include "clang/AST/RecordLayout.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" @@ -36,7 +37,8 @@ ASTContext::ASTContext(const LangOptions& LOpts, SourceManager &SM, bool FreeMem, unsigned size_reserve) : GlobalNestedNameSpecifier(0), CFConstantStringTypeDecl(0), ObjCFastEnumerationStateTypeDecl(0), SourceMgr(SM), LangOpts(LOpts), - FreeMemory(FreeMem), Target(t), Idents(idents), Selectors(sels) { + FreeMemory(FreeMem), Target(t), Idents(idents), Selectors(sels), + ExternalSource(0) { if (size_reserve > 0) Types.reserve(size_reserve); InitBuiltinTypes(); BuiltinInfo.InitializeBuiltins(idents, Target, LangOpts.NoBuiltin); @@ -91,6 +93,11 @@ ASTContext::~ASTContext() { TUDecl->Destroy(*this); } +void +ASTContext::setExternalSource(llvm::OwningPtr<ExternalASTSource> &Source) { + ExternalSource.reset(Source.take()); +} + void ASTContext::PrintStats() const { fprintf(stderr, "*** AST Context Stats:\n"); fprintf(stderr, " %d types total.\n", (int)Types.size()); @@ -195,6 +202,11 @@ void ASTContext::PrintStats() const { NumTypeName*sizeof(TypedefType)+NumTagged*sizeof(TagType)+ NumTypeOfTypes*sizeof(TypeOfType)+NumTypeOfExprTypes*sizeof(TypeOfExprType)+ NumExtQual*sizeof(ExtQualType))); + + if (ExternalSource.get()) { + fprintf(stderr, "\n"); + ExternalSource->PrintStats(); + } } @@ -3359,3 +3371,7 @@ ASTContext* ASTContext::Create(llvm::Deserializer& D) { return A; } + +ExternalASTSource::~ExternalASTSource() { } + +void ExternalASTSource::PrintStats() { } diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp index 763998e852e..be349428ecf 100644 --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -17,6 +17,7 @@ #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" +#include "clang/AST/ExternalASTSource.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Type.h" #include "llvm/ADT/DenseMap.h" @@ -439,11 +440,82 @@ DeclContext *DeclContext::getNextContext() { } } +/// \brief Load the declarations within this lexical storage from an +/// external source. +void +DeclContext::LoadLexicalDeclsFromExternalStorage(ASTContext &Context) const { + ExternalASTSource *Source = Context.getExternalSource(); + assert(hasExternalLexicalStorage() && Source && "No external storage?"); + + llvm::SmallVector<unsigned, 64> Decls; + if (Source->ReadDeclsLexicallyInContext(const_cast<DeclContext *>(this), + Decls)) + return; + + // There is no longer any lexical storage in this context + ExternalLexicalStorage = false; + + if (Decls.empty()) + return; + + // Resolve all of the declaration IDs into declarations, building up + // a chain of declarations via the Decl::NextDeclInContext field. + Decl *FirstNewDecl = 0; + Decl *PrevDecl = 0; + for (unsigned I = 0, N = Decls.size(); I != N; ++I) { + Decl *D = Source->GetDecl(Decls[I]); + if (PrevDecl) + PrevDecl->NextDeclInContext = D; + else + FirstNewDecl = D; + + PrevDecl = D; + } + + // Splice the newly-read declarations into the beginning of the list + // of declarations. + PrevDecl->NextDeclInContext = FirstDecl; + FirstDecl = FirstNewDecl; + if (!LastDecl) + LastDecl = PrevDecl; +} + +void +DeclContext::LoadVisibleDeclsFromExternalStorage(ASTContext &Context) const { + DeclContext *This = const_cast<DeclContext *>(this); + ExternalASTSource *Source = Context.getExternalSource(); + assert(hasExternalVisibleStorage() && Source && "No external storage?"); + + llvm::SmallVector<VisibleDeclaration, 64> Decls; + if (Source->ReadDeclsVisibleInContext(This, Decls)) + return; + + // There is no longer any visible storage in this context + ExternalVisibleStorage = false; + + // Load the declaration IDs for all of the names visible in this + // context. + assert(!LookupPtr && "Have a lookup map before de-serialization?"); + StoredDeclsMap *Map = new StoredDeclsMap; + LookupPtr = Map; + for (unsigned I = 0, N = Decls.size(); I != N; ++I) { + (*Map)[Decls[I].Name].setFromDeclIDs(Decls[I].Declarations); + } +} + DeclContext::decl_iterator DeclContext::decls_begin(ASTContext &Context) const { + if (hasExternalLexicalStorage()) + LoadLexicalDeclsFromExternalStorage(Context); + + // FIXME: Check whether we need to load some declarations from + // external storage. return decl_iterator(FirstDecl); } DeclContext::decl_iterator DeclContext::decls_end(ASTContext &Context) const { + if (hasExternalLexicalStorage()) + LoadLexicalDeclsFromExternalStorage(Context); + return decl_iterator(); } @@ -491,6 +563,9 @@ DeclContext::lookup(ASTContext &Context, DeclarationName Name) { if (PrimaryContext != this) return PrimaryContext->lookup(Context, Name); + if (hasExternalVisibleStorage()) + LoadVisibleDeclsFromExternalStorage(Context); + /// If there is no lookup data structure, build one now by walking /// all of the linked DeclContexts (in declaration order!) and /// inserting their values. @@ -595,3 +670,40 @@ DeclContext::getUsingDirectives(ASTContext &Context) const { return udir_iterator_range(reinterpret_cast<udir_iterator>(Result.first), reinterpret_cast<udir_iterator>(Result.second)); } + +void StoredDeclsList::materializeDecls(ASTContext &Context) { + if (isNull()) + return; + + switch ((DataKind)(Data & 0x03)) { + case DK_Decl: + case DK_Decl_Vector: + break; + + case DK_DeclID: { + // Resolve this declaration ID to an actual declaration by + // querying the external AST source. + unsigned DeclID = Data >> 2; + + ExternalASTSource *Source = Context.getExternalSource(); + assert(Source && "No external AST source available!"); + + Data = reinterpret_cast<uintptr_t>(Source->GetDecl(DeclID)); + break; + } + + case DK_ID_Vector: { + // We have a vector of declaration IDs. Resolve all of them to + // actual declarations. + VectorTy &Vector = *getAsVector(); + ExternalASTSource *Source = Context.getExternalSource(); + assert(Source && "No external AST source available!"); + + for (unsigned I = 0, N = Vector.size(); I != N; ++I) + Vector[I] = reinterpret_cast<uintptr_t>(Source->GetDecl(Vector[I])); + + Data = (Data & ~0x03) | DK_Decl_Vector; + break; + } + } +} diff --git a/clang/lib/Frontend/PCHReader.cpp b/clang/lib/Frontend/PCHReader.cpp new file mode 100644 index 00000000000..d366cddf175 --- /dev/null +++ b/clang/lib/Frontend/PCHReader.cpp @@ -0,0 +1,602 @@ +//===--- PCHReader.cpp - Precompiled Headers Reader -------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the PCHReader class, which reads a precompiled header. +// +//===----------------------------------------------------------------------===// +#include "clang/Frontend/PCHReader.h" +#include "clang/Frontend/PCHBitCodes.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Decl.h" +#include "clang/AST/Type.h" +#include "llvm/Bitcode/BitstreamReader.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/MemoryBuffer.h" +#include <algorithm> +#include <cstdio> + +using namespace clang; + +//===----------------------------------------------------------------------===// +// Declaration deserialization +//===----------------------------------------------------------------------===// +namespace { + class VISIBILITY_HIDDEN PCHDeclReader { + PCHReader &Reader; + const PCHReader::RecordData &Record; + unsigned &Idx; + + public: + PCHDeclReader(PCHReader &Reader, const PCHReader::RecordData &Record, + unsigned &Idx) + : Reader(Reader), Record(Record), Idx(Idx) { } + + void VisitDecl(Decl *D); + void VisitTranslationUnitDecl(TranslationUnitDecl *TU); + void VisitNamedDecl(NamedDecl *ND); + void VisitTypeDecl(TypeDecl *TD); + void VisitTypedefDecl(TypedefDecl *TD); + void VisitValueDecl(ValueDecl *VD); + void VisitVarDecl(VarDecl *VD); + + std::pair<uint64_t, uint64_t> VisitDeclContext(DeclContext *DC); + }; +} + +void PCHDeclReader::VisitDecl(Decl *D) { + D->setDeclContext(cast_or_null<DeclContext>(Reader.GetDecl(Record[Idx++]))); + D->setLexicalDeclContext( + cast_or_null<DeclContext>(Reader.GetDecl(Record[Idx++]))); + D->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++])); + D->setInvalidDecl(Record[Idx++]); + // FIXME: hasAttrs + D->setImplicit(Record[Idx++]); + D->setAccess((AccessSpecifier)Record[Idx++]); +} + +void PCHDeclReader::VisitTranslationUnitDecl(TranslationUnitDecl *TU) { + VisitDecl(TU); +} + +void PCHDeclReader::VisitNamedDecl(NamedDecl *ND) { + VisitDecl(ND); + ND->setDeclName(Reader.ReadDeclarationName(Record, Idx)); +} + +void PCHDeclReader::VisitTypeDecl(TypeDecl *TD) { + VisitNamedDecl(TD); + // FIXME: circular dependencies here? + TD->setTypeForDecl(Reader.GetType(Record[Idx++]).getTypePtr()); +} + +void PCHDeclReader::VisitTypedefDecl(TypedefDecl *TD) { + VisitTypeDecl(TD); + TD->setUnderlyingType(Reader.GetType(Record[Idx++])); +} + +void PCHDeclReader::VisitValueDecl(ValueDecl *VD) { + VisitNamedDecl(VD); + VD->setType(Reader.GetType(Record[Idx++])); +} + +void PCHDeclReader::VisitVarDecl(VarDecl *VD) { + VisitValueDecl(VD); + VD->setStorageClass((VarDecl::StorageClass)Record[Idx++]); + VD->setThreadSpecified(Record[Idx++]); + VD->setCXXDirectInitializer(Record[Idx++]); + VD->setDeclaredInCondition(Record[Idx++]); + VD->setPreviousDeclaration( + cast_or_null<VarDecl>(Reader.GetDecl(Record[Idx++]))); + VD->setTypeSpecStartLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} + +std::pair<uint64_t, uint64_t> +PCHDeclReader::VisitDeclContext(DeclContext *DC) { + uint64_t LexicalOffset = Record[Idx++]; + uint64_t VisibleOffset = 0; + if (DC->getPrimaryContext() == DC) + VisibleOffset = Record[Idx++]; + return std::make_pair(LexicalOffset, VisibleOffset); +} + +// FIXME: use the diagnostics machinery +static bool Error(const char *Str) { + std::fprintf(stderr, "%s\n", Str); + return true; +} + +/// \brief Read the type-offsets block. +bool PCHReader::ReadTypeOffsets() { + if (Stream.EnterSubBlock(pch::TYPE_OFFSETS_BLOCK_ID)) + return Error("Malformed block record"); + + RecordData Record; + while (true) { + unsigned Code = Stream.ReadCode(); + if (Code == llvm::bitc::END_BLOCK) { + if (Stream.ReadBlockEnd()) + return Error("Error at end of TYPE_OFFSETS block"); + return false; + } + + if (Code == llvm::bitc::ENTER_SUBBLOCK) { + // No known subblocks, always skip them. + Stream.ReadSubBlockID(); + if (Stream.SkipBlock()) + return Error("Malformed block record"); + continue; + } + + if (Code == llvm::bitc::DEFINE_ABBREV) { + Stream.ReadAbbrevRecord(); + continue; + } + + // Read a record. + Record.clear(); + switch (Stream.ReadRecord(Code, Record)) { + default: // Default behavior: ignore. + break; + case pch::TYPE_OFFSET: + if (!TypeOffsets.empty()) + return Error("Duplicate TYPE_OFFSETS block"); + TypeOffsets.swap(Record); + TypeAlreadyLoaded.resize(TypeOffsets.size(), false); + break; + } + } +} + +/// \brief Read the decl-offsets block. +bool PCHReader::ReadDeclOffsets() { + if (Stream.EnterSubBlock(pch::DECL_OFFSETS_BLOCK_ID)) + return Error("Malformed block record"); + + RecordData Record; + while (true) { + unsigned Code = Stream.ReadCode(); + if (Code == llvm::bitc::END_BLOCK) { + if (Stream.ReadBlockEnd()) + return Error("Error at end of DECL_OFFSETS block"); + return false; + } + + if (Code == llvm::bitc::ENTER_SUBBLOCK) { + // No known subblocks, always skip them. + Stream.ReadSubBlockID(); + if (Stream.SkipBlock()) + return Error("Malformed block record"); + continue; + } + + if (Code == llvm::bitc::DEFINE_ABBREV) { + Stream.ReadAbbrevRecord(); + continue; + } + + // Read a record. + Record.clear(); + switch (Stream.ReadRecord(Code, Record)) { + default: // Default behavior: ignore. + break; + case pch::DECL_OFFSET: + if (!DeclOffsets.empty()) + return Error("Duplicate DECL_OFFSETS block"); + DeclOffsets.swap(Record); + DeclAlreadyLoaded.resize(DeclOffsets.size(), false); + break; + } + } +} + +bool PCHReader::ReadPCHBlock() { + if (Stream.EnterSubBlock(pch::PCH_BLOCK_ID)) + return Error("Malformed block record"); + + // Read all of the records and blocks for the PCH file. + while (!Stream.AtEndOfStream()) { + unsigned Code = Stream.ReadCode(); + if (Code == llvm::bitc::END_BLOCK) { + if (Stream.ReadBlockEnd()) + return Error("Error at end of module block"); + return false; + } + + if (Code == llvm::bitc::ENTER_SUBBLOCK) { + switch (Stream.ReadSubBlockID()) { + case pch::DECLS_BLOCK_ID: // Skip decls block (lazily loaded) + case pch::TYPES_BLOCK_ID: // Skip types block (lazily loaded) + default: // Skip unknown content. + if (Stream.SkipBlock()) + return Error("Malformed block record"); + break; + + + case pch::TYPE_OFFSETS_BLOCK_ID: + if (ReadTypeOffsets()) + return Error("Malformed type-offsets block"); + break; + + case pch::DECL_OFFSETS_BLOCK_ID: + if (ReadDeclOffsets()) + return Error("Malformed decl-offsets block"); + break; + } + } + } + + return Error("Premature end of bitstream"); +} + +PCHReader::~PCHReader() { } + +bool PCHReader::ReadPCH(const std::string &FileName) { + // Open the PCH file. + std::string ErrStr; + Buffer.reset(llvm::MemoryBuffer::getFile(FileName.c_str(), &ErrStr)); + if (!Buffer) + return Error(ErrStr.c_str()); + + // Initialize the stream + Stream.init((const unsigned char *)Buffer->getBufferStart(), + (const unsigned char *)Buffer->getBufferEnd()); + + // Sniff for the signature. + if (Stream.Read(8) != 'C' || + Stream.Read(8) != 'P' || + Stream.Read(8) != 'C' || + Stream.Read(8) != 'H') + return Error("Not a PCH file"); + + // We expect a number of well-defined blocks, though we don't necessarily + // need to understand them all. + while (!Stream.AtEndOfStream()) { + unsigned Code = Stream.ReadCode(); + + if (Code != llvm::bitc::ENTER_SUBBLOCK) + return Error("Invalid record at top-level"); + + unsigned BlockID = Stream.ReadSubBlockID(); + + // We only know the PCH subblock ID. + switch (BlockID) { + case llvm::bitc::BLOCKINFO_BLOCK_ID: + if (Stream.ReadBlockInfoBlock()) + return Error("Malformed BlockInfoBlock"); + break; + case pch::PCH_BLOCK_ID: + if (ReadPCHBlock()) + return true; + break; + default: + if (Stream.SkipBlock()) + return Error("Malformed block record"); + break; + } + } + + // Load the translation unit declaration + ReadDeclRecord(DeclOffsets[0], 0); + + return false; +} + +/// \brief Read and return the type at the given offset. +/// +/// This routine actually reads the record corresponding to the type +/// at the given offset in the bitstream. It is a helper routine for +/// GetType, which deals with reading type IDs. +QualType PCHReader::ReadTypeRecord(uint64_t Offset) { + Stream.JumpToBit(Offset); + RecordData Record; + unsigned Code = Stream.ReadCode(); + switch ((pch::TypeCode)Stream.ReadRecord(Code, Record)) { + case pch::TYPE_FIXED_WIDTH_INT: { + assert(Record.size() == 2 && "Incorrect encoding of fixed-width int type"); + return Context.getFixedWidthIntType(Record[0], Record[1]); + } + + case pch::TYPE_COMPLEX: { + assert(Record.size() == 1 && "Incorrect encoding of complex type"); + QualType ElemType = GetType(Record[0]); + return Context.getComplexType(ElemType); + } + + case pch::TYPE_POINTER: { + assert(Record.size() == 1 && "Incorrect encoding of pointer type"); + QualType PointeeType = GetType(Record[0]); + return Context.getPointerType(PointeeType); + } + + case pch::TYPE_BLOCK_POINTER: { + assert(Record.size() == 1 && "Incorrect encoding of block pointer type"); + QualType PointeeType = GetType(Record[0]); + return Context.getBlockPointerType(PointeeType); + } + + case pch::TYPE_LVALUE_REFERENCE: { + assert(Record.size() == 1 && "Incorrect encoding of lvalue reference type"); + QualType PointeeType = GetType(Record[0]); + return Context.getLValueReferenceType(PointeeType); + } + + case pch::TYPE_RVALUE_REFERENCE: { + assert(Record.size() == 1 && "Incorrect encoding of rvalue reference type"); + QualType PointeeType = GetType(Record[0]); + return Context.getRValueReferenceType(PointeeType); + } + + case pch::TYPE_MEMBER_POINTER: { + assert(Record.size() == 1 && "Incorrect encoding of member pointer type"); + QualType PointeeType = GetType(Record[0]); + QualType ClassType = GetType(Record[1]); + return Context.getMemberPointerType(PointeeType, ClassType.getTypePtr()); + } + + // FIXME: Several other kinds of types to deserialize here! + default: + assert("Unable to deserialize this type"); + break; + } + + // Suppress a GCC warning + return QualType(); +} + +/// \brief Note that we have loaded the declaration with the given +/// Index. +/// +/// This routine notes that this declaration has already been loaded, +/// so that future GetDecl calls will return this declaration rather +/// than trying to load a new declaration. +inline void PCHReader::LoadedDecl(unsigned Index, Decl *D) { + assert(!DeclAlreadyLoaded[Index] && "Decl loaded twice?"); + DeclAlreadyLoaded[Index] = true; + DeclOffsets[Index] = reinterpret_cast<uint64_t>(D); +} + +/// \brief Read the declaration at the given offset from the PCH file. +Decl *PCHReader::ReadDeclRecord(uint64_t Offset, unsigned Index) { + Decl *D = 0; + Stream.JumpToBit(Offset); + RecordData Record; + unsigned Code = Stream.ReadCode(); + unsigned Idx = 0; + PCHDeclReader Reader(*this, Record, Idx); + switch ((pch::DeclCode)Stream.ReadRecord(Code, Record)) { + case pch::DECL_TRANSLATION_UNIT: + assert(Index == 0 && "Translation unit must be at index 0"); + Reader.VisitTranslationUnitDecl(Context.getTranslationUnitDecl()); + D = Context.getTranslationUnitDecl(); + LoadedDecl(Index, D); + break; + + case pch::DECL_TYPEDEF: { + TypedefDecl *Typedef = TypedefDecl::Create(Context, 0, SourceLocation(), + 0, QualType()); + LoadedDecl(Index, Typedef); + Reader.VisitTypedefDecl(Typedef); + D = Typedef; + break; + } + + case pch::DECL_VAR: { + VarDecl *Var = VarDecl::Create(Context, 0, SourceLocation(), 0, QualType(), + VarDecl::None, SourceLocation()); + LoadedDecl(Index, Var); + Reader.VisitVarDecl(Var); + D = Var; + break; + } + + default: + assert(false && "Cannot de-serialize this kind of declaration"); + break; + } + + // If this declaration is also a declaration context, get the + // offsets for its tables of lexical and visible declarations. + if (DeclContext *DC = dyn_cast<DeclContext>(D)) { + std::pair<uint64_t, uint64_t> Offsets = Reader.VisitDeclContext(DC); + if (Offsets.first || Offsets.second) { + DC->setHasExternalLexicalStorage(Offsets.first != 0); + DC->setHasExternalVisibleStorage(Offsets.second != 0); + DeclContextOffsets[DC] = Offsets; + } + } + assert(Idx == Record.size()); + + return D; +} + +QualType PCHReader::GetType(unsigned ID) { + unsigned Quals = ID & 0x07; + unsigned Index = ID >> 3; + + if (Index < pch::NUM_PREDEF_TYPE_IDS) { + QualType T; + switch ((pch::PredefinedTypeIDs)Index) { + case pch::PREDEF_TYPE_NULL_ID: return QualType(); + case pch::PREDEF_TYPE_VOID_ID: T = Context.VoidTy; break; + case pch::PREDEF_TYPE_BOOL_ID: T = Context.BoolTy; break; + + case pch::PREDEF_TYPE_CHAR_U_ID: + case pch::PREDEF_TYPE_CHAR_S_ID: + // FIXME: Check that the signedness of CharTy is correct! + T = Context.CharTy; + break; + + case pch::PREDEF_TYPE_UCHAR_ID: T = Context.UnsignedCharTy; break; + case pch::PREDEF_TYPE_USHORT_ID: T = Context.UnsignedShortTy; break; + case pch::PREDEF_TYPE_UINT_ID: T = Context.UnsignedIntTy; break; + case pch::PREDEF_TYPE_ULONG_ID: T = Context.UnsignedLongTy; break; + case pch::PREDEF_TYPE_ULONGLONG_ID: T = Context.UnsignedLongLongTy; break; + case pch::PREDEF_TYPE_SCHAR_ID: T = Context.SignedCharTy; break; + case pch::PREDEF_TYPE_WCHAR_ID: T = Context.WCharTy; break; + case pch::PREDEF_TYPE_SHORT_ID: T = Context.ShortTy; break; + case pch::PREDEF_TYPE_INT_ID: T = Context.IntTy; break; + case pch::PREDEF_TYPE_LONG_ID: T = Context.LongTy; break; + case pch::PREDEF_TYPE_LONGLONG_ID: T = Context.LongLongTy; break; + case pch::PREDEF_TYPE_FLOAT_ID: T = Context.FloatTy; break; + case pch::PREDEF_TYPE_DOUBLE_ID: T = Context.DoubleTy; break; + case pch::PREDEF_TYPE_LONGDOUBLE_ID: T = Context.LongDoubleTy; break; + case pch::PREDEF_TYPE_OVERLOAD_ID: T = Context.OverloadTy; break; + case pch::PREDEF_TYPE_DEPENDENT_ID: T = Context.DependentTy; break; + } + + assert(!T.isNull() && "Unknown predefined type"); + return T.getQualifiedType(Quals); + } + + Index -= pch::NUM_PREDEF_TYPE_IDS; + if (!TypeAlreadyLoaded[Index]) { + // Load the type from the PCH file. + TypeOffsets[Index] = reinterpret_cast<uint64_t>( + ReadTypeRecord(TypeOffsets[Index]).getTypePtr()); + TypeAlreadyLoaded[Index] = true; + } + + return QualType(reinterpret_cast<Type *>(TypeOffsets[Index]), Quals); +} + +Decl *PCHReader::GetDecl(unsigned ID) { + if (ID == 0) + return 0; + + unsigned Index = ID - 1; + if (DeclAlreadyLoaded[Index]) + return reinterpret_cast<Decl *>(DeclOffsets[Index]); + + // Load the declaration from the PCH file. + return ReadDeclRecord(DeclOffsets[Index], Index); +} + +bool PCHReader::ReadDeclsLexicallyInContext(DeclContext *DC, + llvm::SmallVectorImpl<unsigned> &Decls) { + assert(DC->hasExternalLexicalStorage() && + "DeclContext has no lexical decls in storage"); + uint64_t Offset = DeclContextOffsets[DC].first; + assert(Offset && "DeclContext has no lexical decls in storage"); + + // Load the record containing all of the declarations lexically in + // this context. + Stream.JumpToBit(Offset); + RecordData Record; + unsigned Code = Stream.ReadCode(); + unsigned RecCode = Stream.ReadRecord(Code, Record); + assert(RecCode == pch::DECL_CONTEXT_LEXICAL && "Expected lexical block"); + + // Load all of the declaration IDs + Decls.clear(); + Decls.insert(Decls.end(), Record.begin(), Record.end()); + return false; +} + +bool PCHReader::ReadDeclsVisibleInContext(DeclContext *DC, + llvm::SmallVectorImpl<VisibleDeclaration> & Decls) { + assert(DC->hasExternalVisibleStorage() && + "DeclContext has no visible decls in storage"); + uint64_t Offset = DeclContextOffsets[DC].second; + assert(Offset && "DeclContext has no visible decls in storage"); + + // Load the record containing all of the declarations visible in + // this context. + Stream.JumpToBit(Offset); + RecordData Record; + unsigned Code = Stream.ReadCode(); + unsigned RecCode = Stream.ReadRecord(Code, Record); + assert(RecCode == pch::DECL_CONTEXT_VISIBLE && "Expected visible block"); + if (Record.size() == 0) + return false; + + Decls.clear(); + + unsigned Idx = 0; + // llvm::SmallVector<uintptr_t, 16> DeclIDs; + while (Idx < Record.size()) { + Decls.push_back(VisibleDeclaration()); + Decls.back().Name = ReadDeclarationName(Record, Idx); + + // FIXME: Don't actually read anything here! + unsigned Size = Record[Idx++]; + llvm::SmallVector<unsigned, 4> & LoadedDecls + = Decls.back().Declarations; + LoadedDecls.reserve(Size); + for (unsigned I = 0; I < Size; ++I) + LoadedDecls.push_back(Record[Idx++]); + } + + return false; +} + +void PCHReader::PrintStats() { + std::fprintf(stderr, "*** PCH Statistics:\n"); + + unsigned NumTypesLoaded = std::count(TypeAlreadyLoaded.begin(), + TypeAlreadyLoaded.end(), + true); + unsigned NumDeclsLoaded = std::count(DeclAlreadyLoaded.begin(), + DeclAlreadyLoaded.end(), + true); + std::fprintf(stderr, " %u/%u types read (%f%%)\n", + NumTypesLoaded, (unsigned)TypeAlreadyLoaded.size(), + ((float)NumTypesLoaded/(float)TypeAlreadyLoaded.size() * 100)); + std::fprintf(stderr, " %u/%u declarations read (%f%%)\n", + NumDeclsLoaded, (unsigned)DeclAlreadyLoaded.size(), + ((float)NumDeclsLoaded/(float)DeclAlreadyLoaded.size() * 100)); + std::fprintf(stderr, "\n"); +} + +const IdentifierInfo *PCHReader::GetIdentifierInfo(const RecordData &Record, + unsigned &Idx) { + // FIXME: we need unique IDs for identifiers. + std::string Str; + unsigned Length = Record[Idx++]; + Str.resize(Length); + for (unsigned I = 0; I != Length; ++I) + Str[I] = Record[Idx++]; + return &Context.Idents.get(Str); +} + +DeclarationName +PCHReader::ReadDeclarationName(const RecordData &Record, unsigned &Idx) { + DeclarationName::NameKind Kind = (DeclarationName::NameKind)Record[Idx++]; + switch (Kind) { + case DeclarationName::Identifier: + return DeclarationName(GetIdentifierInfo(Record, Idx)); + + case DeclarationName::ObjCZeroArgSelector: + case DeclarationName::ObjCOneArgSelector: + case DeclarationName::ObjCMultiArgSelector: + assert(false && "Unable to de-serialize Objective-C selectors"); + break; + + case DeclarationName::CXXConstructorName: + return Context.DeclarationNames.getCXXConstructorName( + GetType(Record[Idx++])); + + case DeclarationName::CXXDestructorName: + return Context.DeclarationNames.getCXXDestructorName( + GetType(Record[Idx++])); + + case DeclarationName::CXXConversionFunctionName: + return Context.DeclarationNames.getCXXConversionFunctionName( + GetType(Record[Idx++])); + + case DeclarationName::CXXOperatorName: + return Context.DeclarationNames.getCXXOperatorName( + (OverloadedOperatorKind)Record[Idx++]); + + case DeclarationName::CXXUsingDirective: + return DeclarationName::getUsingDirectiveName(); + } + + // Required to silence GCC warning + return DeclarationName(); +} diff --git a/clang/lib/Frontend/PCHWriter.cpp b/clang/lib/Frontend/PCHWriter.cpp new file mode 100644 index 00000000000..39936b34f5f --- /dev/null +++ b/clang/lib/Frontend/PCHWriter.cpp @@ -0,0 +1,636 @@ +//===--- PCHWriter.h - Precompiled Headers Writer ---------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the PCHWriter class, which writes a precompiled header. +// +//===----------------------------------------------------------------------===// + +#include "clang/Frontend/PCHWriter.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclContextInternals.h" +#include "clang/AST/DeclVisitor.h" +#include "clang/AST/Type.h" +#include "llvm/Bitcode/BitstreamWriter.h" +#include "llvm/Support/Compiler.h" + +using namespace clang; + +//===----------------------------------------------------------------------===// +// Type serialization +//===----------------------------------------------------------------------===// +namespace { + class VISIBILITY_HIDDEN PCHTypeWriter { + PCHWriter &Writer; + PCHWriter::RecordData &Record; + + public: + /// \brief Type code that corresponds to the record generated. + pch::TypeCode Code; + + PCHTypeWriter(PCHWriter &Writer, PCHWriter::RecordData &Record) + : Writer(Writer), Record(Record) { } + + void VisitArrayType(const ArrayType *T); + void VisitFunctionType(const FunctionType *T); + void VisitTagType(const TagType *T); + +#define TYPE(Class, Base) void Visit##Class##Type(const Class##Type *T); +#define ABSTRACT_TYPE(Class, Base) +#define DEPENDENT_TYPE(Class, Base) +#include "clang/AST/TypeNodes.def" + }; +} + +void PCHTypeWriter::VisitExtQualType(const ExtQualType *T) { + Writer.AddTypeRef(QualType(T->getBaseType(), 0), Record); + Record.push_back(T->getObjCGCAttr()); // FIXME: use stable values + Record.push_back(T->getAddressSpace()); + Code = pch::TYPE_EXT_QUAL; +} + +void PCHTypeWriter::VisitBuiltinType(const BuiltinType *T) { + assert(false && "Built-in types are never serialized"); +} + +void PCHTypeWriter::VisitFixedWidthIntType(const FixedWidthIntType *T) { + Record.push_back(T->getWidth()); + Record.push_back(T->isSigned()); + Code = pch::TYPE_FIXED_WIDTH_INT; +} + +void PCHTypeWriter::VisitComplexType(const ComplexType *T) { + Writer.AddTypeRef(T->getElementType(), Record); + Code = pch::TYPE_COMPLEX; +} + +void PCHTypeWriter::VisitPointerType(const PointerType *T) { + Writer.AddTypeRef(T->getPointeeType(), Record); + Code = pch::TYPE_POINTER; +} + +void PCHTypeWriter::VisitBlockPointerType(const BlockPointerType *T) { + Writer.AddTypeRef(T->getPointeeType(), Record); + Code = pch::TYPE_BLOCK_POINTER; +} + +void PCHTypeWriter::VisitLValueReferenceType(const LValueReferenceType *T) { + Writer.AddTypeRef(T->getPointeeType(), Record); + Code = pch::TYPE_LVALUE_REFERENCE; +} + +void PCHTypeWriter::VisitRValueReferenceType(const RValueReferenceType *T) { + Writer.AddTypeRef(T->getPointeeType(), Record); + Code = pch::TYPE_RVALUE_REFERENCE; +} + +void PCHTypeWriter::VisitMemberPointerType(const MemberPointerType *T) { + Writer.AddTypeRef(T->getPointeeType(), Record); + Writer.AddTypeRef(QualType(T->getClass(), 0), Record); + Code = pch::TYPE_MEMBER_POINTER; +} + +void PCHTypeWriter::VisitArrayType(const ArrayType *T) { + Writer.AddTypeRef(T->getElementType(), Record); + Record.push_back(T->getSizeModifier()); // FIXME: stable values + Record.push_back(T->getIndexTypeQualifier()); // FIXME: stable values +} + +void PCHTypeWriter::VisitConstantArrayType(const ConstantArrayType *T) { + VisitArrayType(T); + Writer.AddAPInt(T->getSize(), Record); + Code = pch::TYPE_CONSTANT_ARRAY; +} + +void PCHTypeWriter::VisitIncompleteArrayType(const IncompleteArrayType *T) { + VisitArrayType(T); + Code = pch::TYPE_INCOMPLETE_ARRAY; +} + +void PCHTypeWriter::VisitVariableArrayType(const VariableArrayType *T) { + VisitArrayType(T); + // FIXME: Serialize array size expression. + assert(false && "Cannot serialize variable-length arrays"); + Code = pch::TYPE_VARIABLE_ARRAY; +} + +void PCHTypeWriter::VisitVectorType(const VectorType *T) { + Writer.AddTypeRef(T->getElementType(), Record); + Record.push_back(T->getNumElements()); + Code = pch::TYPE_VECTOR; +} + +void PCHTypeWriter::VisitExtVectorType(const ExtVectorType *T) { + VisitVectorType(T); + Code = pch::TYPE_EXT_VECTOR; +} + +void PCHTypeWriter::VisitFunctionType(const FunctionType *T) { + Writer.AddTypeRef(T->getResultType(), Record); +} + +void PCHTypeWriter::VisitFunctionNoProtoType(const FunctionNoProtoType *T) { + VisitFunctionType(T); + Code = pch::TYPE_FUNCTION_NO_PROTO; +} + +void PCHTypeWriter::VisitFunctionProtoType(const FunctionProtoType *T) { + VisitFunctionType(T); + Record.push_back(T->getNumArgs()); + for (unsigned I = 0, N = T->getNumArgs(); I != N; ++I) + Writer.AddTypeRef(T->getArgType(I), Record); + Record.push_back(T->isVariadic()); + Record.push_back(T->getTypeQuals()); + Code = pch::TYPE_FUNCTION_PROTO; +} + +void PCHTypeWriter::VisitTypedefType(const TypedefType *T) { + Writer.AddDeclRef(T->getDecl(), Record); + Code = pch::TYPE_TYPEDEF; +} + +void PCHTypeWriter::VisitTypeOfExprType(const TypeOfExprType *T) { + // FIXME: serialize the typeof expression + assert(false && "Cannot serialize typeof(expr)"); + Code = pch::TYPE_TYPEOF_EXPR; +} + +void PCHTypeWriter::VisitTypeOfType(const TypeOfType *T) { + Writer.AddTypeRef(T->getUnderlyingType(), Record); + Code = pch::TYPE_TYPEOF; +} + +void PCHTypeWriter::VisitTagType(const TagType *T) { + Writer.AddDeclRef(T->getDecl(), Record); + assert(!T->isBeingDefined() && + "Cannot serialize in the middle of a type definition"); +} + +void PCHTypeWriter::VisitRecordType(const RecordType *T) { + VisitTagType(T); + Code = pch::TYPE_RECORD; +} + +void PCHTypeWriter::VisitEnumType(const EnumType *T) { + VisitTagType(T); + Code = pch::TYPE_ENUM; +} + +void +PCHTypeWriter::VisitTemplateSpecializationType( + const TemplateSpecializationType *T) { + // FIXME: Serialize this type + assert(false && "Cannot serialize template specialization types"); +} + +void PCHTypeWriter::VisitQualifiedNameType(const QualifiedNameType *T) { + // FIXME: Serialize this type + assert(false && "Cannot serialize qualified name types"); +} + +void PCHTypeWriter::VisitObjCInterfaceType(const ObjCInterfaceType *T) { + Writer.AddDeclRef(T->getDecl(), Record); + Code = pch::TYPE_OBJC_INTERFACE; +} + +void +PCHTypeWriter::VisitObjCQualifiedInterfaceType( + const ObjCQualifiedInterfaceType *T) { + VisitObjCInterfaceType(T); + Record.push_back(T->getNumProtocols()); + for (unsigned I = 0, N = T->getNumProtocols(); I != N; ++I) + Writer.AddDeclRef(T->getProtocol(I), Record); + Code = pch::TYPE_OBJC_QUALIFIED_INTERFACE; +} + +void PCHTypeWriter::VisitObjCQualifiedIdType(const ObjCQualifiedIdType *T) { + Record.push_back(T->getNumProtocols()); + for (unsigned I = 0, N = T->getNumProtocols(); I != N; ++I) + Writer.AddDeclRef(T->getProtocols(I), Record); + Code = pch::TYPE_OBJC_QUALIFIED_ID; +} + +void +PCHTypeWriter::VisitObjCQualifiedClassType(const ObjCQualifiedClassType *T) { + Record.push_back(T->getNumProtocols()); + for (unsigned I = 0, N = T->getNumProtocols(); I != N; ++I) + Writer.AddDeclRef(T->getProtocols(I), Record); + Code = pch::TYPE_OBJC_QUALIFIED_CLASS; +} + +//===----------------------------------------------------------------------===// +// Declaration serialization +//===----------------------------------------------------------------------===// +namespace { + class VISIBILITY_HIDDEN PCHDeclWriter + : public DeclVisitor<PCHDeclWriter, void> { + + PCHWriter &Writer; + PCHWriter::RecordData &Record; + + public: + pch::DeclCode Code; + + PCHDeclWriter(PCHWriter &Writer, PCHWriter::RecordData &Record) + : Writer(Writer), Record(Record) { } + + void VisitDecl(Decl *D); + void VisitTranslationUnitDecl(TranslationUnitDecl *D); + void VisitNamedDecl(NamedDecl *D); + void VisitTypeDecl(TypeDecl *D); + void VisitTypedefDecl(TypedefDecl *D); + void VisitValueDecl(ValueDecl *D); + void VisitVarDecl(VarDecl *D); + + void VisitDeclContext(DeclContext *DC, uint64_t LexicalOffset, + uint64_t VisibleOffset); + }; +} + +void PCHDeclWriter::VisitDecl(Decl *D) { + Writer.AddDeclRef(cast_or_null<Decl>(D->getDeclContext()), Record); + Writer.AddDeclRef(cast_or_null<Decl>(D->getLexicalDeclContext()), Record); + Writer.AddSourceLocation(D->getLocation(), Record); + Record.push_back(D->isInvalidDecl()); + // FIXME: hasAttrs + Record.push_back(D->isImplicit()); + Record.push_back(D->getAccess()); +} + +void PCHDeclWriter::VisitTranslationUnitDecl(TranslationUnitDecl *D) { + VisitDecl(D); + Code = pch::DECL_TRANSLATION_UNIT; +} + +void PCHDeclWriter::VisitNamedDecl(NamedDecl *D) { + VisitDecl(D); + Writer.AddDeclarationName(D->getDeclName(), Record); +} + +void PCHDeclWriter::VisitTypeDecl(TypeDecl *D) { + VisitNamedDecl(D); + Writer.AddTypeRef(QualType(D->getTypeForDecl(), 0), Record); +} + +void PCHDeclWriter::VisitTypedefDecl(TypedefDecl *D) { + VisitTypeDecl(D); + Writer.AddTypeRef(D->getUnderlyingType(), Record); + Code = pch::DECL_TYPEDEF; +} + +void PCHDeclWriter::VisitValueDecl(ValueDecl *D) { + VisitNamedDecl(D); + Writer.AddTypeRef(D->getType(), Record); +} + +void PCHDeclWriter::VisitVarDecl(VarDecl *D) { + VisitValueDecl(D); + Record.push_back(D->getStorageClass()); + Record.push_back(D->isThreadSpecified()); + Record.push_back(D->hasCXXDirectInitializer()); + Record.push_back(D->isDeclaredInCondition()); + Writer.AddDeclRef(D->getPreviousDeclaration(), Record); + Writer.AddSourceLocation(D->getTypeSpecStartLoc(), Record); + // FIXME: emit initializer + Code = pch::DECL_VAR; +} + +/// \brief Emit the DeclContext part of a declaration context decl. +/// +/// \param LexicalOffset the offset at which the DECL_CONTEXT_LEXICAL +/// block for this declaration context is stored. May be 0 to indicate +/// that there are no declarations stored within this context. +/// +/// \param VisibleOffset the offset at which the DECL_CONTEXT_VISIBLE +/// block for this declaration context is stored. May be 0 to indicate +/// that there are no declarations visible from this context. Note +/// that this value will not be emitted for non-primary declaration +/// contexts. +void PCHDeclWriter::VisitDeclContext(DeclContext *DC, uint64_t LexicalOffset, + uint64_t VisibleOffset) { + Record.push_back(LexicalOffset); + if (DC->getPrimaryContext() == DC) + Record.push_back(VisibleOffset); +} + +//===----------------------------------------------------------------------===// +// PCHWriter Implementation +//===----------------------------------------------------------------------===// + +/// \brief Write the representation of a type to the PCH stream. +void PCHWriter::WriteType(const Type *T) { + pch::ID &ID = TypeIDs[T]; + if (ID == 0) // we haven't seen this type before + ID = NextTypeID++; + + // Record the offset for this type. + if (TypeOffsets.size() == ID - pch::NUM_PREDEF_TYPE_IDS) + TypeOffsets.push_back(S.GetCurrentBitNo()); + else if (TypeOffsets.size() < ID - pch::NUM_PREDEF_TYPE_IDS) { + TypeOffsets.resize(ID + 1 - pch::NUM_PREDEF_TYPE_IDS); + TypeOffsets[ID - pch::NUM_PREDEF_TYPE_IDS] = S.GetCurrentBitNo(); + } + + RecordData Record; + + // Emit the type's representation. + PCHTypeWriter W(*this, Record); + switch (T->getTypeClass()) { + // For all of the concrete, non-dependent types, call the + // appropriate visitor function. +#define TYPE(Class, Base) \ + case Type::Class: W.Visit##Class##Type(cast<Class##Type>(T)); break; +#define ABSTRACT_TYPE(Class, Base) +#define DEPENDENT_TYPE(Class, Base) +#include "clang/AST/TypeNodes.def" + + // For all of the dependent type nodes (which only occur in C++ + // templates), produce an error. +#define TYPE(Class, Base) +#define DEPENDENT_TYPE(Class, Base) case Type::Class: +#include "clang/AST/TypeNodes.def" + assert(false && "Cannot serialize dependent type nodes"); + break; + } + + // Emit the serialized record. + S.EmitRecord(W.Code, Record); +} + +/// \brief Write a block containing all of the types. +void PCHWriter::WriteTypesBlock(ASTContext &Context) { + // Enter the types block + S.EnterSubblock(pch::TYPES_BLOCK_ID, 2); + + // Emit all of the types in the ASTContext + for (std::vector<Type*>::const_iterator T = Context.getTypes().begin(), + TEnd = Context.getTypes().end(); + T != TEnd; ++T) { + // Builtin types are never serialized. + if (isa<BuiltinType>(*T)) + continue; + + WriteType(*T); + } + + // Exit the types block + S.ExitBlock(); + + // Write the type offsets block + S.EnterSubblock(pch::TYPE_OFFSETS_BLOCK_ID, 2); + S.EmitRecord(pch::TYPE_OFFSET, TypeOffsets); + S.ExitBlock(); +} + +/// \brief Write the block containing all of the declaration IDs +/// lexically declared within the given DeclContext. +/// +/// \returns the offset of the DECL_CONTEXT_LEXICAL block within the +/// bistream, or 0 if no block was written. +uint64_t PCHWriter::WriteDeclContextLexicalBlock(ASTContext &Context, + DeclContext *DC) { + if (DC->decls_begin(Context) == DC->decls_end(Context)) + return 0; + + uint64_t Offset = S.GetCurrentBitNo(); + RecordData Record; + for (DeclContext::decl_iterator D = DC->decls_begin(Context), + DEnd = DC->decls_end(Context); + D != DEnd; ++D) + AddDeclRef(*D, Record); + + S.EmitRecord(pch::DECL_CONTEXT_LEXICAL, Record); + return Offset; +} + +/// \brief Write the block containing all of the declaration IDs +/// visible from the given DeclContext. +/// +/// \returns the offset of the DECL_CONTEXT_VISIBLE block within the +/// bistream, or 0 if no block was written. +uint64_t PCHWriter::WriteDeclContextVisibleBlock(ASTContext &Context, + DeclContext *DC) { + if (DC->getPrimaryContext() != DC) + return 0; + + // Force the DeclContext to build a its name-lookup table. + DC->lookup(Context, DeclarationName()); + + // Serialize the contents of the mapping used for lookup. Note that, + // although we have two very different code paths, the serialized + // representation is the same for both cases: a declaration name, + // followed by a size, followed by references to the visible + // declarations that have that name. + uint64_t Offset = S.GetCurrentBitNo(); + RecordData Record; + StoredDeclsMap *Map = static_cast<StoredDeclsMap*>(DC->getLookupPtr()); + for (StoredDeclsMap::iterator D = Map->begin(), DEnd = Map->end(); + D != DEnd; ++D) { + AddDeclarationName(D->first, Record); + DeclContext::lookup_result Result = D->second.getLookupResult(Context); + Record.push_back(Result.second - Result.first); + for(; Result.first != Result.second; ++Result.first) + AddDeclRef(*Result.first, Record); + } + + if (Record.size() == 0) + return 0; + + S.EmitRecord(pch::DECL_CONTEXT_VISIBLE, Record); + return Offset; +} + +/// \brief Write a block containing all of the declarations. +void PCHWriter::WriteDeclsBlock(ASTContext &Context) { + // Enter the declarations block + S.EnterSubblock(pch::DECLS_BLOCK_ID, 2); + + // Emit all of the declarations. + RecordData Record; + PCHDeclWriter W(*this, Record); + while (!DeclsToEmit.empty()) { + // Pull the next declaration off the queue + Decl *D = DeclsToEmit.front(); + DeclsToEmit.pop(); + + // 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 + // are written before the declaration itself so that we can put + // their offsets into the record for the declaration. + uint64_t LexicalOffset = 0; + uint64_t VisibleOffset = 0; + DeclContext *DC = dyn_cast<DeclContext>(D); + if (DC) { + LexicalOffset = WriteDeclContextLexicalBlock(Context, DC); + VisibleOffset = WriteDeclContextVisibleBlock(Context, DC); + } + + // Determine the ID for this declaration + pch::ID ID = DeclIDs[D]; + if (ID == 0) + ID = DeclIDs.size(); + + unsigned Index = ID - 1; + + // Record the offset for this declaration + if (DeclOffsets.size() == Index) + DeclOffsets.push_back(S.GetCurrentBitNo()); + else if (DeclOffsets.size() < Index) { + DeclOffsets.resize(Index+1); + DeclOffsets[Index] = S.GetCurrentBitNo(); + } + + // Build and emit a record for this declaration + Record.clear(); + W.Code = (pch::DeclCode)0; + W.Visit(D); + if (DC) W.VisitDeclContext(DC, LexicalOffset, VisibleOffset); + assert(W.Code && "Visitor did not set record code"); + S.EmitRecord(W.Code, Record); + } + + // Exit the declarations block + S.ExitBlock(); + + // Write the declaration offsets block + S.EnterSubblock(pch::DECL_OFFSETS_BLOCK_ID, 2); + S.EmitRecord(pch::DECL_OFFSET, DeclOffsets); + S.ExitBlock(); +} + +PCHWriter::PCHWriter(llvm::BitstreamWriter &S) + : S(S), NextTypeID(pch::NUM_PREDEF_TYPE_IDS) { } + +void PCHWriter::WritePCH(ASTContext &Context) { + // Emit the file header. + S.Emit((unsigned)'C', 8); + S.Emit((unsigned)'P', 8); + S.Emit((unsigned)'C', 8); + S.Emit((unsigned)'H', 8); + + // The translation unit is the first declaration we'll emit. + DeclIDs[Context.getTranslationUnitDecl()] = 1; + DeclsToEmit.push(Context.getTranslationUnitDecl()); + + // Write the remaining PCH contents. + S.EnterSubblock(pch::PCH_BLOCK_ID, 2); + WriteTypesBlock(Context); + WriteDeclsBlock(Context); + S.ExitBlock(); +} + +void PCHWriter::AddSourceLocation(SourceLocation Loc, RecordData &Record) { + Record.push_back(Loc.getRawEncoding()); +} + +void PCHWriter::AddAPInt(const llvm::APInt &Value, RecordData &Record) { + Record.push_back(Value.getBitWidth()); + unsigned N = Value.getNumWords(); + const uint64_t* Words = Value.getRawData(); + for (unsigned I = 0; I != N; ++I) + Record.push_back(Words[I]); +} + +void PCHWriter::AddIdentifierRef(const IdentifierInfo *II, RecordData &Record) { + // FIXME: Emit an identifier ID, not the actual string! + const char *Name = II->getName(); + unsigned Len = strlen(Name); + Record.push_back(Len); + Record.insert(Record.end(), Name, Name + Len); +} + +void PCHWriter::AddTypeRef(QualType T, RecordData &Record) { + if (T.isNull()) { + Record.push_back(pch::PREDEF_TYPE_NULL_ID); + return; + } + + if (const BuiltinType *BT = dyn_cast<BuiltinType>(T.getTypePtr())) { + pch::ID ID; + switch (BT->getKind()) { + case BuiltinType::Void: ID = pch::PREDEF_TYPE_VOID_ID; break; + case BuiltinType::Bool: ID = pch::PREDEF_TYPE_BOOL_ID; break; + case BuiltinType::Char_U: ID = pch::PREDEF_TYPE_CHAR_U_ID; break; + case BuiltinType::UChar: ID = pch::PREDEF_TYPE_UCHAR_ID; break; + case BuiltinType::UShort: ID = pch::PREDEF_TYPE_USHORT_ID; break; + case BuiltinType::UInt: ID = pch::PREDEF_TYPE_UINT_ID; break; + case BuiltinType::ULong: ID = pch::PREDEF_TYPE_ULONG_ID; break; + case BuiltinType::ULongLong: ID = pch::PREDEF_TYPE_ULONGLONG_ID; break; + case BuiltinType::Char_S: ID = pch::PREDEF_TYPE_CHAR_S_ID; break; + case BuiltinType::SChar: ID = pch::PREDEF_TYPE_SCHAR_ID; break; + case BuiltinType::WChar: ID = pch::PREDEF_TYPE_WCHAR_ID; break; + case BuiltinType::Short: ID = pch::PREDEF_TYPE_SHORT_ID; break; + case BuiltinType::Int: ID = pch::PREDEF_TYPE_INT_ID; break; + case BuiltinType::Long: ID = pch::PREDEF_TYPE_LONG_ID; break; + case BuiltinType::LongLong: ID = pch::PREDEF_TYPE_LONGLONG_ID; break; + case BuiltinType::Float: ID = pch::PREDEF_TYPE_FLOAT_ID; break; + case BuiltinType::Double: ID = pch::PREDEF_TYPE_DOUBLE_ID; break; + case BuiltinType::LongDouble: ID = pch::PREDEF_TYPE_LONGDOUBLE_ID; break; + case BuiltinType::Overload: ID = pch::PREDEF_TYPE_OVERLOAD_ID; break; + case BuiltinType::Dependent: ID = pch::PREDEF_TYPE_DEPENDENT_ID; break; + } + + Record.push_back((ID << 3) | T.getCVRQualifiers()); + return; + } + + pch::ID &ID = TypeIDs[T.getTypePtr()]; + if (ID == 0) // we haven't seen this type before + ID = NextTypeID++; + + // Encode the type qualifiers in the type reference. + Record.push_back((ID << 3) | T.getCVRQualifiers()); +} + +void PCHWriter::AddDeclRef(const Decl *D, RecordData &Record) { + if (D == 0) { + Record.push_back(0); + return; + } + + pch::ID &ID = DeclIDs[D]; + if (ID == 0) { + // We haven't seen this declaration before. Give it a new ID and + // enqueue it in the list of declarations to emit. + ID = DeclIDs.size(); + DeclsToEmit.push(const_cast<Decl *>(D)); + } + + Record.push_back(ID); +} + +void PCHWriter::AddDeclarationName(DeclarationName Name, RecordData &Record) { + Record.push_back(Name.getNameKind()); + switch (Name.getNameKind()) { + case DeclarationName::Identifier: + AddIdentifierRef(Name.getAsIdentifierInfo(), Record); + break; + + case DeclarationName::ObjCZeroArgSelector: + case DeclarationName::ObjCOneArgSelector: + case DeclarationName::ObjCMultiArgSelector: + assert(false && "Serialization of Objective-C selectors unavailable"); + break; + + case DeclarationName::CXXConstructorName: + case DeclarationName::CXXDestructorName: + case DeclarationName::CXXConversionFunctionName: + AddTypeRef(Name.getCXXNameType(), Record); + break; + + case DeclarationName::CXXOperatorName: + Record.push_back(Name.getCXXOverloadedOperator()); + break; + + case DeclarationName::CXXUsingDirective: + // No extra data to emit + break; + } +} diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 474c1e490e4..b024d36acc3 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -524,6 +524,12 @@ bool Sema::MergeTypeDefDecl(TypedefDecl *New, Decl *OldD) { return false; } + // __builtin_va_list gets redeclared in the built-in definitions + // buffer when using PCH. Don't complain about such redefinitions. + if (Context.getExternalSource() && + strcmp(SourceMgr.getBufferName(New->getLocation()), "<built-in>") == 0) + return false; + Diag(New->getLocation(), diag::err_redefinition) << New->getDeclName(); Diag(Old->getLocation(), diag::note_previous_definition); return true; diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index 0b11d9cf68c..cd825070054 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -878,6 +878,17 @@ Sema::LookupName(Scope *S, DeclarationName Name, LookupNameKind NameKind, // We have a single lookup result. return LookupResult::CreateLookupResult(Context, *I); } + + /// If the context has an external AST source attached, look at + /// translation unit scope. + if (Context.getExternalSource()) { + DeclContext::lookup_iterator I, E; + for (llvm::tie(I, E) + = Context.getTranslationUnitDecl()->lookup(Context, Name); + I != E; ++I) + if (isAcceptableLookupResult(*I, NameKind, IDNS)) + return LookupResult::CreateLookupResult(Context, I, E); + } } else { // Perform C++ unqualified name lookup. std::pair<bool, LookupResult> MaybeResult = |