From: Douglas Gregor Date: Fri, 10 Apr 2009 17:25:41 +0000 (+0000) Subject: Various minor fixes to PCH reading and writing, with general X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=8038d5182b72dcdef292f6fb8539ad77f338855a;p=clang Various minor fixes to PCH reading and writing, with general cleanup. Aside from a minor tweak to the PCH file format, no functionality change. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@68793 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h index 46af4ec6b6..d05b5a597e 100644 --- a/include/clang/AST/DeclBase.h +++ b/include/clang/AST/DeclBase.h @@ -549,6 +549,7 @@ public: /// this context. decl_iterator decls_begin(ASTContext &Context) const; decl_iterator decls_end(ASTContext &Context) const; + bool decls_empty(ASTContext &Context) const; /// specific_decl_iterator - Iterates over a subrange of /// declarations stored in a DeclContext, providing only those that diff --git a/include/clang/AST/DeclContextInternals.h b/include/clang/AST/DeclContextInternals.h index 7489413be8..6a905be4a7 100644 --- a/include/clang/AST/DeclContextInternals.h +++ b/include/clang/AST/DeclContextInternals.h @@ -112,7 +112,7 @@ public: if (VectorTy *Vector = getAsVector()) delete Vector; - if (Vec.size() == 0) + if (Vec.empty()) Data = 0; else Data = (Vec[0] << 2) | DK_DeclID; diff --git a/include/clang/AST/ExternalASTSource.h b/include/clang/AST/ExternalASTSource.h index 17fa72612f..f8b3c4db4d 100644 --- a/include/clang/AST/ExternalASTSource.h +++ b/include/clang/AST/ExternalASTSource.h @@ -16,7 +16,6 @@ #include "clang/AST/DeclarationName.h" #include "clang/AST/Type.h" #include "llvm/ADT/SmallVector.h" - namespace clang { class Decl; diff --git a/include/clang/Frontend/PCHBitCodes.h b/include/clang/Frontend/PCHBitCodes.h index 00bd1cfac2..e4e50e3aa6 100644 --- a/include/clang/Frontend/PCHBitCodes.h +++ b/include/clang/Frontend/PCHBitCodes.h @@ -22,8 +22,24 @@ namespace clang { namespace pch { - const int IDBits = 32; - typedef uint32_t ID; + /// \brief An ID number that refers to a declaration in a PCH file. + /// + /// The ID numbers of types are consecutive (in order of + /// discovery) and start at 2. 0 is reserved for NULL, and 1 is + /// reserved for the translation unit declaration. + typedef uint32_t DeclID; + + /// \brief An ID number that refers to a type in a PCH file. + /// + /// The ID of a type is partitioned into two parts: the lower + /// three bits are used to store the const/volatile/restrict + /// qualifiers (as with QualType) and the upper bits provide a + /// type index. The type index values are partitioned into two + /// sets. The values below NUM_PREDEF_TYPE_IDs are predefined type + /// IDs (based on the PREDEF_TYPE_*_ID constants), with 0 as a + /// placeholder for "no type". Values from NUM_PREDEF_TYPE_IDs are + /// other types that have serialized representations. + typedef uint32_t TypeID; /// \brief Describes the various kinds of blocks that occur within /// a PCH file. @@ -48,23 +64,39 @@ namespace clang { /// types used within the PCH file. TYPES_BLOCK_ID, - /// \brief The block containing the offsets of all of the types - /// used within the PCH. - /// - /// The offsets in this block point into the block identified by - /// TYPES_BLOCK_ID, and are indexed by the type ID. - TYPE_OFFSETS_BLOCK_ID, - /// \brief The block containing the definitions of all of the /// declarations stored in the PCH file. - DECLS_BLOCK_ID, + DECLS_BLOCK_ID + }; - /// \brief The block containing the offsets of all of the - /// declarations stored within the PCH file. + /// \brief Record types that occur within the PCH block itself. + enum PCHRecordTypes { + /// \brief Offset of each type within the types block. /// - /// The offsets in this block point into the block identified by - /// DECLS_BLOCK_ID, and are indexed by the decaration ID. - DECL_OFFSETS_BLOCK_ID + /// The TYPE_OFFSET constant describes the record that occurs + /// within the block identified by TYPE_OFFSETS_BLOCK_ID within + /// the PCH file. The record itself is an array of offsets that + /// point into the types block (identified by TYPES_BLOCK_ID in + /// the PCH file). The index into the array is based on the ID + /// of a type. For a given type ID @c T, the lower three bits of + /// @c T are its qualifiers (const, volatile, restrict), as in + /// the QualType class. The upper bits, after being shifted and + /// subtracting NUM_PREDEF_TYPE_IDS, are used to index into the + /// TYPE_OFFSET block to determine the offset of that type's + /// corresponding record within the TYPES_BLOCK_ID block. + TYPE_OFFSET = 1, + + /// \brief Record code for the offsets of each decl. + /// + /// The DECL_OFFSET constant describes the record that occurs + /// within the block identifier by DECL_OFFSETS_BLOCK_ID within + /// the PCH file. The record itself is an array of offsets that + /// point into the declarations block (identified by + /// DECLS_BLOCK_ID). The declaration ID is an index into this + /// record, after subtracting one to account for the use of + /// declaration ID 0 for a NULL declaration pointer. Index 0 is + /// reserved for the translation unit declaration. + DECL_OFFSET = 2 }; /// \brief Record types used within a source manager block. @@ -209,20 +241,6 @@ namespace clang { /// \brief Record code for the offsets of each type. /// - /// The TYPE_OFFSET constant describes the record that occurs - /// within the block identified by TYPE_OFFSETS_BLOCK_ID within - /// the PCH file. The record itself is an array of offsets that - /// point into the types block (identified by TYPES_BLOCK_ID in - /// the PCH file). The index into the array is based on the ID of - /// a type. For a given type ID @c T, the lower three bits of @c T - /// are its qualifiers (const, volatile, restrict), as in the - /// QualType class. The upper bits, after being shifted and - /// subtracting NUM_PREDEF_TYPE_IDS, are used to index into the - /// TYPE_OFFSET block to determine the offset of that type's - /// corresponding record within the TYPES_BLOCK_ID block. - enum TypeOffsetCode { - TYPE_OFFSET = 1 - }; /// \brief Record codes for each kind of declaration. /// @@ -255,21 +273,6 @@ namespace clang { /// into a DeclContext via DeclContext::lookup. DECL_CONTEXT_VISIBLE }; - - /// \brief Record code for the offsets of each decl. - /// - /// The DECL_OFFSET constant describes the record that occurs - /// within the block identifier by DECL_OFFSETS_BLOCK_ID within - /// the PCH file. The record itself is an array of offsets that - /// point into the declarations block (identified by - /// DECLS_BLOCK_ID). The declaration ID is an index into this - /// record, after subtracting one to account for the use of - /// declaration ID 0 for a NULL declaration pointer. Index 0 is - /// reserved for the translation unit declaration. - enum DeclOffsetCode { - DECL_OFFSET = 1 - }; - /// @} } } // end namespace clang diff --git a/include/clang/Frontend/PCHReader.h b/include/clang/Frontend/PCHReader.h index fe7632896e..52354e3eb3 100644 --- a/include/clang/Frontend/PCHReader.h +++ b/include/clang/Frontend/PCHReader.h @@ -16,6 +16,7 @@ #include "clang/AST/DeclarationName.h" #include "clang/AST/ExternalASTSource.h" #include "clang/AST/Type.h" +#include "clang/Frontend/PCHBitCodes.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/SmallVector.h" @@ -100,8 +101,6 @@ class PCHReader : public ExternalASTSource { bool ReadPCHBlock(); bool ReadSourceManagerBlock(); - bool ReadTypeOffsets(); - bool ReadDeclOffsets(); QualType ReadTypeRecord(uint64_t Offset); void LoadedDecl(unsigned Index, Decl *D); @@ -122,11 +121,11 @@ public: /// \brief Resolve a type ID into a type, potentially building a new /// type. - virtual QualType GetType(unsigned ID); + virtual QualType GetType(pch::TypeID ID); /// \brief Resolve a declaration ID into a declaration, potentially /// building a new declaration. - virtual Decl *GetDecl(unsigned ID); + virtual Decl *GetDecl(pch::DeclID ID); /// \brief Read all of the declarations lexically stored in a /// declaration context. diff --git a/include/clang/Frontend/PCHWriter.h b/include/clang/Frontend/PCHWriter.h index 01eb2b0a77..a560857be2 100644 --- a/include/clang/Frontend/PCHWriter.h +++ b/include/clang/Frontend/PCHWriter.h @@ -50,7 +50,7 @@ class PCHWriter { /// The ID numbers of declarations are consecutive (in order of /// discovery) and start at 2. 1 is reserved for the translation /// unit, while 0 is reserved for NULL. - llvm::DenseMap DeclIDs; + llvm::DenseMap DeclIDs; /// \brief Offset of each declaration in the bitstream, indexed by /// the declaration's ID. @@ -67,14 +67,14 @@ class PCHWriter { /// and start at 1. 0 is reserved for NULL. When types are actually /// stored in the stream, the ID number is shifted by 3 bits to /// allow for the const/volatile/restrict qualifiers. - llvm::DenseMap TypeIDs; + llvm::DenseMap TypeIDs; /// \brief Offset of each type in the bitstream, indexed by /// the type's ID. llvm::SmallVector TypeOffsets; /// \brief The type ID that will be assigned to the next new type. - unsigned NextTypeID; + pch::TypeID NextTypeID; void WriteSourceManagerBlock(SourceManager &SourceMgr); void WritePreprocessor(Preprocessor &PP); diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index be349428ec..62783b140f 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -519,6 +519,13 @@ DeclContext::decl_iterator DeclContext::decls_end(ASTContext &Context) const { return decl_iterator(); } +bool DeclContext::decls_empty(ASTContext &Context) const { + if (hasExternalLexicalStorage()) + LoadLexicalDeclsFromExternalStorage(Context); + + return !FirstDecl; +} + void DeclContext::addDecl(ASTContext &Context, Decl *D) { assert(D->getLexicalDeclContext() == this && "Decl inserted into wrong lexical context"); diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp index 01a79b44d9..0e5b6ee8aa 100644 --- a/lib/Frontend/PCHReader.cpp +++ b/lib/Frontend/PCHReader.cpp @@ -192,129 +192,63 @@ bool PCHReader::ReadSourceManagerBlock() { } } -/// \brief Read the type-offsets block. -bool PCHReader::ReadTypeOffsets() { - if (Stream.EnterSubBlock(pch::TYPE_OFFSETS_BLOCK_ID)) +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. RecordData Record; - while (true) { + while (!Stream.AtEndOfStream()) { unsigned Code = Stream.ReadCode(); if (Code == llvm::bitc::END_BLOCK) { if (Stream.ReadBlockEnd()) - return Error("Error at end of TYPE_OFFSETS block"); + return Error("Error at end of module 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"); + 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::SOURCE_MANAGER_BLOCK_ID: + if (ReadSourceManagerBlock()) + return Error("Malformed source manager block"); + break; + } continue; } - + if (Code == llvm::bitc::DEFINE_ABBREV) { Stream.ReadAbbrevRecord(); continue; } - - // Read a record. + + // Read and process a record. Record.clear(); - switch (Stream.ReadRecord(Code, Record)) { + switch ((pch::PCHRecordTypes)Stream.ReadRecord(Code, Record)) { default: // Default behavior: ignore. break; + case pch::TYPE_OFFSET: if (!TypeOffsets.empty()) - return Error("Duplicate TYPE_OFFSETS block"); + return Error("Duplicate TYPE_OFFSET record in PCH file"); 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"); + return Error("Duplicate DECL_OFFSET record in PCH file"); 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::SOURCE_MANAGER_BLOCK_ID: - if (ReadSourceManagerBlock()) - return Error("Malformed source manager block"); - 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"); } @@ -426,7 +360,7 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) { // FIXME: Several other kinds of types to deserialize here! default: - assert("Unable to deserialize this type"); + assert(false && "Unable to deserialize this type"); break; } @@ -500,7 +434,7 @@ Decl *PCHReader::ReadDeclRecord(uint64_t Offset, unsigned Index) { return D; } -QualType PCHReader::GetType(unsigned ID) { +QualType PCHReader::GetType(pch::TypeID ID) { unsigned Quals = ID & 0x07; unsigned Index = ID >> 3; @@ -550,7 +484,7 @@ QualType PCHReader::GetType(unsigned ID) { return QualType(reinterpret_cast(TypeOffsets[Index]), Quals); } -Decl *PCHReader::GetDecl(unsigned ID) { +Decl *PCHReader::GetDecl(pch::DeclID ID) { if (ID == 0) return 0; @@ -563,7 +497,7 @@ Decl *PCHReader::GetDecl(unsigned ID) { } bool PCHReader::ReadDeclsLexicallyInContext(DeclContext *DC, - llvm::SmallVectorImpl &Decls) { + llvm::SmallVectorImpl &Decls) { assert(DC->hasExternalLexicalStorage() && "DeclContext has no lexical decls in storage"); uint64_t Offset = DeclContextOffsets[DC].first; diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp index 1986b5945f..f80d46ab5d 100644 --- a/lib/Frontend/PCHWriter.cpp +++ b/lib/Frontend/PCHWriter.cpp @@ -490,7 +490,7 @@ void PCHWriter::WritePreprocessor(Preprocessor &PP) { /// \brief Write the representation of a type to the PCH stream. void PCHWriter::WriteType(const Type *T) { - pch::ID &ID = TypeIDs[T]; + pch::TypeID &ID = TypeIDs[T]; if (ID == 0) // we haven't seen this type before. ID = NextTypeID++; @@ -547,10 +547,8 @@ void PCHWriter::WriteTypesBlock(ASTContext &Context) { // Exit the types block S.ExitBlock(); - // Write the type offsets block - S.EnterSubblock(pch::TYPE_OFFSETS_BLOCK_ID, 2); + // Write the type offsets record S.EmitRecord(pch::TYPE_OFFSET, TypeOffsets); - S.ExitBlock(); } /// \brief Write the block containing all of the declaration IDs @@ -560,7 +558,7 @@ void PCHWriter::WriteTypesBlock(ASTContext &Context) { /// 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)) + if (DC->decls_empty(Context)) return 0; uint64_t Offset = S.GetCurrentBitNo(); @@ -638,7 +636,7 @@ void PCHWriter::WriteDeclsBlock(ASTContext &Context) { } // Determine the ID for this declaration - pch::ID ID = DeclIDs[D]; + pch::DeclID ID = DeclIDs[D]; if (ID == 0) ID = DeclIDs.size(); @@ -664,10 +662,8 @@ void PCHWriter::WriteDeclsBlock(ASTContext &Context) { // Exit the declarations block S.ExitBlock(); - // Write the declaration offsets block - S.EnterSubblock(pch::DECL_OFFSETS_BLOCK_ID, 2); + // Write the declaration offsets record S.EmitRecord(pch::DECL_OFFSET, DeclOffsets); - S.ExitBlock(); } PCHWriter::PCHWriter(llvm::BitstreamWriter &S) @@ -720,7 +716,7 @@ void PCHWriter::AddTypeRef(QualType T, RecordData &Record) { } if (const BuiltinType *BT = dyn_cast(T.getTypePtr())) { - pch::ID ID; + pch::TypeID ID; switch (BT->getKind()) { case BuiltinType::Void: ID = pch::PREDEF_TYPE_VOID_ID; break; case BuiltinType::Bool: ID = pch::PREDEF_TYPE_BOOL_ID; break; @@ -748,7 +744,7 @@ void PCHWriter::AddTypeRef(QualType T, RecordData &Record) { return; } - pch::ID &ID = TypeIDs[T.getTypePtr()]; + pch::TypeID &ID = TypeIDs[T.getTypePtr()]; if (ID == 0) // we haven't seen this type before ID = NextTypeID++; @@ -762,7 +758,7 @@ void PCHWriter::AddDeclRef(const Decl *D, RecordData &Record) { return; } - pch::ID &ID = DeclIDs[D]; + pch::DeclID &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. diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index b024d36acc..4f87b48eff 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -526,6 +526,16 @@ bool Sema::MergeTypeDefDecl(TypedefDecl *New, Decl *OldD) { // __builtin_va_list gets redeclared in the built-in definitions // buffer when using PCH. Don't complain about such redefinitions. + // + // FIXME: The problem here is that the __builtin_va_list declaration + // comes in as target-specific text in the predefines buffer, both + // in the generation of the PCH file and in the source file. Thus, + // we end up with two typedefs for the same type, which is an error + // in C. Our hackish solution is to allow redundant typedefs *to the + // same type* if the types are defined in the predefined buffer. We + // would like to eliminate this ugliness, perhaps by making + // __builtin_va_list a real, Sema-supplied declaration rather than + // putting its text into the predefines buffer. if (Context.getExternalSource() && strcmp(SourceMgr.getBufferName(New->getLocation()), "") == 0) return false; diff --git a/test/PCH/variables.c b/test/PCH/variables.c index a5283f92ad..ffb9ec08c0 100644 --- a/test/PCH/variables.c +++ b/test/PCH/variables.c @@ -1,5 +1,5 @@ -// RUN: clang-cc -emit-pch -o %t %S/variables.h && -// RUN: clang-cc -include-pch %t -fsyntax-only -verify %s +// RUN: clang-cc -emit-pch -triple=i686-apple-darwin9 -o %t %S/variables.h && +// RUN: clang-cc -triple=i686-apple-darwin9 -include-pch %t -fsyntax-only -verify %s int *ip2 = &x; float *fp = &ip; // expected-warning{{incompatible pointer types}}