diff options
author | Sebastian Redl <sebastian.redl@getdesigned.at> | 2010-08-17 17:55:49 +0000 |
---|---|---|
committer | Sebastian Redl <sebastian.redl@getdesigned.at> | 2010-08-17 17:55:49 +0000 |
commit | 93c972945bccd1a966b0445f9ed45db433b77bc1 (patch) | |
tree | 6ca928695d9e3bcc8263f6744f27062eddd5c8fc /lib/Serialization/PCHWriter.cpp | |
parent | 11c3dc45a89f632b5fb52610d5cb217bfc062e9a (diff) |
Create a new Serialization module that contains all the PCH code, and will contain all the module code in the future. Update the Makefiles, CMake projects and the Xcode project. I hope I did everything right for Xcode. No functionality change.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@111258 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Serialization/PCHWriter.cpp')
-rw-r--r-- | lib/Serialization/PCHWriter.cpp | 3094 |
1 files changed, 3094 insertions, 0 deletions
diff --git a/lib/Serialization/PCHWriter.cpp b/lib/Serialization/PCHWriter.cpp new file mode 100644 index 0000000000..f75373a33b --- /dev/null +++ b/lib/Serialization/PCHWriter.cpp @@ -0,0 +1,3094 @@ +//===--- PCHWriter.cpp - Precompiled Headers Writer -----------------------===// +// +// 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/Serialization/PCHWriter.h" +#include "clang/Sema/Sema.h" +#include "clang/Sema/IdentifierResolver.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclContextInternals.h" +#include "clang/AST/Expr.h" +#include "clang/AST/Type.h" +#include "clang/AST/TypeLocVisitor.h" +#include "clang/Serialization/PCHReader.h" +#include "clang/Lex/MacroInfo.h" +#include "clang/Lex/PreprocessingRecord.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Lex/HeaderSearch.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/OnDiskHashTable.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/SourceManagerInternals.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/Version.h" +#include "llvm/ADT/APFloat.h" +#include "llvm/ADT/APInt.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Bitcode/BitstreamWriter.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/System/Path.h" +#include <cstdio> +using namespace clang; + +template <typename T, typename Allocator> +T *data(std::vector<T, Allocator> &v) { + return v.empty() ? 0 : &v.front(); +} +template <typename T, typename Allocator> +const T *data(const std::vector<T, Allocator> &v) { + return v.empty() ? 0 : &v.front(); +} + +//===----------------------------------------------------------------------===// +// Type serialization +//===----------------------------------------------------------------------===// + +namespace { + class 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), Code(pch::TYPE_EXT_QUAL) { } + + 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) +#include "clang/AST/TypeNodes.def" + }; +} + +void PCHTypeWriter::VisitBuiltinType(const BuiltinType *T) { + assert(false && "Built-in types are never serialized"); +} + +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->getIndexTypeCVRQualifiers()); // 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); + Writer.AddSourceLocation(T->getLBracketLoc(), Record); + Writer.AddSourceLocation(T->getRBracketLoc(), Record); + Writer.AddStmt(T->getSizeExpr()); + Code = pch::TYPE_VARIABLE_ARRAY; +} + +void PCHTypeWriter::VisitVectorType(const VectorType *T) { + Writer.AddTypeRef(T->getElementType(), Record); + Record.push_back(T->getNumElements()); + Record.push_back(T->getAltiVecSpecific()); + 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); + FunctionType::ExtInfo C = T->getExtInfo(); + Record.push_back(C.getNoReturn()); + Record.push_back(C.getRegParm()); + // FIXME: need to stabilize encoding of calling convention... + Record.push_back(C.getCC()); +} + +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()); + Record.push_back(T->hasExceptionSpec()); + Record.push_back(T->hasAnyExceptionSpec()); + Record.push_back(T->getNumExceptions()); + for (unsigned I = 0, N = T->getNumExceptions(); I != N; ++I) + Writer.AddTypeRef(T->getExceptionType(I), Record); + Code = pch::TYPE_FUNCTION_PROTO; +} + +void PCHTypeWriter::VisitUnresolvedUsingType(const UnresolvedUsingType *T) { + Writer.AddDeclRef(T->getDecl(), Record); + Code = pch::TYPE_UNRESOLVED_USING; +} + +void PCHTypeWriter::VisitTypedefType(const TypedefType *T) { + Writer.AddDeclRef(T->getDecl(), Record); + assert(!T->isCanonicalUnqualified() && "Invalid typedef ?"); + Writer.AddTypeRef(T->getCanonicalTypeInternal(), Record); + Code = pch::TYPE_TYPEDEF; +} + +void PCHTypeWriter::VisitTypeOfExprType(const TypeOfExprType *T) { + Writer.AddStmt(T->getUnderlyingExpr()); + Code = pch::TYPE_TYPEOF_EXPR; +} + +void PCHTypeWriter::VisitTypeOfType(const TypeOfType *T) { + Writer.AddTypeRef(T->getUnderlyingType(), Record); + Code = pch::TYPE_TYPEOF; +} + +void PCHTypeWriter::VisitDecltypeType(const DecltypeType *T) { + Writer.AddStmt(T->getUnderlyingExpr()); + Code = pch::TYPE_DECLTYPE; +} + +void PCHTypeWriter::VisitTagType(const TagType *T) { + Record.push_back(T->isDependentType()); + 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::VisitSubstTemplateTypeParmType( + const SubstTemplateTypeParmType *T) { + Writer.AddTypeRef(QualType(T->getReplacedParameter(), 0), Record); + Writer.AddTypeRef(T->getReplacementType(), Record); + Code = pch::TYPE_SUBST_TEMPLATE_TYPE_PARM; +} + +void +PCHTypeWriter::VisitTemplateSpecializationType( + const TemplateSpecializationType *T) { + Record.push_back(T->isDependentType()); + Writer.AddTemplateName(T->getTemplateName(), Record); + Record.push_back(T->getNumArgs()); + for (TemplateSpecializationType::iterator ArgI = T->begin(), ArgE = T->end(); + ArgI != ArgE; ++ArgI) + Writer.AddTemplateArgument(*ArgI, Record); + Writer.AddTypeRef(T->isCanonicalUnqualified() ? QualType() + : T->getCanonicalTypeInternal(), + Record); + Code = pch::TYPE_TEMPLATE_SPECIALIZATION; +} + +void +PCHTypeWriter::VisitDependentSizedArrayType(const DependentSizedArrayType *T) { + VisitArrayType(T); + Writer.AddStmt(T->getSizeExpr()); + Writer.AddSourceRange(T->getBracketsRange(), Record); + Code = pch::TYPE_DEPENDENT_SIZED_ARRAY; +} + +void +PCHTypeWriter::VisitDependentSizedExtVectorType( + const DependentSizedExtVectorType *T) { + // FIXME: Serialize this type (C++ only) + assert(false && "Cannot serialize dependent sized extended vector types"); +} + +void +PCHTypeWriter::VisitTemplateTypeParmType(const TemplateTypeParmType *T) { + Record.push_back(T->getDepth()); + Record.push_back(T->getIndex()); + Record.push_back(T->isParameterPack()); + Writer.AddIdentifierRef(T->getName(), Record); + Code = pch::TYPE_TEMPLATE_TYPE_PARM; +} + +void +PCHTypeWriter::VisitDependentNameType(const DependentNameType *T) { + Record.push_back(T->getKeyword()); + Writer.AddNestedNameSpecifier(T->getQualifier(), Record); + Writer.AddIdentifierRef(T->getIdentifier(), Record); + Writer.AddTypeRef(T->isCanonicalUnqualified() ? QualType() + : T->getCanonicalTypeInternal(), + Record); + Code = pch::TYPE_DEPENDENT_NAME; +} + +void +PCHTypeWriter::VisitDependentTemplateSpecializationType( + const DependentTemplateSpecializationType *T) { + Record.push_back(T->getKeyword()); + Writer.AddNestedNameSpecifier(T->getQualifier(), Record); + Writer.AddIdentifierRef(T->getIdentifier(), Record); + Record.push_back(T->getNumArgs()); + for (DependentTemplateSpecializationType::iterator + I = T->begin(), E = T->end(); I != E; ++I) + Writer.AddTemplateArgument(*I, Record); + Code = pch::TYPE_DEPENDENT_TEMPLATE_SPECIALIZATION; +} + +void PCHTypeWriter::VisitElaboratedType(const ElaboratedType *T) { + Record.push_back(T->getKeyword()); + Writer.AddNestedNameSpecifier(T->getQualifier(), Record); + Writer.AddTypeRef(T->getNamedType(), Record); + Code = pch::TYPE_ELABORATED; +} + +void PCHTypeWriter::VisitInjectedClassNameType(const InjectedClassNameType *T) { + Writer.AddDeclRef(T->getDecl(), Record); + Writer.AddTypeRef(T->getInjectedSpecializationType(), Record); + Code = pch::TYPE_INJECTED_CLASS_NAME; +} + +void PCHTypeWriter::VisitObjCInterfaceType(const ObjCInterfaceType *T) { + Writer.AddDeclRef(T->getDecl(), Record); + Code = pch::TYPE_OBJC_INTERFACE; +} + +void PCHTypeWriter::VisitObjCObjectType(const ObjCObjectType *T) { + Writer.AddTypeRef(T->getBaseType(), Record); + Record.push_back(T->getNumProtocols()); + for (ObjCObjectType::qual_iterator I = T->qual_begin(), + E = T->qual_end(); I != E; ++I) + Writer.AddDeclRef(*I, Record); + Code = pch::TYPE_OBJC_OBJECT; +} + +void +PCHTypeWriter::VisitObjCObjectPointerType(const ObjCObjectPointerType *T) { + Writer.AddTypeRef(T->getPointeeType(), Record); + Code = pch::TYPE_OBJC_OBJECT_POINTER; +} + +namespace { + +class TypeLocWriter : public TypeLocVisitor<TypeLocWriter> { + PCHWriter &Writer; + PCHWriter::RecordData &Record; + +public: + TypeLocWriter(PCHWriter &Writer, PCHWriter::RecordData &Record) + : Writer(Writer), Record(Record) { } + +#define ABSTRACT_TYPELOC(CLASS, PARENT) +#define TYPELOC(CLASS, PARENT) \ + void Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc); +#include "clang/AST/TypeLocNodes.def" + + void VisitArrayTypeLoc(ArrayTypeLoc TyLoc); + void VisitFunctionTypeLoc(FunctionTypeLoc TyLoc); +}; + +} + +void TypeLocWriter::VisitQualifiedTypeLoc(QualifiedTypeLoc TL) { + // nothing to do +} +void TypeLocWriter::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) { + Writer.AddSourceLocation(TL.getBuiltinLoc(), Record); + if (TL.needsExtraLocalData()) { + Record.push_back(TL.getWrittenTypeSpec()); + Record.push_back(TL.getWrittenSignSpec()); + Record.push_back(TL.getWrittenWidthSpec()); + Record.push_back(TL.hasModeAttr()); + } +} +void TypeLocWriter::VisitComplexTypeLoc(ComplexTypeLoc TL) { + Writer.AddSourceLocation(TL.getNameLoc(), Record); +} +void TypeLocWriter::VisitPointerTypeLoc(PointerTypeLoc TL) { + Writer.AddSourceLocation(TL.getStarLoc(), Record); +} +void TypeLocWriter::VisitBlockPointerTypeLoc(BlockPointerTypeLoc TL) { + Writer.AddSourceLocation(TL.getCaretLoc(), Record); +} +void TypeLocWriter::VisitLValueReferenceTypeLoc(LValueReferenceTypeLoc TL) { + Writer.AddSourceLocation(TL.getAmpLoc(), Record); +} +void TypeLocWriter::VisitRValueReferenceTypeLoc(RValueReferenceTypeLoc TL) { + Writer.AddSourceLocation(TL.getAmpAmpLoc(), Record); +} +void TypeLocWriter::VisitMemberPointerTypeLoc(MemberPointerTypeLoc TL) { + Writer.AddSourceLocation(TL.getStarLoc(), Record); +} +void TypeLocWriter::VisitArrayTypeLoc(ArrayTypeLoc TL) { + Writer.AddSourceLocation(TL.getLBracketLoc(), Record); + Writer.AddSourceLocation(TL.getRBracketLoc(), Record); + Record.push_back(TL.getSizeExpr() ? 1 : 0); + if (TL.getSizeExpr()) + Writer.AddStmt(TL.getSizeExpr()); +} +void TypeLocWriter::VisitConstantArrayTypeLoc(ConstantArrayTypeLoc TL) { + VisitArrayTypeLoc(TL); +} +void TypeLocWriter::VisitIncompleteArrayTypeLoc(IncompleteArrayTypeLoc TL) { + VisitArrayTypeLoc(TL); +} +void TypeLocWriter::VisitVariableArrayTypeLoc(VariableArrayTypeLoc TL) { + VisitArrayTypeLoc(TL); +} +void TypeLocWriter::VisitDependentSizedArrayTypeLoc( + DependentSizedArrayTypeLoc TL) { + VisitArrayTypeLoc(TL); +} +void TypeLocWriter::VisitDependentSizedExtVectorTypeLoc( + DependentSizedExtVectorTypeLoc TL) { + Writer.AddSourceLocation(TL.getNameLoc(), Record); +} +void TypeLocWriter::VisitVectorTypeLoc(VectorTypeLoc TL) { + Writer.AddSourceLocation(TL.getNameLoc(), Record); +} +void TypeLocWriter::VisitExtVectorTypeLoc(ExtVectorTypeLoc TL) { + Writer.AddSourceLocation(TL.getNameLoc(), Record); +} +void TypeLocWriter::VisitFunctionTypeLoc(FunctionTypeLoc TL) { + Writer.AddSourceLocation(TL.getLParenLoc(), Record); + Writer.AddSourceLocation(TL.getRParenLoc(), Record); + for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) + Writer.AddDeclRef(TL.getArg(i), Record); +} +void TypeLocWriter::VisitFunctionProtoTypeLoc(FunctionProtoTypeLoc TL) { + VisitFunctionTypeLoc(TL); +} +void TypeLocWriter::VisitFunctionNoProtoTypeLoc(FunctionNoProtoTypeLoc TL) { + VisitFunctionTypeLoc(TL); +} +void TypeLocWriter::VisitUnresolvedUsingTypeLoc(UnresolvedUsingTypeLoc TL) { + Writer.AddSourceLocation(TL.getNameLoc(), Record); +} +void TypeLocWriter::VisitTypedefTypeLoc(TypedefTypeLoc TL) { + Writer.AddSourceLocation(TL.getNameLoc(), Record); +} +void TypeLocWriter::VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL) { + Writer.AddSourceLocation(TL.getTypeofLoc(), Record); + Writer.AddSourceLocation(TL.getLParenLoc(), Record); + Writer.AddSourceLocation(TL.getRParenLoc(), Record); +} +void TypeLocWriter::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) { + Writer.AddSourceLocation(TL.getTypeofLoc(), Record); + Writer.AddSourceLocation(TL.getLParenLoc(), Record); + Writer.AddSourceLocation(TL.getRParenLoc(), Record); + Writer.AddTypeSourceInfo(TL.getUnderlyingTInfo(), Record); +} +void TypeLocWriter::VisitDecltypeTypeLoc(DecltypeTypeLoc TL) { + Writer.AddSourceLocation(TL.getNameLoc(), Record); +} +void TypeLocWriter::VisitRecordTypeLoc(RecordTypeLoc TL) { + Writer.AddSourceLocation(TL.getNameLoc(), Record); +} +void TypeLocWriter::VisitEnumTypeLoc(EnumTypeLoc TL) { + Writer.AddSourceLocation(TL.getNameLoc(), Record); +} +void TypeLocWriter::VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) { + Writer.AddSourceLocation(TL.getNameLoc(), Record); +} +void TypeLocWriter::VisitSubstTemplateTypeParmTypeLoc( + SubstTemplateTypeParmTypeLoc TL) { + Writer.AddSourceLocation(TL.getNameLoc(), Record); +} +void TypeLocWriter::VisitTemplateSpecializationTypeLoc( + TemplateSpecializationTypeLoc TL) { + Writer.AddSourceLocation(TL.getTemplateNameLoc(), Record); + Writer.AddSourceLocation(TL.getLAngleLoc(), Record); + Writer.AddSourceLocation(TL.getRAngleLoc(), Record); + for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) + Writer.AddTemplateArgumentLocInfo(TL.getArgLoc(i).getArgument().getKind(), + TL.getArgLoc(i).getLocInfo(), Record); +} +void TypeLocWriter::VisitElaboratedTypeLoc(ElaboratedTypeLoc TL) { + Writer.AddSourceLocation(TL.getKeywordLoc(), Record); + Writer.AddSourceRange(TL.getQualifierRange(), Record); +} +void TypeLocWriter::VisitInjectedClassNameTypeLoc(InjectedClassNameTypeLoc TL) { + Writer.AddSourceLocation(TL.getNameLoc(), Record); +} +void TypeLocWriter::VisitDependentNameTypeLoc(DependentNameTypeLoc TL) { + Writer.AddSourceLocation(TL.getKeywordLoc(), Record); + Writer.AddSourceRange(TL.getQualifierRange(), Record); + Writer.AddSourceLocation(TL.getNameLoc(), Record); +} +void TypeLocWriter::VisitDependentTemplateSpecializationTypeLoc( + DependentTemplateSpecializationTypeLoc TL) { + Writer.AddSourceLocation(TL.getKeywordLoc(), Record); + Writer.AddSourceRange(TL.getQualifierRange(), Record); + Writer.AddSourceLocation(TL.getNameLoc(), Record); + Writer.AddSourceLocation(TL.getLAngleLoc(), Record); + Writer.AddSourceLocation(TL.getRAngleLoc(), Record); + for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I) + Writer.AddTemplateArgumentLocInfo(TL.getArgLoc(I).getArgument().getKind(), + TL.getArgLoc(I).getLocInfo(), Record); +} +void TypeLocWriter::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) { + Writer.AddSourceLocation(TL.getNameLoc(), Record); +} +void TypeLocWriter::VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) { + Record.push_back(TL.hasBaseTypeAsWritten()); + Writer.AddSourceLocation(TL.getLAngleLoc(), Record); + Writer.AddSourceLocation(TL.getRAngleLoc(), Record); + for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i) + Writer.AddSourceLocation(TL.getProtocolLoc(i), Record); +} +void TypeLocWriter::VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) { + Writer.AddSourceLocation(TL.getStarLoc(), Record); +} + +//===----------------------------------------------------------------------===// +// PCHWriter Implementation +//===----------------------------------------------------------------------===// + +static void EmitBlockID(unsigned ID, const char *Name, + llvm::BitstreamWriter &Stream, + PCHWriter::RecordData &Record) { + Record.clear(); + Record.push_back(ID); + Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETBID, Record); + + // Emit the block name if present. + if (Name == 0 || Name[0] == 0) return; + Record.clear(); + while (*Name) + Record.push_back(*Name++); + Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_BLOCKNAME, Record); +} + +static void EmitRecordID(unsigned ID, const char *Name, + llvm::BitstreamWriter &Stream, + PCHWriter::RecordData &Record) { + Record.clear(); + Record.push_back(ID); + while (*Name) + Record.push_back(*Name++); + Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, Record); +} + +static void AddStmtsExprs(llvm::BitstreamWriter &Stream, + PCHWriter::RecordData &Record) { +#define RECORD(X) EmitRecordID(pch::X, #X, Stream, Record) + RECORD(STMT_STOP); + RECORD(STMT_NULL_PTR); + RECORD(STMT_NULL); + RECORD(STMT_COMPOUND); + RECORD(STMT_CASE); + RECORD(STMT_DEFAULT); + RECORD(STMT_LABEL); + RECORD(STMT_IF); + RECORD(STMT_SWITCH); + RECORD(STMT_WHILE); + RECORD(STMT_DO); + RECORD(STMT_FOR); + RECORD(STMT_GOTO); + RECORD(STMT_INDIRECT_GOTO); + RECORD(STMT_CONTINUE); + RECORD(STMT_BREAK); + RECORD(STMT_RETURN); + RECORD(STMT_DECL); + RECORD(STMT_ASM); + RECORD(EXPR_PREDEFINED); + RECORD(EXPR_DECL_REF); + RECORD(EXPR_INTEGER_LITERAL); + RECORD(EXPR_FLOATING_LITERAL); + RECORD(EXPR_IMAGINARY_LITERAL); + RECORD(EXPR_STRING_LITERAL); + RECORD(EXPR_CHARACTER_LITERAL); + RECORD(EXPR_PAREN); + RECORD(EXPR_UNARY_OPERATOR); + RECORD(EXPR_SIZEOF_ALIGN_OF); + RECORD(EXPR_ARRAY_SUBSCRIPT); + RECORD(EXPR_CALL); + RECORD(EXPR_MEMBER); + RECORD(EXPR_BINARY_OPERATOR); + RECORD(EXPR_COMPOUND_ASSIGN_OPERATOR); + RECORD(EXPR_CONDITIONAL_OPERATOR); + RECORD(EXPR_IMPLICIT_CAST); + RECORD(EXPR_CSTYLE_CAST); + RECORD(EXPR_COMPOUND_LITERAL); + RECORD(EXPR_EXT_VECTOR_ELEMENT); + RECORD(EXPR_INIT_LIST); + RECORD(EXPR_DESIGNATED_INIT); + RECORD(EXPR_IMPLICIT_VALUE_INIT); + RECORD(EXPR_VA_ARG); + RECORD(EXPR_ADDR_LABEL); + RECORD(EXPR_STMT); + RECORD(EXPR_TYPES_COMPATIBLE); + RECORD(EXPR_CHOOSE); + RECORD(EXPR_GNU_NULL); + RECORD(EXPR_SHUFFLE_VECTOR); + RECORD(EXPR_BLOCK); + RECORD(EXPR_BLOCK_DECL_REF); + RECORD(EXPR_OBJC_STRING_LITERAL); + RECORD(EXPR_OBJC_ENCODE); + RECORD(EXPR_OBJC_SELECTOR_EXPR); + RECORD(EXPR_OBJC_PROTOCOL_EXPR); + RECORD(EXPR_OBJC_IVAR_REF_EXPR); + RECORD(EXPR_OBJC_PROPERTY_REF_EXPR); + RECORD(EXPR_OBJC_KVC_REF_EXPR); + RECORD(EXPR_OBJC_MESSAGE_EXPR); + RECORD(EXPR_OBJC_SUPER_EXPR); + RECORD(STMT_OBJC_FOR_COLLECTION); + RECORD(STMT_OBJC_CATCH); + RECORD(STMT_OBJC_FINALLY); + RECORD(STMT_OBJC_AT_TRY); + RECORD(STMT_OBJC_AT_SYNCHRONIZED); + RECORD(STMT_OBJC_AT_THROW); + RECORD(EXPR_CXX_OPERATOR_CALL); + RECORD(EXPR_CXX_CONSTRUCT); + RECORD(EXPR_CXX_STATIC_CAST); + RECORD(EXPR_CXX_DYNAMIC_CAST); + RECORD(EXPR_CXX_REINTERPRET_CAST); + RECORD(EXPR_CXX_CONST_CAST); + RECORD(EXPR_CXX_FUNCTIONAL_CAST); + RECORD(EXPR_CXX_BOOL_LITERAL); + RECORD(EXPR_CXX_NULL_PTR_LITERAL); +#undef RECORD +} + +void PCHWriter::WriteBlockInfoBlock() { + RecordData Record; + Stream.EnterSubblock(llvm::bitc::BLOCKINFO_BLOCK_ID, 3); + +#define BLOCK(X) EmitBlockID(pch::X ## _ID, #X, Stream, Record) +#define RECORD(X) EmitRecordID(pch::X, #X, Stream, Record) + + // PCH Top-Level Block. + BLOCK(PCH_BLOCK); + RECORD(ORIGINAL_FILE_NAME); + RECORD(TYPE_OFFSET); + RECORD(DECL_OFFSET); + RECORD(LANGUAGE_OPTIONS); + RECORD(METADATA); + RECORD(IDENTIFIER_OFFSET); + RECORD(IDENTIFIER_TABLE); + RECORD(EXTERNAL_DEFINITIONS); + RECORD(SPECIAL_TYPES); + RECORD(STATISTICS); + RECORD(TENTATIVE_DEFINITIONS); + RECORD(UNUSED_FILESCOPED_DECLS); + RECORD(LOCALLY_SCOPED_EXTERNAL_DECLS); + RECORD(SELECTOR_OFFSETS); + RECORD(METHOD_POOL); + RECORD(PP_COUNTER_VALUE); + RECORD(SOURCE_LOCATION_OFFSETS); + RECORD(SOURCE_LOCATION_PRELOADS); + RECORD(STAT_CACHE); + RECORD(EXT_VECTOR_DECLS); + RECORD(VERSION_CONTROL_BRANCH_REVISION); + RECORD(MACRO_DEFINITION_OFFSETS); + RECORD(CHAINED_METADATA); + RECORD(REFERENCED_SELECTOR_POOL); + + // SourceManager Block. + BLOCK(SOURCE_MANAGER_BLOCK); + RECORD(SM_SLOC_FILE_ENTRY); + RECORD(SM_SLOC_BUFFER_ENTRY); + RECORD(SM_SLOC_BUFFER_BLOB); + RECORD(SM_SLOC_INSTANTIATION_ENTRY); + RECORD(SM_LINE_TABLE); + + // Preprocessor Block. + BLOCK(PREPROCESSOR_BLOCK); + RECORD(PP_MACRO_OBJECT_LIKE); + RECORD(PP_MACRO_FUNCTION_LIKE); + RECORD(PP_TOKEN); + RECORD(PP_MACRO_INSTANTIATION); + RECORD(PP_MACRO_DEFINITION); + + // Decls and Types block. + BLOCK(DECLTYPES_BLOCK); + RECORD(TYPE_EXT_QUAL); + RECORD(TYPE_COMPLEX); + RECORD(TYPE_POINTER); + RECORD(TYPE_BLOCK_POINTER); + RECORD(TYPE_LVALUE_REFERENCE); + RECORD(TYPE_RVALUE_REFERENCE); + RECORD(TYPE_MEMBER_POINTER); + RECORD(TYPE_CONSTANT_ARRAY); + RECORD(TYPE_INCOMPLETE_ARRAY); + RECORD(TYPE_VARIABLE_ARRAY); + RECORD(TYPE_VECTOR); + RECORD(TYPE_EXT_VECTOR); + RECORD(TYPE_FUNCTION_PROTO); + RECORD(TYPE_FUNCTION_NO_PROTO); + RECORD(TYPE_TYPEDEF); + RECORD(TYPE_TYPEOF_EXPR); + RECORD(TYPE_TYPEOF); + RECORD(TYPE_RECORD); + RECORD(TYPE_ENUM); + RECORD(TYPE_OBJC_INTERFACE); + RECORD(TYPE_OBJC_OBJECT); + RECORD(TYPE_OBJC_OBJECT_POINTER); + RECORD(DECL_ATTR); + RECORD(DECL_TRANSLATION_UNIT); + RECORD(DECL_TYPEDEF); + RECORD(DECL_ENUM); + RECORD(DECL_RECORD); + RECORD(DECL_ENUM_CONSTANT); + RECORD(DECL_FUNCTION); + RECORD(DECL_OBJC_METHOD); + RECORD(DECL_OBJC_INTERFACE); + RECORD(DECL_OBJC_PROTOCOL); + RECORD(DECL_OBJC_IVAR); + RECORD(DECL_OBJC_AT_DEFS_FIELD); + RECORD(DECL_OBJC_CLASS); + RECORD(DECL_OBJC_FORWARD_PROTOCOL); + RECORD(DECL_OBJC_CATEGORY); + RECORD(DECL_OBJC_CATEGORY_IMPL); + RECORD(DECL_OBJC_IMPLEMENTATION); + RECORD(DECL_OBJC_COMPATIBLE_ALIAS); + RECORD(DECL_OBJC_PROPERTY); + RECORD(DECL_OBJC_PROPERTY_IMPL); + RECORD(DECL_FIELD); + RECORD(DECL_VAR); + RECORD(DECL_IMPLICIT_PARAM); + RECORD(DECL_PARM_VAR); + RECORD(DECL_FILE_SCOPE_ASM); + RECORD(DECL_BLOCK); + RECORD(DECL_CONTEXT_LEXICAL); + RECORD(DECL_CONTEXT_VISIBLE); + // Statements and Exprs can occur in the Decls and Types block. + AddStmtsExprs(Stream, Record); +#undef RECORD +#undef BLOCK + Stream.ExitBlock(); +} + +/// \brief Adjusts the given filename to only write out the portion of the +/// filename that is not part of the system root directory. +/// +/// \param Filename the file name to adjust. +/// +/// \param isysroot When non-NULL, the PCH file is a relocatable PCH file and +/// the returned filename will be adjusted by this system root. +/// +/// \returns either the original filename (if it needs no adjustment) or the +/// adjusted filename (which points into the @p Filename parameter). +static const char * +adjustFilenameForRelocatablePCH(const char *Filename, const char *isysroot) { + assert(Filename && "No file name to adjust?"); + + if (!isysroot) + return Filename; + + // Verify that the filename and the system root have the same prefix. + unsigned Pos = 0; + for (; Filename[Pos] && isysroot[Pos]; ++Pos) + if (Filename[Pos] != isysroot[Pos]) + return Filename; // Prefixes don't match. + + // We hit the end of the filename before we hit the end of the system root. + if (!Filename[Pos]) + return Filename; + + // If the file name has a '/' at the current position, skip over the '/'. + // We distinguish sysroot-based includes from absolute includes by the + // absence of '/' at the beginning of sysroot-based includes. + if (Filename[Pos] == '/') + ++Pos; + + return Filename + Pos; +} + +/// \brief Write the PCH metadata (e.g., i686-apple-darwin9). +void PCHWriter::WriteMetadata(ASTContext &Context, const char *isysroot) { + using namespace llvm; + + // Metadata + const TargetInfo &Target = Context.Target; + BitCodeAbbrev *MetaAbbrev = new BitCodeAbbrev(); + MetaAbbrev->Add(BitCodeAbbrevOp( + Chain ? pch::CHAINED_METADATA : pch::METADATA)); + MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // PCH major + MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // PCH minor + MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Clang major + MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Clang minor + MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Relocatable + // Target triple or chained PCH name + MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); + unsigned MetaAbbrevCode = Stream.EmitAbbrev(MetaAbbrev); + + RecordData Record; + Record.push_back(Chain ? pch::CHAINED_METADATA : pch::METADATA); + Record.push_back(pch::VERSION_MAJOR); + Record.push_back(pch::VERSION_MINOR); + Record.push_back(CLANG_VERSION_MAJOR); + Record.push_back(CLANG_VERSION_MINOR); + Record.push_back(isysroot != 0); + // FIXME: This writes the absolute path for chained headers. + const std::string &BlobStr = Chain ? Chain->getFileName() : Target.getTriple().getTriple(); + Stream.EmitRecordWithBlob(MetaAbbrevCode, Record, BlobStr); + + // Original file name + SourceManager &SM = Context.getSourceManager(); + if (const FileEntry *MainFile = SM.getFileEntryForID(SM.getMainFileID())) { + BitCodeAbbrev *FileAbbrev = new BitCodeAbbrev(); + FileAbbrev->Add(BitCodeAbbrevOp(pch::ORIGINAL_FILE_NAME)); + FileAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name + unsigned FileAbbrevCode = Stream.EmitAbbrev(FileAbbrev); + + llvm::sys::Path MainFilePath(MainFile->getName()); + + MainFilePath.makeAbsolute(); + + const char *MainFileNameStr = MainFilePath.c_str(); + MainFileNameStr = adjustFilenameForRelocatablePCH(MainFileNameStr, + isysroot); + RecordData Record; + Record.push_back(pch::ORIGINAL_FILE_NAME); + Stream.EmitRecordWithBlob(FileAbbrevCode, Record, MainFileNameStr); + } + + // Repository branch/version information. + BitCodeAbbrev *RepoAbbrev = new BitCodeAbbrev(); + RepoAbbrev->Add(BitCodeAbbrevOp(pch::VERSION_CONTROL_BRANCH_REVISION)); + RepoAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // SVN branch/tag + unsigned RepoAbbrevCode = Stream.EmitAbbrev(RepoAbbrev); + Record.clear(); + Record.push_back(pch::VERSION_CONTROL_BRANCH_REVISION); + Stream.EmitRecordWithBlob(RepoAbbrevCode, Record, + getClangFullRepositoryVersion()); +} + +/// \brief Write the LangOptions structure. +void PCHWriter::WriteLanguageOptions(const LangOptions &LangOpts) { + RecordData Record; + Record.push_back(LangOpts.Trigraphs); + Record.push_back(LangOpts.BCPLComment); // BCPL-style '//' comments. + Record.push_back(LangOpts.DollarIdents); // '$' allowed in identifiers. + Record.push_back(LangOpts.AsmPreprocessor); // Preprocessor in asm mode. + Record.push_back(LangOpts.GNUMode); // True in gnu99 mode false in c99 mode (etc) + Record.push_back(LangOpts.GNUKeywords); // Allow GNU-extension keywords + Record.push_back(LangOpts.ImplicitInt); // C89 implicit 'int'. + Record.push_back(LangOpts.Digraphs); // C94, C99 and C++ + Record.push_back(LangOpts.HexFloats); // C99 Hexadecimal float constants. + Record.push_back(LangOpts.C99); // C99 Support + Record.push_back(LangOpts.Microsoft); // Microsoft extensions. + Record.push_back(LangOpts.CPlusPlus); // C++ Support + Record.push_back(LangOpts.CPlusPlus0x); // C++0x Support + Record.push_back(LangOpts.CXXOperatorNames); // Treat C++ operator names as keywords. + + Record.push_back(LangOpts.ObjC1); // Objective-C 1 support enabled. + Record.push_back(LangOpts.ObjC2); // Objective-C 2 support enabled. + Record.push_back(LangOpts.ObjCNonFragileABI); // Objective-C + // modern abi enabled. + Record.push_back(LangOpts.ObjCNonFragileABI2); // Objective-C enhanced + // modern abi enabled. + Record.push_back(LangOpts.NoConstantCFStrings); // non cfstring generation enabled.. + + Record.push_back(LangOpts.PascalStrings); // Allow Pascal strings + Record.push_back(LangOpts.WritableStrings); // Allow writable strings + Record.push_back(LangOpts.LaxVectorConversions); + Record.push_back(LangOpts.AltiVec); + Record.push_back(LangOpts.Exceptions); // Support exception handling. + Record.push_back(LangOpts.SjLjExceptions); + + Record.push_back(LangOpts.NeXTRuntime); // Use NeXT runtime. + Record.push_back(LangOpts.Freestanding); // Freestanding implementation + Record.push_back(LangOpts.NoBuiltin); // Do not use builtin functions (-fno-builtin) + + // Whether static initializers are protected by locks. + Record.push_back(LangOpts.ThreadsafeStatics); + Record.push_back(LangOpts.POSIXThreads); + Record.push_back(LangOpts.Blocks); // block extension to C + Record.push_back(LangOpts.EmitAllDecls); // Emit all declarations, even if + // they are unused. + Record.push_back(LangOpts.MathErrno); // Math functions must respect errno + // (modulo the platform support). + + Record.push_back(LangOpts.getSignedOverflowBehavior()); + Record.push_back(LangOpts.HeinousExtensions); + + Record.push_back(LangOpts.Optimize); // Whether __OPTIMIZE__ should be defined. + Record.push_back(LangOpts.OptimizeSize); // Whether __OPTIMIZE_SIZE__ should be + // defined. + Record.push_back(LangOpts.Static); // Should __STATIC__ be defined (as + // opposed to __DYNAMIC__). + Record.push_back(LangOpts.PICLevel); // The value for __PIC__, if non-zero. + + Record.push_back(LangOpts.GNUInline); // Should GNU inline semantics be + // used (instead of C99 semantics). + Record.push_back(LangOpts.NoInline); // Should __NO_INLINE__ be defined. + Record.push_back(LangOpts.AccessControl); // Whether C++ access control should + // be enabled. + Record.push_back(LangOpts.CharIsSigned); // Whether char is a signed or + // unsigned type + Record.push_back(LangOpts.ShortWChar); // force wchar_t to be unsigned short + Record.push_back(LangOpts.getGCMode()); + Record.push_back(LangOpts.getVisibilityMode()); + Record.push_back(LangOpts.getStackProtectorMode()); + Record.push_back(LangOpts.InstantiationDepth); + Record.push_back(LangOpts.OpenCL); + Record.push_back(LangOpts.CatchUndefined); + Record.push_back(LangOpts.ElideConstructors); + Record.push_back(LangOpts.SpellChecking); + Stream.EmitRecord(pch::LANGUAGE_OPTIONS, Record); +} + +//===----------------------------------------------------------------------===// +// stat cache Serialization +//===----------------------------------------------------------------------===// + +namespace { +// Trait used for the on-disk hash table of stat cache results. +class PCHStatCacheTrait { +public: + typedef const char * key_type; + typedef key_type key_type_ref; + + typedef std::pair<int, struct stat> data_type; + typedef const data_type& data_type_ref; + + static unsigned ComputeHash(const char *path) { + return llvm::HashString(path); + } + + std::pair<unsigned,unsigned> + EmitKeyDataLength(llvm::raw_ostream& Out, const char *path, + data_type_ref Data) { + unsigned StrLen = strlen(path); + clang::io::Emit16(Out, StrLen); + unsigned DataLen = 1; // result value + if (Data.first == 0) + DataLen += 4 + 4 + 2 + 8 + 8; + clang::io::Emit8(Out, DataLen); + return std::make_pair(StrLen + 1, DataLen); + } + + void EmitKey(llvm::raw_ostream& Out, const char *path, unsigned KeyLen) { + Out.write(path, KeyLen); + } + + void EmitData(llvm::raw_ostream& Out, key_type_ref, + data_type_ref Data, unsigned DataLen) { + using namespace clang::io; + uint64_t Start = Out.tell(); (void)Start; + + // Result of stat() + Emit8(Out, Data.first? 1 : 0); + + if (Data.first == 0) { + Emit32(Out, (uint32_t) Data.second.st_ino); + Emit32(Out, (uint32_t) Data.second.st_dev); + Emit16(Out, (uint16_t) Data.second.st_mode); + Emit64(Out, (uint64_t) Data.second.st_mtime); + Emit64(Out, (uint64_t) Data.second.st_size); + } + + assert(Out.tell() - Start == DataLen && "Wrong data length"); + } +}; +} // end anonymous namespace + +/// \brief Write the stat() system call cache to the PCH file. +void PCHWriter::WriteStatCache(MemorizeStatCalls &StatCalls) { + // Build the on-disk hash table containing information about every + // stat() call. + OnDiskChainedHashTableGenerator<PCHStatCacheTrait> Generator; + unsigned NumStatEntries = 0; + for (MemorizeStatCalls::iterator Stat = StatCalls.begin(), + StatEnd = StatCalls.end(); + Stat != StatEnd; ++Stat, ++NumStatEntries) { + const char *Filename = Stat->first(); + Generator.insert(Filename, Stat->second); + } + + // Create the on-disk hash table in a buffer. + llvm::SmallString<4096> StatCacheData; + uint32_t BucketOffset; + { + llvm::raw_svector_ostream Out(StatCacheData); + // Make sure that no bucket is at offset 0 + clang::io::Emit32(Out, 0); + BucketOffset = Generator.Emit |