#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/OwningPtr.h"
#include "llvm/Bitcode/SerializationFwd.h"
#include "llvm/Support/Allocator.h"
#include <vector>
class FileManager;
class ASTRecordLayout;
class Expr;
+ class ExternalASTSource;
class IdentifierTable;
class SelectorTable;
class SourceManager;
IdentifierTable &Idents;
SelectorTable &Selectors;
DeclarationNameTable DeclarationNames;
+ llvm::OwningPtr<ExternalASTSource> ExternalSource;
SourceManager& getSourceManager() { return SourceMgr; }
const SourceManager& getSourceManager() const { return SourceMgr; }
~ASTContext();
+ /// \brief Attach an external AST source to the AST context.
+ ///
+ /// The external AST source provides the ability to load parts of
+ /// the abstract syntax tree as needed from some external storage,
+ /// e.g., a precompiled header.
+ void setExternalSource(llvm::OwningPtr<ExternalASTSource> &Source);
+
+ /// \brief Retrieve a pointer to the external AST source associated
+ /// with this AST context, if any.
+ ExternalASTSource *getExternalSource() const { return ExternalSource.get(); }
+
void PrintStats() const;
const std::vector<Type*>& getTypes() const { return Types; }
/// DeclKind - This indicates which class this is.
Decl::Kind DeclKind : 8;
+ /// \brief Whether this declaration context also has some external
+ /// storage that contains additional declarations that are lexically
+ /// part of this context.
+ mutable bool ExternalLexicalStorage : 1;
+
+ /// \brief Whether this declaration context also has some external
+ /// storage that contains additional declarations that are visible
+ /// in this context.
+ mutable bool ExternalVisibleStorage : 1;
+
/// \brief Pointer to the data structure used to lookup declarations
/// within this context, which is a DenseMap<DeclarationName,
/// StoredDeclsList>.
- void* LookupPtr;
+ mutable void* LookupPtr;
/// FirstDecl - The first declaration stored within this declaration
/// context.
- Decl *FirstDecl;
+ mutable Decl *FirstDecl;
/// LastDecl - The last declaration stored within this declaration
/// context. FIXME: We could probably cache this value somewhere
/// outside of the DeclContext, to reduce the size of DeclContext by
/// another pointer.
- Decl *LastDecl;
+ mutable Decl *LastDecl;
protected:
DeclContext(Decl::Kind K)
- : DeclKind(K), LookupPtr(0), FirstDecl(0), LastDecl(0) { }
+ : DeclKind(K), ExternalLexicalStorage(false),
+ ExternalVisibleStorage(false), LookupPtr(0), FirstDecl(0),
+ LastDecl(0) { }
void DestroyDecls(ASTContext &C);
/// \brief Retrieve the internal representation of the lookup structure.
void* getLookupPtr() const { return LookupPtr; }
+ /// \brief Whether this DeclContext has external storage containing
+ /// additional declarations that are lexically in this context.
+ bool hasExternalLexicalStorage() const { return ExternalLexicalStorage; }
+
+ /// \brief State whether this DeclContext has external storage for
+ /// declarations lexically in this context.
+ void setHasExternalLexicalStorage(bool ES = true) {
+ ExternalLexicalStorage = ES;
+ }
+
+ /// \brief Whether this DeclContext has external storage containing
+ /// additional declarations that are visible in this context.
+ bool hasExternalVisibleStorage() const { return ExternalVisibleStorage; }
+
+ /// \brief State whether this DeclContext has external storage for
+ /// declarations visible in this context.
+ void setHasExternalVisibleStorage(bool ES = true) {
+ ExternalVisibleStorage = ES;
+ }
+
static bool classof(const Decl *D);
static bool classof(const DeclContext *D) { return true; }
#define DECL_CONTEXT(Name) \
#include "clang/AST/DeclNodes.def"
private:
+ void LoadLexicalDeclsFromExternalStorage(ASTContext &Context) const;
+ void LoadVisibleDeclsFromExternalStorage(ASTContext &Context) const;
+
void buildLookup(ASTContext &Context, DeclContext *DCtx);
void makeDeclVisibleInContextImpl(ASTContext &Context, NamedDecl *D);
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/PointerUnion.h"
#include "llvm/ADT/SmallVector.h"
-#include <functional>
+#include <algorithm>
namespace clang {
/// StoredDeclsList - This is an array of decls optimized a common case of only
/// containing one entry.
struct StoredDeclsList {
+ /// The kind of data encoded in this list.
+ enum DataKind {
+ /// \brief The data is a NamedDecl*.
+ DK_Decl = 0,
+ /// \brief The data is a declaration ID (an unsigned value),
+ /// shifted left by 2 bits.
+ DK_DeclID = 1,
+ /// \brief The data is a pointer to a vector (of type VectorTy)
+ /// that contains declarations.
+ DK_Decl_Vector = 2,
+ /// \brief The data is a pointer to a vector (of type VectorTy)
+ /// that contains declaration ID.
+ DK_ID_Vector = 3
+ };
+
/// VectorTy - When in vector form, this is what the Data pointer points to.
- typedef llvm::SmallVector<NamedDecl*, 4> VectorTy;
+ typedef llvm::SmallVector<uintptr_t, 4> VectorTy;
+
+ /// \brief The stored data, which will be either a declaration ID, a
+ /// pointer to a NamedDecl, or a pointer to a vector.
+ uintptr_t Data;
- /// Data - Union of NamedDecl*/VectorTy*.
- llvm::PointerUnion<NamedDecl*, VectorTy*> Data;
public:
- StoredDeclsList() {}
+ StoredDeclsList() : Data(0) {}
+
StoredDeclsList(const StoredDeclsList &RHS) : Data(RHS.Data) {
- if (isVector())
- Data = new VectorTy(*Data.get<VectorTy*>());
+ if (VectorTy *RHSVec = RHS.getAsVector()) {
+ VectorTy *New = new VectorTy(*RHSVec);
+ Data = reinterpret_cast<uintptr_t>(New) | (Data & 0x03);
+ }
}
~StoredDeclsList() {
// If this is a vector-form, free the vector.
- if (isVector())
- delete Data.get<VectorTy*>();
+ if (VectorTy *Vector = getAsVector())
+ delete Vector;
}
StoredDeclsList &operator=(const StoredDeclsList &RHS) {
- if (isVector())
- delete Data.get<VectorTy*>();
+ if (VectorTy *Vector = getAsVector())
+ delete Vector;
Data = RHS.Data;
- if (isVector())
- Data = new VectorTy(*Data.get<VectorTy*>());
+ if (VectorTy *RHSVec = RHS.getAsVector()) {
+ VectorTy *New = new VectorTy(*RHSVec);
+ Data = reinterpret_cast<uintptr_t>(New) | (Data & 0x03);
+ }
return *this;
}
- bool isVector() const { return Data.is<VectorTy*>(); }
- bool isInline() const { return Data.is<NamedDecl*>(); }
- bool isNull() const { return Data.isNull(); }
+ bool isNull() const { return (Data & ~0x03) == 0; }
+ NamedDecl *getAsDecl() const {
+ if ((Data & 0x03) != DK_Decl)
+ return 0;
+
+ return reinterpret_cast<NamedDecl *>(Data & ~0x03);
+ }
+
+ VectorTy *getAsVector() const {
+ if ((Data & 0x03) != DK_ID_Vector && (Data & 0x03) != DK_Decl_Vector)
+ return 0;
+
+ return reinterpret_cast<VectorTy *>(Data & ~0x03);
+ }
+
void setOnlyValue(NamedDecl *ND) {
- assert(isInline() && "Not inline");
- Data = ND;
+ assert(!getAsVector() && "Not inline");
+ Data = reinterpret_cast<uintptr_t>(ND);
+ }
+
+ void setFromDeclIDs(const llvm::SmallVectorImpl<unsigned> &Vec) {
+ if (Vec.size() > 1) {
+ VectorTy *Vector = getAsVector();
+ if (!Vector) {
+ Vector = new VectorTy;
+ Data = reinterpret_cast<uintptr_t>(Vector) | DK_Decl_Vector;
+ }
+
+ Vector->resize(Vec.size());
+ std::copy(Vec.begin(), Vec.end(), Vector->begin());
+ return;
+ }
+
+ if (VectorTy *Vector = getAsVector())
+ delete Vector;
+
+ if (Vec.size() == 0)
+ Data = 0;
+ else
+ Data = (Vec[0] << 2) | DK_DeclID;
+ }
+
+ /// \brief Force the stored declarations list to contain actual
+ /// declarations.
+ ///
+ /// This routine will resolve any declaration IDs for declarations
+ /// that may not yet have been loaded from external storage.
+ void materializeDecls(ASTContext &Context);
+
+ bool hasDeclarationIDs() const {
+ DataKind DK = (DataKind)(Data & 0x03);
+ return DK == DK_DeclID || DK == DK_ID_Vector;
}
/// getLookupResult - Return an array of all the decls that this list
/// represents.
DeclContext::lookup_result getLookupResult(ASTContext &Context) {
- // If we have a single inline unit, return it.
- if (isInline()) {
+ if (isNull())
+ return DeclContext::lookup_result(0, 0);
+
+ if (hasDeclarationIDs())
+ materializeDecls(Context);
+
+ // If we have a single NamedDecl, return it.
+ if (getAsDecl()) {
assert(!isNull() && "Empty list isn't allowed");
// Data is a raw pointer to a NamedDecl*, return it.
return DeclContext::lookup_result((NamedDecl**)Ptr, (NamedDecl**)Ptr+1);
}
+ assert(getAsVector() && "Must have a vector at this point");
+ VectorTy &Vector = *getAsVector();
+
// Otherwise, we have a range result.
- VectorTy &V = *Data.get<VectorTy*>();
- return DeclContext::lookup_result(&V[0], &V[0]+V.size());
+ return DeclContext::lookup_result((NamedDecl **)&Vector[0],
+ (NamedDecl **)&Vector[0]+Vector.size());
}
/// HandleRedeclaration - If this is a redeclaration of an existing decl,
/// replace the old one with D and return true. Otherwise return false.
bool HandleRedeclaration(ASTContext &Context, NamedDecl *D) {
+ if (hasDeclarationIDs())
+ materializeDecls(Context);
+
// Most decls only have one entry in their list, special case it.
- if (isInline()) {
- if (!D->declarationReplaces(Data.get<NamedDecl*>()))
+ if (NamedDecl *OldD = getAsDecl()) {
+ if (!D->declarationReplaces(OldD))
return false;
setOnlyValue(D);
return true;
}
// Determine if this declaration is actually a redeclaration.
- VectorTy &Vec = *Data.get<VectorTy*>();
- VectorTy::iterator RDI
- = std::find_if(Vec.begin(), Vec.end(),
- std::bind1st(std::mem_fun(&NamedDecl::declarationReplaces),
- D));
- if (RDI == Vec.end())
- return false;
- *RDI = D;
- return true;
+ VectorTy &Vec = *getAsVector();
+ for (VectorTy::iterator OD = Vec.begin(), ODEnd = Vec.end();
+ OD != ODEnd; ++OD) {
+ NamedDecl *OldD = reinterpret_cast<NamedDecl *>(*OD);
+ if (D->declarationReplaces(OldD)) {
+ *OD = reinterpret_cast<uintptr_t>(D);
+ return true;
+ }
+ }
+
+ return false;
}
/// AddSubsequentDecl - This is called on the second and later decl when it is
/// not a redeclaration to merge it into the appropriate place in our list.
///
void AddSubsequentDecl(NamedDecl *D) {
+ assert(!hasDeclarationIDs() && "Must materialize before adding decls");
+
// If this is the second decl added to the list, convert this to vector
// form.
- if (isInline()) {
- NamedDecl *OldD = Data.get<NamedDecl*>();
+ if (NamedDecl *OldD = getAsDecl()) {
VectorTy *VT = new VectorTy();
- VT->push_back(OldD);
- Data = VT;
+ VT->push_back(reinterpret_cast<uintptr_t>(OldD));
+ Data = reinterpret_cast<uintptr_t>(VT) | DK_Decl_Vector;
}
- VectorTy &Vec = *Data.get<VectorTy*>();
+ VectorTy &Vec = *getAsVector();
if (isa<UsingDirectiveDecl>(D) ||
D->getIdentifierNamespace() == Decl::IDNS_Tag)
- Vec.push_back(D);
- else if (Vec.back()->getIdentifierNamespace() == Decl::IDNS_Tag) {
- NamedDecl *TagD = Vec.back();
- Vec.back() = D;
+ Vec.push_back(reinterpret_cast<uintptr_t>(D));
+ else if (reinterpret_cast<NamedDecl *>(Vec.back())
+ ->getIdentifierNamespace() == Decl::IDNS_Tag) {
+ uintptr_t TagD = Vec.back();
+ Vec.back() = reinterpret_cast<uintptr_t>(D);
Vec.push_back(TagD);
} else
- Vec.push_back(D);
+ Vec.push_back(reinterpret_cast<uintptr_t>(D));
}
};
--- /dev/null
+//===--- ExternalASTSource.h - Abstract External AST Interface --*- 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 ExternalASTSource interface,
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_AST_EXTERNAL_AST_SOURCE_H
+#define LLVM_CLANG_AST_EXTERNAL_AST_SOURCE_H
+
+#include "clang/AST/DeclarationName.h"
+#include "clang/AST/Type.h"
+#include "llvm/ADT/SmallVector.h"
+
+namespace clang {
+
+class Decl;
+class DeclContext;
+
+/// \brief The deserialized representation of a set of declarations
+/// with the same name that are visible in a given context.
+struct VisibleDeclaration {
+ /// \brief The name of the declarations.
+ DeclarationName Name;
+
+ /// \brief The ID numbers of all of the declarations with this name.
+ ///
+ /// These declarations have not necessarily been de-serialized.
+ llvm::SmallVector<unsigned, 4> Declarations;
+};
+
+/// \brief Abstract interface for external sources of AST nodes.
+///
+/// External AST sources provide AST nodes constructed from some
+/// external source, such as a precompiled header. External AST
+/// sources can resolve types and declarations from abstract IDs into
+/// actual type and declaration nodes, and read parts of declaration
+/// contexts.
+class ExternalASTSource {
+public:
+ virtual ~ExternalASTSource();
+
+ /// \brief Resolve a type ID into a type, potentially building a new
+ /// type.
+ virtual QualType GetType(unsigned ID) = 0;
+
+ /// \brief Resolve a declaration ID into a declaration, potentially
+ /// building a new declaration.
+ virtual Decl *GetDecl(unsigned ID) = 0;
+
+ /// \brief Read all of the declarations lexically stored in a
+ /// declaration context.
+ ///
+ /// \param DC The declaration context whose declarations will be
+ /// read.
+ ///
+ /// \param Decls Vector that will contain the declarations loaded
+ /// from the external source. The caller is responsible for merging
+ /// these declarations with any declarations already stored in the
+ /// declaration context.
+ ///
+ /// \returns true if there was an error while reading the
+ /// declarations for this declaration context.
+ virtual bool ReadDeclsLexicallyInContext(DeclContext *DC,
+ llvm::SmallVectorImpl<unsigned> &Decls) = 0;
+
+ /// \brief Read all of the declarations visible from a declaration
+ /// context.
+ ///
+ /// \param DC The declaration context whose visible declarations
+ /// will be read.
+ ///
+ /// \param Decls A vector of visible declaration structures,
+ /// providing the mapping from each name visible in the declaration
+ /// context to the declaration IDs of declarations with that name.
+ ///
+ /// \returns true if there was an error while reading the
+ /// declarations for this declaration context.
+ virtual bool ReadDeclsVisibleInContext(DeclContext *DC,
+ llvm::SmallVectorImpl<VisibleDeclaration> & Decls) = 0;
+
+ /// \brief Print any statistics that have been gathered regarding
+ /// the external AST source.
+ virtual void PrintStats();
+};
+
+} // end namespace clang
+
+#endif // LLVM_CLANG_AST_EXTERNAL_AST_SOURCE_H
--- /dev/null
+//===- PCHBitCodes.h - Enum values for the PCH bitcode format ---*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This header defines Bitcode enum values for Clang precompiled header files.
+//
+// The enum values defined in this file should be considered permanent. If
+// new features are added, they should have values added at the end of the
+// respective lists.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_FRONTEND_PCHBITCODES_H
+#define LLVM_CLANG_FRONTEND_PCHBITCODES_H
+
+#include "llvm/Bitcode/BitCodes.h"
+#include "llvm/Support/DataTypes.h"
+
+namespace clang {
+ namespace pch {
+ const int IDBits = 32;
+ typedef uint32_t ID;
+
+ /// \brief Describes the various kinds of blocks that occur within
+ /// a PCH file.
+ enum BlockIDs {
+ /// \brief The PCH block, which acts as a container around the
+ /// full PCH block.
+ PCH_BLOCK_ID = llvm::bitc::FIRST_APPLICATION_BLOCKID,
+
+ /// \brief The block containing the definitions of all of the
+ /// 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,
+
+ /// \brief The block containing the offsets of all of the
+ /// declarations stored within the PCH file.
+ ///
+ /// 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
+ };
+
+ /// \brief Predefined type IDs.
+ ///
+ /// These type IDs correspond to predefined types in the AST
+ /// context, such as built-in types (int) and special place-holder
+ /// types (the <overload> and <dependent> type markers). Such
+ /// types are never actually serialized, since they will be built
+ /// by the AST context when it is created.
+ enum PredefinedTypeIDs {
+ /// \brief The NULL type.
+ PREDEF_TYPE_NULL_ID = 0,
+ /// \brief The void type.
+ PREDEF_TYPE_VOID_ID = 1,
+ /// \brief The 'bool' or '_Bool' type.
+ PREDEF_TYPE_BOOL_ID = 2,
+ /// \brief The 'char' type, when it is unsigned.
+ PREDEF_TYPE_CHAR_U_ID = 3,
+ /// \brief The 'unsigned char' type.
+ PREDEF_TYPE_UCHAR_ID = 4,
+ /// \brief The 'unsigned short' type.
+ PREDEF_TYPE_USHORT_ID = 5,
+ /// \brief The 'unsigned int' type.
+ PREDEF_TYPE_UINT_ID = 6,
+ /// \brief The 'unsigned long' type.
+ PREDEF_TYPE_ULONG_ID = 7,
+ /// \brief The 'unsigned long long' type.
+ PREDEF_TYPE_ULONGLONG_ID = 8,
+ /// \brief The 'char' type, when it is signed.
+ PREDEF_TYPE_CHAR_S_ID = 9,
+ /// \brief The 'signed char' type.
+ PREDEF_TYPE_SCHAR_ID = 10,
+ /// \brief The C++ 'wchar_t' type.
+ PREDEF_TYPE_WCHAR_ID = 11,
+ /// \brief The (signed) 'short' type.
+ PREDEF_TYPE_SHORT_ID = 12,
+ /// \brief The (signed) 'int' type.
+ PREDEF_TYPE_INT_ID = 13,
+ /// \brief The (signed) 'long' type.
+ PREDEF_TYPE_LONG_ID = 14,
+ /// \brief The (signed) 'long long' type.
+ PREDEF_TYPE_LONGLONG_ID = 15,
+ /// \brief The 'float' type.
+ PREDEF_TYPE_FLOAT_ID = 16,
+ /// \brief The 'double' type.
+ PREDEF_TYPE_DOUBLE_ID = 17,
+ /// \brief The 'long double' type.
+ PREDEF_TYPE_LONGDOUBLE_ID = 18,
+ /// \brief The placeholder type for overloaded function sets.
+ PREDEF_TYPE_OVERLOAD_ID = 19,
+ /// \brief The placeholder type for dependent types.
+ PREDEF_TYPE_DEPENDENT_ID = 20
+ };
+
+ /// \brief The number of predefined type IDs that are reserved for
+ /// the PREDEF_TYPE_* constants.
+ ///
+ /// Type IDs for non-predefined types will start at
+ /// NUM_PREDEF_TYPE_IDs.
+ const unsigned NUM_PREDEF_TYPE_IDS = 100;
+
+ /// \brief Record codes for each kind of type.
+ ///
+ /// These constants describe the records that can occur within a
+ /// block identified by TYPES_BLOCK_ID in the PCH file. Each
+ /// constant describes a record for a specific type class in the
+ /// AST.
+ enum TypeCode {
+ /// \brief An ExtQualType record.
+ TYPE_EXT_QUAL = 1,
+ /// \brief A FixedWidthIntType record.
+ TYPE_FIXED_WIDTH_INT = 2,
+ /// \brief A ComplexType record.
+ TYPE_COMPLEX = 3,
+ /// \brief A PointerType record.
+ TYPE_POINTER = 4,
+ /// \brief A BlockPointerType record.
+ TYPE_BLOCK_POINTER = 5,
+ /// \brief An LValueReferenceType record.
+ TYPE_LVALUE_REFERENCE = 6,
+ /// \brief An RValueReferenceType record.
+ TYPE_RVALUE_REFERENCE = 7,
+ /// \brief A MemberPointerType record.
+ TYPE_MEMBER_POINTER = 8,
+ /// \brief A ConstantArrayType record.
+ TYPE_CONSTANT_ARRAY = 9,
+ /// \brief An IncompleteArrayType record.
+ TYPE_INCOMPLETE_ARRAY = 10,
+ /// \brief A VariableArrayType record.
+ TYPE_VARIABLE_ARRAY = 11,
+ /// \brief A VectorType record.
+ TYPE_VECTOR = 12,
+ /// \brief An ExtVectorType record.
+ TYPE_EXT_VECTOR = 13,
+ /// \brief A FunctionNoProtoType record.
+ TYPE_FUNCTION_NO_PROTO = 14,
+ /// \brief A FunctionProtoType record.
+ TYPE_FUNCTION_PROTO = 15,
+ /// \brief A TypedefType record.
+ TYPE_TYPEDEF = 16,
+ /// \brief A TypeOfExprType record.
+ TYPE_TYPEOF_EXPR = 17,
+ /// \brief A TypeOfType record.
+ TYPE_TYPEOF = 18,
+ /// \brief A RecordType record.
+ TYPE_RECORD = 19,
+ /// \brief An EnumType record.
+ TYPE_ENUM = 20,
+ /// \brief An ObjCInterfaceType record.
+ TYPE_OBJC_INTERFACE = 21,
+ /// \brief An ObjCQualifiedInterfaceType record.
+ TYPE_OBJC_QUALIFIED_INTERFACE = 22,
+ /// \brief An ObjCQualifiedIdType record.
+ TYPE_OBJC_QUALIFIED_ID = 23,
+ /// \brief An ObjCQualifiedClassType record.
+ TYPE_OBJC_QUALIFIED_CLASS = 24
+ };
+
+ /// \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.
+ ///
+ /// These constants describe the records that can occur within a
+ /// declarations block (identified by DECLS_BLOCK_ID). Each
+ /// constant describes a record for a specific declaration class
+ /// in the AST.
+ enum DeclCode {
+ /// \brief A TranslationUnitDecl record.
+ DECL_TRANSLATION_UNIT = 1,
+ /// \brief A TypedefDecl record.
+ DECL_TYPEDEF,
+ /// \brief A VarDecl record.
+ DECL_VAR,
+ /// \brief A record that stores the set of declarations that are
+ /// lexically stored within a given DeclContext.
+ ///
+ /// The record itself is an array of declaration IDs, in the
+ /// order in which those declarations were added to the
+ /// declaration context. This data is used when iterating over
+ /// the contents of a DeclContext, e.g., via
+ /// DeclContext::decls_begin()/DeclContext::decls_end().
+ DECL_CONTEXT_LEXICAL,
+ /// \brief A record that stores the set of declarations that are
+ /// visible from a given DeclContext.
+ ///
+ /// The record itself stores a set of mappings, each of which
+ /// associates a declaration name with one or more declaration
+ /// IDs. This data is used when performing qualified name lookup
+ /// 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
+
+#endif
--- /dev/null
+//===--- PCHReader.h - 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.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_FRONTEND_PCH_READER_H
+#define LLVM_CLANG_FRONTEND_PCH_READER_H
+
+#include "clang/AST/DeclarationName.h"
+#include "clang/AST/ExternalASTSource.h"
+#include "clang/AST/Type.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Bitcode/BitstreamReader.h"
+#include "llvm/Support/DataTypes.h"
+#include <string>
+#include <utility>
+#include <vector>
+
+namespace llvm {
+ class MemoryBuffer;
+}
+
+namespace clang {
+
+class ASTContext;
+class Decl;
+class DeclContext;
+
+/// \brief Reads a precompiled head containing the contents of a
+/// translation unit.
+///
+/// The PCHReader class reads a bitstream (produced by the PCHWriter
+/// class) containing the serialized representation of a given
+/// abstract syntax tree and its supporting data structures. An
+/// instance of the PCHReader can be attached to an ASTContext object,
+/// which will provide access to the contents of the PCH file.
+///
+/// The PCH reader provides lazy de-serialization of declarations, as
+/// required when traversing the AST. Only those AST nodes that are
+/// actually required will be de-serialized.
+class PCHReader : public ExternalASTSource {
+ /// \brief The AST context into which we'll read the PCH file.
+ ASTContext &Context;
+
+ /// \brief The bitstream reader from which we'll read the PCH file.
+ llvm::BitstreamReader Stream;
+
+ /// \brief The memory buffer that stores the data associated with
+ /// this PCH file.
+ llvm::OwningPtr<llvm::MemoryBuffer> Buffer;
+
+ /// \brief Offset of each type within the bitstream, indexed by the
+ /// type ID, or the representation of a Type*.
+ llvm::SmallVector<uint64_t, 16> TypeOffsets;
+
+ /// \brief Whether the type with a given index has already been loaded.
+ ///
+ /// When the bit at a given index I is true, then TypeOffsets[I] is
+ /// the already-loaded Type*. Otherwise, TypeOffsets[I] is the
+ /// location of the type's record in the PCH file.
+ ///
+ /// FIXME: We can probably eliminate this, e.g., by bitmangling the
+ /// values in TypeOffsets.
+ std::vector<bool> TypeAlreadyLoaded;
+
+ /// \brief Offset of each declaration within the bitstream, indexed
+ /// by the declaration ID.
+ llvm::SmallVector<uint64_t, 16> DeclOffsets;
+
+ /// \brief Whether the declaration with a given index has already
+ /// been loaded.
+ ///
+ /// When the bit at the given index I is true, then DeclOffsets[I]
+ /// is the already-loaded Decl*. Otherwise, DeclOffsets[I] is the
+ /// location of the declaration's record in the PCH file.
+ ///
+ /// FIXME: We can probably eliminate this, e.g., by bitmangling the
+ /// values in DeclOffsets.
+ std::vector<bool> DeclAlreadyLoaded;
+
+ typedef llvm::DenseMap<const DeclContext *, std::pair<uint64_t, uint64_t> >
+ DeclContextOffsetsMap;
+
+ /// \brief Offsets of the lexical and visible declarations for each
+ /// DeclContext.
+ DeclContextOffsetsMap DeclContextOffsets;
+
+ bool ReadPCHBlock();
+ bool ReadTypeOffsets();
+ bool ReadDeclOffsets();
+
+ QualType ReadTypeRecord(uint64_t Offset);
+ void LoadedDecl(unsigned Index, Decl *D);
+ Decl *ReadDeclRecord(uint64_t Offset, unsigned Index);
+
+ PCHReader(const PCHReader&); // do not implement
+ PCHReader &operator=(const PCHReader &); // do not implement
+
+public:
+ typedef llvm::SmallVector<uint64_t, 64> RecordData;
+
+ PCHReader(ASTContext &Context) : Context(Context), Buffer() { }
+ ~PCHReader();
+
+ bool ReadPCH(const std::string &FileName);
+
+ /// \brief Resolve a type ID into a type, potentially building a new
+ /// type.
+ virtual QualType GetType(unsigned ID);
+
+ /// \brief Resolve a declaration ID into a declaration, potentially
+ /// building a new declaration.
+ virtual Decl *GetDecl(unsigned ID);
+
+ /// \brief Read all of the declarations lexically stored in a
+ /// declaration context.
+ ///
+ /// \param DC The declaration context whose declarations will be
+ /// read.
+ ///
+ /// \param Decls Vector that will contain the declarations loaded
+ /// from the external source. The caller is responsible for merging
+ /// these declarations with any declarations already stored in the
+ /// declaration context.
+ ///
+ /// \returns true if there was an error while reading the
+ /// declarations for this declaration context.
+ virtual bool ReadDeclsLexicallyInContext(DeclContext *DC,
+ llvm::SmallVectorImpl<unsigned> &Decls);
+
+ /// \brief Read all of the declarations visible from a declaration
+ /// context.
+ ///
+ /// \param DC The declaration context whose visible declarations
+ /// will be read.
+ ///
+ /// \param Decls A vector of visible declaration structures,
+ /// providing the mapping from each name visible in the declaration
+ /// context to the declaration IDs of declarations with that name.
+ ///
+ /// \returns true if there was an error while reading the
+ /// declarations for this declaration context.
+ ///
+ /// FIXME: Using this intermediate data structure results in an
+ /// extraneous copying of the data. Could we pass in a reference to
+ /// the StoredDeclsMap instead?
+ virtual bool ReadDeclsVisibleInContext(DeclContext *DC,
+ llvm::SmallVectorImpl<VisibleDeclaration> & Decls);
+
+ /// \brief Print some statistics about PCH usage.
+ virtual void PrintStats();
+
+ const IdentifierInfo *GetIdentifierInfo(const RecordData &Record,
+ unsigned &Idx);
+ DeclarationName ReadDeclarationName(const RecordData &Record, unsigned &Idx);
+};
+
+} // end namespace clang
+
+#endif
--- /dev/null
+//===--- 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 containing a serialized representation of a translation
+// unit.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_FRONTEND_PCH_WRITER_H
+#define LLVM_CLANG_FRONTEND_PCH_WRITER_H
+
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclarationName.h"
+#include "clang/Frontend/PCHBitCodes.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallVector.h"
+#include <queue>
+
+namespace llvm {
+ class APInt;
+ class BitstreamWriter;
+}
+
+namespace clang {
+
+class ASTContext;
+
+/// \brief Writes a precompiled header containing the contents of a
+/// translation unit.
+///
+/// The PCHWriter class produces a bitstream containing the serialized
+/// representation of a given abstract syntax tree and its supporting
+/// data structures. This bitstream can be de-serialized via an
+/// instance of the PCHReader class.
+class PCHWriter {
+ /// \brief The bitstream writer used to emit this precompiled header.
+ llvm::BitstreamWriter &S;
+
+ /// \brief Map that provides the ID numbers of each declaration within
+ /// the output stream.
+ ///
+ /// 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<const Decl *, pch::ID> DeclIDs;
+
+ /// \brief Offset of each declaration in the bitstream, indexed by
+ /// the declaration's ID.
+ llvm::SmallVector<uint64_t, 16> DeclOffsets;
+
+ /// \brief Queue containing the declarations that we still need to
+ /// emit.
+ std::queue<Decl *> DeclsToEmit;
+
+ /// \brief Map that provides the ID numbers of each type within the
+ /// output stream.
+ ///
+ /// The ID numbers of types are consecutive (in order of discovery)
+ /// 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<const Type *, pch::ID> TypeIDs;
+
+ /// \brief Offset of each type in the bitstream, indexed by
+ /// the type's ID.
+ llvm::SmallVector<uint64_t, 16> TypeOffsets;
+
+ /// \brief The type ID that will be assigned to the next new type.
+ unsigned NextTypeID;
+
+ void WriteType(const Type *T);
+ void WriteTypesBlock(ASTContext &Context);
+ uint64_t WriteDeclContextLexicalBlock(ASTContext &Context, DeclContext *DC);
+ uint64_t WriteDeclContextVisibleBlock(ASTContext &Context, DeclContext *DC);
+ void WriteDeclsBlock(ASTContext &Context);
+
+public:
+ typedef llvm::SmallVector<uint64_t, 64> RecordData;
+
+ /// \brief Create a new precompiled header writer that outputs to
+ /// the given bitstream.
+ PCHWriter(llvm::BitstreamWriter &S);
+
+ /// \brief Write a precompiled header for the given AST context.
+ void WritePCH(ASTContext &Context);
+
+ /// \brief Emit a source location.
+ void AddSourceLocation(SourceLocation Loc, RecordData &Record);
+
+ /// \brief Emit an integral value.
+ void AddAPInt(const llvm::APInt &Value, RecordData &Record);
+
+ /// \brief Emit a reference to an identifier
+ void AddIdentifierRef(const IdentifierInfo *II, RecordData &Record);
+
+ /// \brief Emit a reference to a type.
+ void AddTypeRef(QualType T, RecordData &Record);
+
+ /// \brief Emit a reference to a declaration.
+ void AddDeclRef(const Decl *D, RecordData &Record);
+
+ /// \brief Emit a declaration name.
+ void AddDeclarationName(DeclarationName Name, RecordData &Record);
+};
+
+} // end namespace clang
+
+#endif
#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"
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);
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());
NumTypeName*sizeof(TypedefType)+NumTagged*sizeof(TagType)+
NumTypeOfTypes*sizeof(TypeOfType)+NumTypeOfExprTypes*sizeof(TypeOfExprType)+
NumExtQual*sizeof(ExtQualType)));
+
+ if (ExternalSource.get()) {
+ fprintf(stderr, "\n");
+ ExternalSource->PrintStats();
+ }
}
return A;
}
+
+ExternalASTSource::~ExternalASTSource() { }
+
+void ExternalASTSource::PrintStats() { }
#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"
}
}
+/// \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();
}
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.
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;
+ }
+ }
+}
--- /dev/null
+//===--- 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();
+}
--- /dev/null
+//===--- 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;
+ }
+}
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;
// 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 =
--- /dev/null
+// RUN: clang-cc -emit-pch -o %t %S/variables.h &&
+// RUN: clang-cc -include-pch %t -fsyntax-only -verify %s
+
+int *ip2 = &x;
+float *fp = &ip; // expected-warning{{incompatible pointer types}}
+
--- /dev/null
+// RUN: clang-cc -emit-pch -o variables.h.pch variables.h
+extern int x;
+extern float y;
+extern int *ip;
+float z;
#
# %s - Replaced with the input name of the program, or the program to
# execute, as appropriate.
+# %S - Replaced with the directory where the input file resides
# %prcontext - prcontext.tcl script
# %t - temporary file name (derived from testcase name)
#
FILENAME=$1
TESTNAME=$1
SUBST=$1
+FILEDIR=`dirname $TESTNAME`
OUTPUT=Output/$1.out
-e "s| clang | $CLANG |g" \
-e "s| clang-cc | $CLANGCC |g" \
-e "s|%s|$SUBST|g" \
+ -e "s|%S|$FILEDIR|g" \
-e "s|%prcontext|prcontext.tcl|g" \
-e "s|%t|$TEMPOUTPUT|g" > $SCRIPT
const std::string& EmitDir,
Diagnostic &Diags);
+ASTConsumer *CreatePCHGenerator(Diagnostic &Diags,
+ const LangOptions &Features,
+ const std::string& InFile,
+ const std::string& OutFile);
+
ASTConsumer *CreateBlockRewriter(const std::string& InFile,
const std::string& OutFile,
Diagnostic &Diags,
--- /dev/null
+//===--- GeneratePCH.cpp - AST Consumer for PCH Generation ------*- 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 CreatePCHGenerate function, which creates an
+// ASTConsume that generates a PCH file.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/PCHWriter.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTConsumer.h"
+#include "llvm/Bitcode/BitstreamWriter.h"
+#include "llvm/System/Path.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/Streams.h"
+#include <string>
+
+using namespace clang;
+using namespace llvm;
+
+namespace {
+ class VISIBILITY_HIDDEN PCHGenerator : public ASTConsumer {
+ Diagnostic &Diags;
+ std::string OutFile;
+
+ public:
+ explicit PCHGenerator(Diagnostic &Diags, const std::string &OutFile)
+ : Diags(Diags), OutFile(OutFile) { }
+
+ virtual void HandleTranslationUnit(ASTContext &Ctx);
+ };
+}
+
+void PCHGenerator::HandleTranslationUnit(ASTContext &Ctx) {
+ if (Diags.hasErrorOccurred())
+ return;
+
+ // Write the PCH contents into a buffer
+ std::vector<unsigned char> Buffer;
+ BitstreamWriter Stream(Buffer);
+ PCHWriter Writer(Stream);
+
+ // Emit the PCH file
+ Writer.WritePCH(Ctx);
+
+ // Open up the PCH file.
+ std::string ErrMsg;
+ llvm::raw_fd_ostream Out(OutFile.c_str(), true, ErrMsg);
+
+ if (!ErrMsg.empty()) {
+ llvm::errs() << "PCH error: " << ErrMsg << "\n";
+ return;
+ }
+
+ // Write the generated bitstream to "Out".
+ Out.write((char *)&Buffer.front(), Buffer.size());
+
+ // Make sure it hits disk now.
+ Out.flush();
+}
+
+namespace clang {
+
+ASTConsumer *CreatePCHGenerator(Diagnostic &Diags,
+ const LangOptions &Features,
+ const std::string& InFile,
+ const std::string& OutFile) {
+ return new PCHGenerator(Diags, OutFile);
+}
+
+}
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/InitHeaderSearch.h"
#include "clang/Frontend/PathDiagnosticClients.h"
+#include "clang/Frontend/PCHReader.h"
#include "clang/Frontend/TextDiagnosticBuffer.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "clang/Analysis/PathDiagnostic.h"
DumpRawTokens, // Dump out raw tokens.
RunAnalysis, // Run one or more source code analyses.
GeneratePTH, // Generate pre-tokenized header.
+ GeneratePCH, // Generate pre-compiled header.
InheritanceView // View C++ inheritance for a specified class.
};
"Print DeclContexts and their Decls"),
clEnumValN(GeneratePTH, "emit-pth",
"Generate pre-tokenized header file"),
+ clEnumValN(GeneratePCH, "emit-pch",
+ "Generate pre-compiled header file"),
clEnumValN(TestSerialization, "test-pickling",
"Run prototype serialization code"),
clEnumValN(EmitAssembly, "S",
ImplicitIncludePTH("include-pth", llvm::cl::value_desc("file"),
llvm::cl::desc("Include file before parsing"));
+static llvm::cl::opt<std::string>
+ImplicitIncludePCH("include-pch", llvm::cl::value_desc("file"),
+ llvm::cl::desc("Include precompiled header file"));
+
// Append a #define line to Buf for Macro. Macro should be of the form XXX,
// in which case we emit "#define XXX 1" or "XXX=Y z W" in which case we emit
// "#define XXX Y z W". To get a #define with no value, use "XXX=".
// FIXME: Allow user to tailor where the file is written.
return CreateASTSerializer(InFile, OutputFile, Diag);
+ case GeneratePCH:
+ return CreatePCHGenerator(Diag, LangOpts, InFile, OutputFile);
+
case RewriteObjC:
return CreateCodeRewriterTest(InFile, OutputFile, Diag, LangOpts);
PP.getSelectorTable(),
/* FreeMemory = */ !DisableFree));
+ if (!ImplicitIncludePCH.empty()) {
+ // The user has asked us to include a precompiled header. Load
+ // the precompiled header into the AST context.
+ llvm::OwningPtr<PCHReader> Reader(
+ new clang::PCHReader(*ContextOwner.get()));
+ if (Reader->ReadPCH(ImplicitIncludePCH))
+ return;
+
+ llvm::OwningPtr<ExternalASTSource> Source(Reader.take());
+ ContextOwner->setExternalSource(Source);
+ }
+
ParseAST(PP, Consumer.get(), *ContextOwner.get(), Stats);
if (FixItRewrite)