2009-04-10 06:27:44 +08:00
|
|
|
//===--- 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"
|
2009-04-20 23:53:59 +08:00
|
|
|
#include "../Sema/Sema.h" // FIXME: move header into include/clang/Sema
|
2009-04-21 04:36:09 +08:00
|
|
|
#include "../Sema/IdentifierResolver.h" // FIXME: move header
|
2009-04-10 06:27:44 +08:00
|
|
|
#include "clang/AST/ASTContext.h"
|
|
|
|
#include "clang/AST/Decl.h"
|
|
|
|
#include "clang/AST/DeclContextInternals.h"
|
|
|
|
#include "clang/AST/DeclVisitor.h"
|
2009-04-15 05:18:50 +08:00
|
|
|
#include "clang/AST/Expr.h"
|
|
|
|
#include "clang/AST/StmtVisitor.h"
|
2009-04-10 06:27:44 +08:00
|
|
|
#include "clang/AST/Type.h"
|
2009-04-11 02:00:12 +08:00
|
|
|
#include "clang/Lex/MacroInfo.h"
|
|
|
|
#include "clang/Lex/Preprocessor.h"
|
2009-04-25 04:03:17 +08:00
|
|
|
#include "clang/Lex/HeaderSearch.h"
|
2009-04-10 11:52:48 +08:00
|
|
|
#include "clang/Basic/FileManager.h"
|
2009-04-21 04:36:09 +08:00
|
|
|
#include "clang/Basic/OnDiskHashTable.h"
|
2009-04-10 11:52:48 +08:00
|
|
|
#include "clang/Basic/SourceManager.h"
|
2009-04-14 00:31:14 +08:00
|
|
|
#include "clang/Basic/SourceManagerInternals.h"
|
2009-04-11 05:16:55 +08:00
|
|
|
#include "clang/Basic/TargetInfo.h"
|
2009-04-15 05:55:33 +08:00
|
|
|
#include "llvm/ADT/APFloat.h"
|
|
|
|
#include "llvm/ADT/APInt.h"
|
2009-04-10 06:27:44 +08:00
|
|
|
#include "llvm/Bitcode/BitstreamWriter.h"
|
|
|
|
#include "llvm/Support/Compiler.h"
|
2009-04-10 11:52:48 +08:00
|
|
|
#include "llvm/Support/MemoryBuffer.h"
|
2009-04-12 02:40:46 +08:00
|
|
|
#include <cstdio>
|
2009-04-10 06:27:44 +08:00
|
|
|
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);
|
2009-04-17 06:23:12 +08:00
|
|
|
Writer.AddStmt(T->getSizeExpr());
|
2009-04-10 06:27:44 +08:00
|
|
|
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) {
|
2009-04-17 06:23:12 +08:00
|
|
|
Writer.AddStmt(T->getUnderlyingExpr());
|
2009-04-10 06:27:44 +08:00
|
|
|
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) {
|
2009-04-16 02:43:11 +08:00
|
|
|
// FIXME: Serialize this type (C++ only)
|
2009-04-10 06:27:44 +08:00
|
|
|
assert(false && "Cannot serialize template specialization types");
|
|
|
|
}
|
|
|
|
|
|
|
|
void PCHTypeWriter::VisitQualifiedNameType(const QualifiedNameType *T) {
|
2009-04-16 02:43:11 +08:00
|
|
|
// FIXME: Serialize this type (C++ only)
|
2009-04-10 06:27:44 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Declaration serialization
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
namespace {
|
|
|
|
class VISIBILITY_HIDDEN PCHDeclWriter
|
|
|
|
: public DeclVisitor<PCHDeclWriter, void> {
|
|
|
|
|
|
|
|
PCHWriter &Writer;
|
2009-04-18 08:02:19 +08:00
|
|
|
ASTContext &Context;
|
2009-04-10 06:27:44 +08:00
|
|
|
PCHWriter::RecordData &Record;
|
|
|
|
|
|
|
|
public:
|
|
|
|
pch::DeclCode Code;
|
|
|
|
|
2009-04-18 08:02:19 +08:00
|
|
|
PCHDeclWriter(PCHWriter &Writer, ASTContext &Context,
|
|
|
|
PCHWriter::RecordData &Record)
|
|
|
|
: Writer(Writer), Context(Context), Record(Record) { }
|
2009-04-10 06:27:44 +08:00
|
|
|
|
|
|
|
void VisitDecl(Decl *D);
|
|
|
|
void VisitTranslationUnitDecl(TranslationUnitDecl *D);
|
|
|
|
void VisitNamedDecl(NamedDecl *D);
|
|
|
|
void VisitTypeDecl(TypeDecl *D);
|
|
|
|
void VisitTypedefDecl(TypedefDecl *D);
|
2009-04-14 02:14:40 +08:00
|
|
|
void VisitTagDecl(TagDecl *D);
|
|
|
|
void VisitEnumDecl(EnumDecl *D);
|
2009-04-14 05:20:57 +08:00
|
|
|
void VisitRecordDecl(RecordDecl *D);
|
2009-04-10 06:27:44 +08:00
|
|
|
void VisitValueDecl(ValueDecl *D);
|
2009-04-14 02:14:40 +08:00
|
|
|
void VisitEnumConstantDecl(EnumConstantDecl *D);
|
2009-04-14 06:18:37 +08:00
|
|
|
void VisitFunctionDecl(FunctionDecl *D);
|
2009-04-14 05:20:57 +08:00
|
|
|
void VisitFieldDecl(FieldDecl *D);
|
2009-04-10 06:27:44 +08:00
|
|
|
void VisitVarDecl(VarDecl *D);
|
2009-04-14 06:18:37 +08:00
|
|
|
void VisitParmVarDecl(ParmVarDecl *D);
|
|
|
|
void VisitOriginalParmVarDecl(OriginalParmVarDecl *D);
|
2009-04-14 06:49:25 +08:00
|
|
|
void VisitFileScopeAsmDecl(FileScopeAsmDecl *D);
|
|
|
|
void VisitBlockDecl(BlockDecl *D);
|
2009-04-10 06:27:44 +08:00
|
|
|
void VisitDeclContext(DeclContext *DC, uint64_t LexicalOffset,
|
|
|
|
uint64_t VisibleOffset);
|
2009-04-20 23:06:07 +08:00
|
|
|
void VisitObjCMethodDecl(ObjCMethodDecl *D);
|
2009-04-21 04:09:33 +08:00
|
|
|
void VisitObjCContainerDecl(ObjCContainerDecl *D);
|
|
|
|
void VisitObjCInterfaceDecl(ObjCInterfaceDecl *D);
|
|
|
|
void VisitObjCIvarDecl(ObjCIvarDecl *D);
|
2009-04-21 23:12:33 +08:00
|
|
|
void VisitObjCProtocolDecl(ObjCProtocolDecl *D);
|
|
|
|
void VisitObjCAtDefsFieldDecl(ObjCAtDefsFieldDecl *D);
|
|
|
|
void VisitObjCClassDecl(ObjCClassDecl *D);
|
|
|
|
void VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D);
|
|
|
|
void VisitObjCCategoryDecl(ObjCCategoryDecl *D);
|
|
|
|
void VisitObjCImplDecl(ObjCImplDecl *D);
|
|
|
|
void VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D);
|
|
|
|
void VisitObjCImplementationDecl(ObjCImplementationDecl *D);
|
|
|
|
void VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *D);
|
|
|
|
void VisitObjCPropertyDecl(ObjCPropertyDecl *D);
|
|
|
|
void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D);
|
2009-04-10 06:27:44 +08:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
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());
|
2009-04-16 05:30:51 +08:00
|
|
|
Record.push_back(D->hasAttrs());
|
2009-04-10 06:27:44 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2009-04-14 02:14:40 +08:00
|
|
|
void PCHDeclWriter::VisitTagDecl(TagDecl *D) {
|
|
|
|
VisitTypeDecl(D);
|
|
|
|
Record.push_back((unsigned)D->getTagKind()); // FIXME: stable encoding
|
|
|
|
Record.push_back(D->isDefinition());
|
|
|
|
Writer.AddDeclRef(D->getTypedefForAnonDecl(), Record);
|
|
|
|
}
|
|
|
|
|
|
|
|
void PCHDeclWriter::VisitEnumDecl(EnumDecl *D) {
|
|
|
|
VisitTagDecl(D);
|
|
|
|
Writer.AddTypeRef(D->getIntegerType(), Record);
|
|
|
|
Code = pch::DECL_ENUM;
|
|
|
|
}
|
|
|
|
|
2009-04-14 05:20:57 +08:00
|
|
|
void PCHDeclWriter::VisitRecordDecl(RecordDecl *D) {
|
|
|
|
VisitTagDecl(D);
|
|
|
|
Record.push_back(D->hasFlexibleArrayMember());
|
|
|
|
Record.push_back(D->isAnonymousStructOrUnion());
|
|
|
|
Code = pch::DECL_RECORD;
|
|
|
|
}
|
|
|
|
|
2009-04-10 06:27:44 +08:00
|
|
|
void PCHDeclWriter::VisitValueDecl(ValueDecl *D) {
|
|
|
|
VisitNamedDecl(D);
|
|
|
|
Writer.AddTypeRef(D->getType(), Record);
|
|
|
|
}
|
|
|
|
|
2009-04-14 02:14:40 +08:00
|
|
|
void PCHDeclWriter::VisitEnumConstantDecl(EnumConstantDecl *D) {
|
|
|
|
VisitValueDecl(D);
|
2009-04-15 05:18:50 +08:00
|
|
|
Record.push_back(D->getInitExpr()? 1 : 0);
|
|
|
|
if (D->getInitExpr())
|
2009-04-17 06:23:12 +08:00
|
|
|
Writer.AddStmt(D->getInitExpr());
|
2009-04-14 02:14:40 +08:00
|
|
|
Writer.AddAPSInt(D->getInitVal(), Record);
|
|
|
|
Code = pch::DECL_ENUM_CONSTANT;
|
|
|
|
}
|
|
|
|
|
2009-04-14 06:18:37 +08:00
|
|
|
void PCHDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
|
|
|
|
VisitValueDecl(D);
|
2009-04-17 08:04:06 +08:00
|
|
|
Record.push_back(D->isThisDeclarationADefinition());
|
|
|
|
if (D->isThisDeclarationADefinition())
|
2009-04-18 08:02:19 +08:00
|
|
|
Writer.AddStmt(D->getBody(Context));
|
2009-04-14 06:18:37 +08:00
|
|
|
Writer.AddDeclRef(D->getPreviousDeclaration(), Record);
|
|
|
|
Record.push_back(D->getStorageClass()); // FIXME: stable encoding
|
|
|
|
Record.push_back(D->isInline());
|
2009-04-24 02:22:55 +08:00
|
|
|
Record.push_back(D->isC99InlineDefinition());
|
2009-04-14 06:18:37 +08:00
|
|
|
Record.push_back(D->isVirtual());
|
|
|
|
Record.push_back(D->isPure());
|
|
|
|
Record.push_back(D->inheritedPrototype());
|
|
|
|
Record.push_back(D->hasPrototype() && !D->inheritedPrototype());
|
|
|
|
Record.push_back(D->isDeleted());
|
|
|
|
Writer.AddSourceLocation(D->getTypeSpecStartLoc(), Record);
|
|
|
|
Record.push_back(D->param_size());
|
|
|
|
for (FunctionDecl::param_iterator P = D->param_begin(), PEnd = D->param_end();
|
|
|
|
P != PEnd; ++P)
|
|
|
|
Writer.AddDeclRef(*P, Record);
|
|
|
|
Code = pch::DECL_FUNCTION;
|
|
|
|
}
|
|
|
|
|
2009-04-20 23:06:07 +08:00
|
|
|
void PCHDeclWriter::VisitObjCMethodDecl(ObjCMethodDecl *D) {
|
|
|
|
VisitNamedDecl(D);
|
|
|
|
// FIXME: convert to LazyStmtPtr?
|
|
|
|
// Unlike C/C++, method bodies will never be in header files.
|
|
|
|
Record.push_back(D->getBody() != 0);
|
|
|
|
if (D->getBody() != 0) {
|
|
|
|
Writer.AddStmt(D->getBody(Context));
|
|
|
|
Writer.AddDeclRef(D->getSelfDecl(), Record);
|
|
|
|
Writer.AddDeclRef(D->getCmdDecl(), Record);
|
|
|
|
}
|
|
|
|
Record.push_back(D->isInstanceMethod());
|
|
|
|
Record.push_back(D->isVariadic());
|
|
|
|
Record.push_back(D->isSynthesized());
|
|
|
|
// FIXME: stable encoding for @required/@optional
|
|
|
|
Record.push_back(D->getImplementationControl());
|
|
|
|
// FIXME: stable encoding for in/out/inout/bycopy/byref/oneway
|
|
|
|
Record.push_back(D->getObjCDeclQualifier());
|
|
|
|
Writer.AddTypeRef(D->getResultType(), Record);
|
|
|
|
Writer.AddSourceLocation(D->getLocEnd(), Record);
|
|
|
|
Record.push_back(D->param_size());
|
|
|
|
for (ObjCMethodDecl::param_iterator P = D->param_begin(),
|
|
|
|
PEnd = D->param_end(); P != PEnd; ++P)
|
|
|
|
Writer.AddDeclRef(*P, Record);
|
|
|
|
Code = pch::DECL_OBJC_METHOD;
|
|
|
|
}
|
|
|
|
|
2009-04-21 04:09:33 +08:00
|
|
|
void PCHDeclWriter::VisitObjCContainerDecl(ObjCContainerDecl *D) {
|
|
|
|
VisitNamedDecl(D);
|
|
|
|
Writer.AddSourceLocation(D->getAtEndLoc(), Record);
|
|
|
|
// Abstract class (no need to define a stable pch::DECL code).
|
|
|
|
}
|
|
|
|
|
|
|
|
void PCHDeclWriter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
|
|
|
|
VisitObjCContainerDecl(D);
|
|
|
|
Writer.AddTypeRef(QualType(D->getTypeForDecl(), 0), Record);
|
|
|
|
Writer.AddDeclRef(D->getSuperClass(), Record);
|
2009-04-23 11:59:07 +08:00
|
|
|
Record.push_back(D->protocol_size());
|
|
|
|
for (ObjCInterfaceDecl::protocol_iterator P = D->protocol_begin(),
|
|
|
|
PEnd = D->protocol_end();
|
|
|
|
P != PEnd; ++P)
|
|
|
|
Writer.AddDeclRef(*P, Record);
|
2009-04-21 04:09:33 +08:00
|
|
|
Record.push_back(D->ivar_size());
|
|
|
|
for (ObjCInterfaceDecl::ivar_iterator I = D->ivar_begin(),
|
|
|
|
IEnd = D->ivar_end(); I != IEnd; ++I)
|
|
|
|
Writer.AddDeclRef(*I, Record);
|
2009-04-24 06:34:55 +08:00
|
|
|
Writer.AddDeclRef(D->getCategoryList(), Record);
|
2009-04-21 04:09:33 +08:00
|
|
|
Record.push_back(D->isForwardDecl());
|
|
|
|
Record.push_back(D->isImplicitInterfaceDecl());
|
|
|
|
Writer.AddSourceLocation(D->getClassLoc(), Record);
|
|
|
|
Writer.AddSourceLocation(D->getSuperClassLoc(), Record);
|
|
|
|
Writer.AddSourceLocation(D->getLocEnd(), Record);
|
2009-04-21 23:12:33 +08:00
|
|
|
Code = pch::DECL_OBJC_INTERFACE;
|
2009-04-21 04:09:33 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void PCHDeclWriter::VisitObjCIvarDecl(ObjCIvarDecl *D) {
|
|
|
|
VisitFieldDecl(D);
|
|
|
|
// FIXME: stable encoding for @public/@private/@protected/@package
|
|
|
|
Record.push_back(D->getAccessControl());
|
2009-04-21 23:12:33 +08:00
|
|
|
Code = pch::DECL_OBJC_IVAR;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PCHDeclWriter::VisitObjCProtocolDecl(ObjCProtocolDecl *D) {
|
|
|
|
VisitObjCContainerDecl(D);
|
|
|
|
Record.push_back(D->isForwardDecl());
|
|
|
|
Writer.AddSourceLocation(D->getLocEnd(), Record);
|
|
|
|
Record.push_back(D->protocol_size());
|
|
|
|
for (ObjCProtocolDecl::protocol_iterator
|
|
|
|
I = D->protocol_begin(), IEnd = D->protocol_end(); I != IEnd; ++I)
|
|
|
|
Writer.AddDeclRef(*I, Record);
|
|
|
|
Code = pch::DECL_OBJC_PROTOCOL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PCHDeclWriter::VisitObjCAtDefsFieldDecl(ObjCAtDefsFieldDecl *D) {
|
|
|
|
VisitFieldDecl(D);
|
|
|
|
Code = pch::DECL_OBJC_AT_DEFS_FIELD;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PCHDeclWriter::VisitObjCClassDecl(ObjCClassDecl *D) {
|
|
|
|
VisitDecl(D);
|
|
|
|
Record.push_back(D->size());
|
|
|
|
for (ObjCClassDecl::iterator I = D->begin(), IEnd = D->end(); I != IEnd; ++I)
|
|
|
|
Writer.AddDeclRef(*I, Record);
|
|
|
|
Code = pch::DECL_OBJC_CLASS;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PCHDeclWriter::VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D) {
|
|
|
|
VisitDecl(D);
|
|
|
|
Record.push_back(D->protocol_size());
|
|
|
|
for (ObjCProtocolDecl::protocol_iterator
|
|
|
|
I = D->protocol_begin(), IEnd = D->protocol_end(); I != IEnd; ++I)
|
|
|
|
Writer.AddDeclRef(*I, Record);
|
|
|
|
Code = pch::DECL_OBJC_FORWARD_PROTOCOL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PCHDeclWriter::VisitObjCCategoryDecl(ObjCCategoryDecl *D) {
|
|
|
|
VisitObjCContainerDecl(D);
|
|
|
|
Writer.AddDeclRef(D->getClassInterface(), Record);
|
|
|
|
Record.push_back(D->protocol_size());
|
|
|
|
for (ObjCProtocolDecl::protocol_iterator
|
|
|
|
I = D->protocol_begin(), IEnd = D->protocol_end(); I != IEnd; ++I)
|
|
|
|
Writer.AddDeclRef(*I, Record);
|
|
|
|
Writer.AddDeclRef(D->getNextClassCategory(), Record);
|
|
|
|
Writer.AddSourceLocation(D->getLocEnd(), Record);
|
|
|
|
Code = pch::DECL_OBJC_CATEGORY;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PCHDeclWriter::VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *D) {
|
|
|
|
VisitNamedDecl(D);
|
|
|
|
Writer.AddDeclRef(D->getClassInterface(), Record);
|
|
|
|
Code = pch::DECL_OBJC_COMPATIBLE_ALIAS;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PCHDeclWriter::VisitObjCPropertyDecl(ObjCPropertyDecl *D) {
|
|
|
|
VisitNamedDecl(D);
|
2009-04-23 07:20:34 +08:00
|
|
|
Writer.AddTypeRef(D->getType(), Record);
|
|
|
|
// FIXME: stable encoding
|
|
|
|
Record.push_back((unsigned)D->getPropertyAttributes());
|
|
|
|
// FIXME: stable encoding
|
|
|
|
Record.push_back((unsigned)D->getPropertyImplementation());
|
|
|
|
Writer.AddDeclarationName(D->getGetterName(), Record);
|
|
|
|
Writer.AddDeclarationName(D->getSetterName(), Record);
|
|
|
|
Writer.AddDeclRef(D->getGetterMethodDecl(), Record);
|
|
|
|
Writer.AddDeclRef(D->getSetterMethodDecl(), Record);
|
|
|
|
Writer.AddDeclRef(D->getPropertyIvarDecl(), Record);
|
2009-04-21 23:12:33 +08:00
|
|
|
Code = pch::DECL_OBJC_PROPERTY;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PCHDeclWriter::VisitObjCImplDecl(ObjCImplDecl *D) {
|
2009-04-24 08:11:27 +08:00
|
|
|
VisitNamedDecl(D);
|
2009-04-23 10:42:49 +08:00
|
|
|
Writer.AddDeclRef(D->getClassInterface(), Record);
|
|
|
|
Writer.AddSourceLocation(D->getLocEnd(), Record);
|
2009-04-21 23:12:33 +08:00
|
|
|
// Abstract class (no need to define a stable pch::DECL code).
|
|
|
|
}
|
|
|
|
|
|
|
|
void PCHDeclWriter::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) {
|
|
|
|
VisitObjCImplDecl(D);
|
2009-04-23 10:53:57 +08:00
|
|
|
Writer.AddIdentifierRef(D->getIdentifier(), Record);
|
2009-04-21 23:12:33 +08:00
|
|
|
Code = pch::DECL_OBJC_CATEGORY_IMPL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PCHDeclWriter::VisitObjCImplementationDecl(ObjCImplementationDecl *D) {
|
|
|
|
VisitObjCImplDecl(D);
|
2009-04-23 11:23:08 +08:00
|
|
|
Writer.AddDeclRef(D->getSuperClass(), Record);
|
2009-04-21 23:12:33 +08:00
|
|
|
Code = pch::DECL_OBJC_IMPLEMENTATION;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PCHDeclWriter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) {
|
|
|
|
VisitDecl(D);
|
2009-04-23 11:43:53 +08:00
|
|
|
Writer.AddSourceLocation(D->getLocStart(), Record);
|
|
|
|
Writer.AddDeclRef(D->getPropertyDecl(), Record);
|
|
|
|
Writer.AddDeclRef(D->getPropertyIvarDecl(), Record);
|
2009-04-21 23:12:33 +08:00
|
|
|
Code = pch::DECL_OBJC_PROPERTY_IMPL;
|
2009-04-21 04:09:33 +08:00
|
|
|
}
|
|
|
|
|
2009-04-14 05:20:57 +08:00
|
|
|
void PCHDeclWriter::VisitFieldDecl(FieldDecl *D) {
|
|
|
|
VisitValueDecl(D);
|
|
|
|
Record.push_back(D->isMutable());
|
2009-04-15 05:18:50 +08:00
|
|
|
Record.push_back(D->getBitWidth()? 1 : 0);
|
|
|
|
if (D->getBitWidth())
|
2009-04-17 06:23:12 +08:00
|
|
|
Writer.AddStmt(D->getBitWidth());
|
2009-04-14 05:20:57 +08:00
|
|
|
Code = pch::DECL_FIELD;
|
|
|
|
}
|
|
|
|
|
2009-04-10 06:27:44 +08:00
|
|
|
void PCHDeclWriter::VisitVarDecl(VarDecl *D) {
|
|
|
|
VisitValueDecl(D);
|
2009-04-14 06:18:37 +08:00
|
|
|
Record.push_back(D->getStorageClass()); // FIXME: stable encoding
|
2009-04-10 06:27:44 +08:00
|
|
|
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);
|
2009-04-15 05:18:50 +08:00
|
|
|
Record.push_back(D->getInit()? 1 : 0);
|
|
|
|
if (D->getInit())
|
2009-04-17 06:23:12 +08:00
|
|
|
Writer.AddStmt(D->getInit());
|
2009-04-10 06:27:44 +08:00
|
|
|
Code = pch::DECL_VAR;
|
|
|
|
}
|
|
|
|
|
2009-04-14 06:18:37 +08:00
|
|
|
void PCHDeclWriter::VisitParmVarDecl(ParmVarDecl *D) {
|
|
|
|
VisitVarDecl(D);
|
|
|
|
Record.push_back(D->getObjCDeclQualifier()); // FIXME: stable encoding
|
2009-04-16 02:43:11 +08:00
|
|
|
// FIXME: emit default argument (C++)
|
2009-04-14 06:18:37 +08:00
|
|
|
// FIXME: why isn't the "default argument" just stored as the initializer
|
|
|
|
// in VarDecl?
|
|
|
|
Code = pch::DECL_PARM_VAR;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PCHDeclWriter::VisitOriginalParmVarDecl(OriginalParmVarDecl *D) {
|
|
|
|
VisitParmVarDecl(D);
|
|
|
|
Writer.AddTypeRef(D->getOriginalType(), Record);
|
|
|
|
Code = pch::DECL_ORIGINAL_PARM_VAR;
|
|
|
|
}
|
|
|
|
|
2009-04-14 06:49:25 +08:00
|
|
|
void PCHDeclWriter::VisitFileScopeAsmDecl(FileScopeAsmDecl *D) {
|
|
|
|
VisitDecl(D);
|
2009-04-17 06:23:12 +08:00
|
|
|
Writer.AddStmt(D->getAsmString());
|
2009-04-14 06:49:25 +08:00
|
|
|
Code = pch::DECL_FILE_SCOPE_ASM;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PCHDeclWriter::VisitBlockDecl(BlockDecl *D) {
|
|
|
|
VisitDecl(D);
|
2009-04-18 03:21:43 +08:00
|
|
|
Writer.AddStmt(D->getBody());
|
2009-04-14 06:49:25 +08:00
|
|
|
Record.push_back(D->param_size());
|
|
|
|
for (FunctionDecl::param_iterator P = D->param_begin(), PEnd = D->param_end();
|
|
|
|
P != PEnd; ++P)
|
|
|
|
Writer.AddDeclRef(*P, Record);
|
|
|
|
Code = pch::DECL_BLOCK;
|
|
|
|
}
|
|
|
|
|
2009-04-10 06:27:44 +08:00
|
|
|
/// \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);
|
2009-04-23 03:09:20 +08:00
|
|
|
Record.push_back(VisibleOffset);
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
|
|
|
|
2009-04-15 05:18:50 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Statement/expression serialization
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
namespace {
|
|
|
|
class VISIBILITY_HIDDEN PCHStmtWriter
|
|
|
|
: public StmtVisitor<PCHStmtWriter, void> {
|
|
|
|
|
|
|
|
PCHWriter &Writer;
|
|
|
|
PCHWriter::RecordData &Record;
|
|
|
|
|
|
|
|
public:
|
|
|
|
pch::StmtCode Code;
|
|
|
|
|
|
|
|
PCHStmtWriter(PCHWriter &Writer, PCHWriter::RecordData &Record)
|
|
|
|
: Writer(Writer), Record(Record) { }
|
|
|
|
|
2009-04-17 08:04:06 +08:00
|
|
|
void VisitStmt(Stmt *S);
|
|
|
|
void VisitNullStmt(NullStmt *S);
|
|
|
|
void VisitCompoundStmt(CompoundStmt *S);
|
|
|
|
void VisitSwitchCase(SwitchCase *S);
|
|
|
|
void VisitCaseStmt(CaseStmt *S);
|
|
|
|
void VisitDefaultStmt(DefaultStmt *S);
|
2009-04-18 02:18:49 +08:00
|
|
|
void VisitLabelStmt(LabelStmt *S);
|
2009-04-17 08:04:06 +08:00
|
|
|
void VisitIfStmt(IfStmt *S);
|
|
|
|
void VisitSwitchStmt(SwitchStmt *S);
|
2009-04-17 08:16:09 +08:00
|
|
|
void VisitWhileStmt(WhileStmt *S);
|
2009-04-17 08:29:51 +08:00
|
|
|
void VisitDoStmt(DoStmt *S);
|
|
|
|
void VisitForStmt(ForStmt *S);
|
2009-04-18 02:18:49 +08:00
|
|
|
void VisitGotoStmt(GotoStmt *S);
|
2009-04-18 02:58:21 +08:00
|
|
|
void VisitIndirectGotoStmt(IndirectGotoStmt *S);
|
2009-04-17 08:16:09 +08:00
|
|
|
void VisitContinueStmt(ContinueStmt *S);
|
2009-04-17 08:04:06 +08:00
|
|
|
void VisitBreakStmt(BreakStmt *S);
|
2009-04-18 00:34:57 +08:00
|
|
|
void VisitReturnStmt(ReturnStmt *S);
|
2009-04-18 00:55:36 +08:00
|
|
|
void VisitDeclStmt(DeclStmt *S);
|
2009-04-18 04:57:14 +08:00
|
|
|
void VisitAsmStmt(AsmStmt *S);
|
2009-04-15 05:18:50 +08:00
|
|
|
void VisitExpr(Expr *E);
|
2009-04-15 05:55:33 +08:00
|
|
|
void VisitPredefinedExpr(PredefinedExpr *E);
|
2009-04-15 05:18:50 +08:00
|
|
|
void VisitDeclRefExpr(DeclRefExpr *E);
|
|
|
|
void VisitIntegerLiteral(IntegerLiteral *E);
|
2009-04-15 05:55:33 +08:00
|
|
|
void VisitFloatingLiteral(FloatingLiteral *E);
|
2009-04-16 06:19:53 +08:00
|
|
|
void VisitImaginaryLiteral(ImaginaryLiteral *E);
|
2009-04-16 00:35:07 +08:00
|
|
|
void VisitStringLiteral(StringLiteral *E);
|
2009-04-15 05:18:50 +08:00
|
|
|
void VisitCharacterLiteral(CharacterLiteral *E);
|
2009-04-15 07:59:37 +08:00
|
|
|
void VisitParenExpr(ParenExpr *E);
|
2009-04-15 23:58:59 +08:00
|
|
|
void VisitUnaryOperator(UnaryOperator *E);
|
|
|
|
void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E);
|
2009-04-16 06:19:53 +08:00
|
|
|
void VisitArraySubscriptExpr(ArraySubscriptExpr *E);
|
2009-04-16 01:43:59 +08:00
|
|
|
void VisitCallExpr(CallExpr *E);
|
|
|
|
void VisitMemberExpr(MemberExpr *E);
|
2009-04-15 07:32:43 +08:00
|
|
|
void VisitCastExpr(CastExpr *E);
|
2009-04-15 08:25:59 +08:00
|
|
|
void VisitBinaryOperator(BinaryOperator *E);
|
2009-04-16 06:40:36 +08:00
|
|
|
void VisitCompoundAssignOperator(CompoundAssignOperator *E);
|
|
|
|
void VisitConditionalOperator(ConditionalOperator *E);
|
2009-04-15 07:32:43 +08:00
|
|
|
void VisitImplicitCastExpr(ImplicitCastExpr *E);
|
2009-04-15 08:25:59 +08:00
|
|
|
void VisitExplicitCastExpr(ExplicitCastExpr *E);
|
|
|
|
void VisitCStyleCastExpr(CStyleCastExpr *E);
|
2009-04-16 10:33:48 +08:00
|
|
|
void VisitCompoundLiteralExpr(CompoundLiteralExpr *E);
|
2009-04-16 07:02:49 +08:00
|
|
|
void VisitExtVectorElementExpr(ExtVectorElementExpr *E);
|
2009-04-16 08:55:48 +08:00
|
|
|
void VisitInitListExpr(InitListExpr *E);
|
|
|
|
void VisitDesignatedInitExpr(DesignatedInitExpr *E);
|
|
|
|
void VisitImplicitValueInitExpr(ImplicitValueInitExpr *E);
|
2009-04-16 07:02:49 +08:00
|
|
|
void VisitVAArgExpr(VAArgExpr *E);
|
2009-04-18 02:58:21 +08:00
|
|
|
void VisitAddrLabelExpr(AddrLabelExpr *E);
|
2009-04-18 03:05:30 +08:00
|
|
|
void VisitStmtExpr(StmtExpr *E);
|
2009-04-16 07:33:31 +08:00
|
|
|
void VisitTypesCompatibleExpr(TypesCompatibleExpr *E);
|
|
|
|
void VisitChooseExpr(ChooseExpr *E);
|
|
|
|
void VisitGNUNullExpr(GNUNullExpr *E);
|
2009-04-16 08:01:45 +08:00
|
|
|
void VisitShuffleVectorExpr(ShuffleVectorExpr *E);
|
2009-04-18 03:21:43 +08:00
|
|
|
void VisitBlockExpr(BlockExpr *E);
|
2009-04-16 08:01:45 +08:00
|
|
|
void VisitBlockDeclRefExpr(BlockDeclRefExpr *E);
|
2009-04-22 13:57:30 +08:00
|
|
|
|
2009-04-27 02:52:16 +08:00
|
|
|
// Objective-C Expressions
|
2009-04-22 14:29:42 +08:00
|
|
|
void VisitObjCStringLiteral(ObjCStringLiteral *E);
|
2009-04-22 13:57:30 +08:00
|
|
|
void VisitObjCEncodeExpr(ObjCEncodeExpr *E);
|
2009-04-22 14:29:42 +08:00
|
|
|
void VisitObjCSelectorExpr(ObjCSelectorExpr *E);
|
|
|
|
void VisitObjCProtocolExpr(ObjCProtocolExpr *E);
|
2009-04-26 08:44:05 +08:00
|
|
|
void VisitObjCIvarRefExpr(ObjCIvarRefExpr *E);
|
|
|
|
void VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E);
|
|
|
|
void VisitObjCKVCRefExpr(ObjCKVCRefExpr *E);
|
2009-04-25 22:04:28 +08:00
|
|
|
void VisitObjCMessageExpr(ObjCMessageExpr *E);
|
2009-04-26 08:44:05 +08:00
|
|
|
void VisitObjCSuperExpr(ObjCSuperExpr *E);
|
2009-04-27 02:52:16 +08:00
|
|
|
|
|
|
|
// Objective-C Statements
|
|
|
|
void VisitObjCForCollectionStmt(ObjCForCollectionStmt *);
|
|
|
|
void VisitObjCCatchStmt(ObjCAtCatchStmt *);
|
|
|
|
void VisitObjCFinallyStmt(ObjCAtFinallyStmt *);
|
|
|
|
void VisitObjCAtTryStmt(ObjCAtTryStmt *);
|
|
|
|
void VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *);
|
|
|
|
void VisitObjCAtThrowStmt(ObjCAtThrowStmt *);
|
2009-04-15 05:18:50 +08:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2009-04-17 08:04:06 +08:00
|
|
|
void PCHStmtWriter::VisitStmt(Stmt *S) {
|
|
|
|
}
|
|
|
|
|
|
|
|
void PCHStmtWriter::VisitNullStmt(NullStmt *S) {
|
|
|
|
VisitStmt(S);
|
|
|
|
Writer.AddSourceLocation(S->getSemiLoc(), Record);
|
|
|
|
Code = pch::STMT_NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PCHStmtWriter::VisitCompoundStmt(CompoundStmt *S) {
|
|
|
|
VisitStmt(S);
|
|
|
|
Record.push_back(S->size());
|
|
|
|
for (CompoundStmt::body_iterator CS = S->body_begin(), CSEnd = S->body_end();
|
|
|
|
CS != CSEnd; ++CS)
|
|
|
|
Writer.WriteSubStmt(*CS);
|
|
|
|
Writer.AddSourceLocation(S->getLBracLoc(), Record);
|
|
|
|
Writer.AddSourceLocation(S->getRBracLoc(), Record);
|
|
|
|
Code = pch::STMT_COMPOUND;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PCHStmtWriter::VisitSwitchCase(SwitchCase *S) {
|
|
|
|
VisitStmt(S);
|
|
|
|
Record.push_back(Writer.RecordSwitchCaseID(S));
|
|
|
|
}
|
|
|
|
|
|
|
|
void PCHStmtWriter::VisitCaseStmt(CaseStmt *S) {
|
|
|
|
VisitSwitchCase(S);
|
|
|
|
Writer.WriteSubStmt(S->getLHS());
|
|
|
|
Writer.WriteSubStmt(S->getRHS());
|
|
|
|
Writer.WriteSubStmt(S->getSubStmt());
|
|
|
|
Writer.AddSourceLocation(S->getCaseLoc(), Record);
|
|
|
|
Code = pch::STMT_CASE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PCHStmtWriter::VisitDefaultStmt(DefaultStmt *S) {
|
|
|
|
VisitSwitchCase(S);
|
|
|
|
Writer.WriteSubStmt(S->getSubStmt());
|
|
|
|
Writer.AddSourceLocation(S->getDefaultLoc(), Record);
|
|
|
|
Code = pch::STMT_DEFAULT;
|
|
|
|
}
|
|
|
|
|
2009-04-18 02:18:49 +08:00
|
|
|
void PCHStmtWriter::VisitLabelStmt(LabelStmt *S) {
|
|
|
|
VisitStmt(S);
|
|
|
|
Writer.AddIdentifierRef(S->getID(), Record);
|
|
|
|
Writer.WriteSubStmt(S->getSubStmt());
|
|
|
|
Writer.AddSourceLocation(S->getIdentLoc(), Record);
|
|
|
|
Record.push_back(Writer.GetLabelID(S));
|
|
|
|
Code = pch::STMT_LABEL;
|
|
|
|
}
|
|
|
|
|
2009-04-17 08:04:06 +08:00
|
|
|
void PCHStmtWriter::VisitIfStmt(IfStmt *S) {
|
|
|
|
VisitStmt(S);
|
|
|
|
Writer.WriteSubStmt(S->getCond());
|
|
|
|
Writer.WriteSubStmt(S->getThen());
|
|
|
|
Writer.WriteSubStmt(S->getElse());
|
|
|
|
Writer.AddSourceLocation(S->getIfLoc(), Record);
|
|
|
|
Code = pch::STMT_IF;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PCHStmtWriter::VisitSwitchStmt(SwitchStmt *S) {
|
|
|
|
VisitStmt(S);
|
|
|
|
Writer.WriteSubStmt(S->getCond());
|
|
|
|
Writer.WriteSubStmt(S->getBody());
|
|
|
|
Writer.AddSourceLocation(S->getSwitchLoc(), Record);
|
|
|
|
for (SwitchCase *SC = S->getSwitchCaseList(); SC;
|
|
|
|
SC = SC->getNextSwitchCase())
|
|
|
|
Record.push_back(Writer.getSwitchCaseID(SC));
|
|
|
|
Code = pch::STMT_SWITCH;
|
|
|
|
}
|
|
|
|
|
2009-04-17 08:16:09 +08:00
|
|
|
void PCHStmtWriter::VisitWhileStmt(WhileStmt *S) {
|
|
|
|
VisitStmt(S);
|
|
|
|
Writer.WriteSubStmt(S->getCond());
|
|
|
|
Writer.WriteSubStmt(S->getBody());
|
|
|
|
Writer.AddSourceLocation(S->getWhileLoc(), Record);
|
|
|
|
Code = pch::STMT_WHILE;
|
|
|
|
}
|
|
|
|
|
2009-04-17 08:29:51 +08:00
|
|
|
void PCHStmtWriter::VisitDoStmt(DoStmt *S) {
|
|
|
|
VisitStmt(S);
|
|
|
|
Writer.WriteSubStmt(S->getCond());
|
|
|
|
Writer.WriteSubStmt(S->getBody());
|
|
|
|
Writer.AddSourceLocation(S->getDoLoc(), Record);
|
|
|
|
Code = pch::STMT_DO;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PCHStmtWriter::VisitForStmt(ForStmt *S) {
|
|
|
|
VisitStmt(S);
|
|
|
|
Writer.WriteSubStmt(S->getInit());
|
|
|
|
Writer.WriteSubStmt(S->getCond());
|
|
|
|
Writer.WriteSubStmt(S->getInc());
|
|
|
|
Writer.WriteSubStmt(S->getBody());
|
|
|
|
Writer.AddSourceLocation(S->getForLoc(), Record);
|
|
|
|
Code = pch::STMT_FOR;
|
|
|
|
}
|
|
|
|
|
2009-04-18 02:18:49 +08:00
|
|
|
void PCHStmtWriter::VisitGotoStmt(GotoStmt *S) {
|
|
|
|
VisitStmt(S);
|
|
|
|
Record.push_back(Writer.GetLabelID(S->getLabel()));
|
|
|
|
Writer.AddSourceLocation(S->getGotoLoc(), Record);
|
|
|
|
Writer.AddSourceLocation(S->getLabelLoc(), Record);
|
|
|
|
Code = pch::STMT_GOTO;
|
|
|
|
}
|
|
|
|
|
2009-04-18 02:58:21 +08:00
|
|
|
void PCHStmtWriter::VisitIndirectGotoStmt(IndirectGotoStmt *S) {
|
|
|
|
VisitStmt(S);
|
2009-04-19 09:04:21 +08:00
|
|
|
Writer.AddSourceLocation(S->getGotoLoc(), Record);
|
2009-04-18 02:58:21 +08:00
|
|
|
Writer.WriteSubStmt(S->getTarget());
|
|
|
|
Code = pch::STMT_INDIRECT_GOTO;
|
|
|
|
}
|
|
|
|
|
2009-04-17 08:16:09 +08:00
|
|
|
void PCHStmtWriter::VisitContinueStmt(ContinueStmt *S) {
|
|
|
|
VisitStmt(S);
|
|
|
|
Writer.AddSourceLocation(S->getContinueLoc(), Record);
|
|
|
|
Code = pch::STMT_CONTINUE;
|
|
|
|
}
|
|
|
|
|
2009-04-17 08:04:06 +08:00
|
|
|
void PCHStmtWriter::VisitBreakStmt(BreakStmt *S) {
|
|
|
|
VisitStmt(S);
|
|
|
|
Writer.AddSourceLocation(S->getBreakLoc(), Record);
|
|
|
|
Code = pch::STMT_BREAK;
|
|
|
|
}
|
|
|
|
|
2009-04-18 00:34:57 +08:00
|
|
|
void PCHStmtWriter::VisitReturnStmt(ReturnStmt *S) {
|
|
|
|
VisitStmt(S);
|
|
|
|
Writer.WriteSubStmt(S->getRetValue());
|
|
|
|
Writer.AddSourceLocation(S->getReturnLoc(), Record);
|
|
|
|
Code = pch::STMT_RETURN;
|
|
|
|
}
|
|
|
|
|
2009-04-18 00:55:36 +08:00
|
|
|
void PCHStmtWriter::VisitDeclStmt(DeclStmt *S) {
|
|
|
|
VisitStmt(S);
|
|
|
|
Writer.AddSourceLocation(S->getStartLoc(), Record);
|
|
|
|
Writer.AddSourceLocation(S->getEndLoc(), Record);
|
|
|
|
DeclGroupRef DG = S->getDeclGroup();
|
|
|
|
for (DeclGroupRef::iterator D = DG.begin(), DEnd = DG.end(); D != DEnd; ++D)
|
|
|
|
Writer.AddDeclRef(*D, Record);
|
|
|
|
Code = pch::STMT_DECL;
|
|
|
|
}
|
|
|
|
|
2009-04-18 04:57:14 +08:00
|
|
|
void PCHStmtWriter::VisitAsmStmt(AsmStmt *S) {
|
|
|
|
VisitStmt(S);
|
|
|
|
Record.push_back(S->getNumOutputs());
|
|
|
|
Record.push_back(S->getNumInputs());
|
|
|
|
Record.push_back(S->getNumClobbers());
|
|
|
|
Writer.AddSourceLocation(S->getAsmLoc(), Record);
|
|
|
|
Writer.AddSourceLocation(S->getRParenLoc(), Record);
|
|
|
|
Record.push_back(S->isVolatile());
|
|
|
|
Record.push_back(S->isSimple());
|
|
|
|
Writer.WriteSubStmt(S->getAsmString());
|
|
|
|
|
|
|
|
// Outputs
|
|
|
|
for (unsigned I = 0, N = S->getNumOutputs(); I != N; ++I) {
|
|
|
|
Writer.AddString(S->getOutputName(I), Record);
|
|
|
|
Writer.WriteSubStmt(S->getOutputConstraintLiteral(I));
|
|
|
|
Writer.WriteSubStmt(S->getOutputExpr(I));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Inputs
|
|
|
|
for (unsigned I = 0, N = S->getNumInputs(); I != N; ++I) {
|
|
|
|
Writer.AddString(S->getInputName(I), Record);
|
|
|
|
Writer.WriteSubStmt(S->getInputConstraintLiteral(I));
|
|
|
|
Writer.WriteSubStmt(S->getInputExpr(I));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Clobbers
|
|
|
|
for (unsigned I = 0, N = S->getNumClobbers(); I != N; ++I)
|
|
|
|
Writer.WriteSubStmt(S->getClobber(I));
|
|
|
|
|
|
|
|
Code = pch::STMT_ASM;
|
|
|
|
}
|
|
|
|
|
2009-04-15 05:18:50 +08:00
|
|
|
void PCHStmtWriter::VisitExpr(Expr *E) {
|
2009-04-17 08:04:06 +08:00
|
|
|
VisitStmt(E);
|
2009-04-15 05:18:50 +08:00
|
|
|
Writer.AddTypeRef(E->getType(), Record);
|
|
|
|
Record.push_back(E->isTypeDependent());
|
|
|
|
Record.push_back(E->isValueDependent());
|
|
|
|
}
|
|
|
|
|
2009-04-15 05:55:33 +08:00
|
|
|
void PCHStmtWriter::VisitPredefinedExpr(PredefinedExpr *E) {
|
|
|
|
VisitExpr(E);
|
|
|
|
Writer.AddSourceLocation(E->getLocation(), Record);
|
|
|
|
Record.push_back(E->getIdentType()); // FIXME: stable encoding
|
|
|
|
Code = pch::EXPR_PREDEFINED;
|
|
|
|
}
|
|
|
|
|
2009-04-15 05:18:50 +08:00
|
|
|
void PCHStmtWriter::VisitDeclRefExpr(DeclRefExpr *E) {
|
|
|
|
VisitExpr(E);
|
|
|
|
Writer.AddDeclRef(E->getDecl(), Record);
|
|
|
|
Writer.AddSourceLocation(E->getLocation(), Record);
|
|
|
|
Code = pch::EXPR_DECL_REF;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PCHStmtWriter::VisitIntegerLiteral(IntegerLiteral *E) {
|
|
|
|
VisitExpr(E);
|
|
|
|
Writer.AddSourceLocation(E->getLocation(), Record);
|
|
|
|
Writer.AddAPInt(E->getValue(), Record);
|
|
|
|
Code = pch::EXPR_INTEGER_LITERAL;
|
|
|
|
}
|
|
|
|
|
2009-04-15 05:55:33 +08:00
|
|
|
void PCHStmtWriter::VisitFloatingLiteral(FloatingLiteral *E) {
|
|
|
|
VisitExpr(E);
|
|
|
|
Writer.AddAPFloat(E->getValue(), Record);
|
|
|
|
Record.push_back(E->isExact());
|
|
|
|
Writer.AddSourceLocation(E->getLocation(), Record);
|
|
|
|
Code = pch::EXPR_FLOATING_LITERAL;
|
|
|
|
}
|
|
|
|
|
2009-04-16 06:19:53 +08:00
|
|
|
void PCHStmtWriter::VisitImaginaryLiteral(ImaginaryLiteral *E) {
|
|
|
|
VisitExpr(E);
|
2009-04-17 06:23:12 +08:00
|
|
|
Writer.WriteSubStmt(E->getSubExpr());
|
2009-04-16 06:19:53 +08:00
|
|
|
Code = pch::EXPR_IMAGINARY_LITERAL;
|
|
|
|
}
|
|
|
|
|
2009-04-16 00:35:07 +08:00
|
|
|
void PCHStmtWriter::VisitStringLiteral(StringLiteral *E) {
|
|
|
|
VisitExpr(E);
|
|
|
|
Record.push_back(E->getByteLength());
|
|
|
|
Record.push_back(E->getNumConcatenated());
|
|
|
|
Record.push_back(E->isWide());
|
|
|
|
// FIXME: String data should be stored as a blob at the end of the
|
|
|
|
// StringLiteral. However, we can't do so now because we have no
|
|
|
|
// provision for coping with abbreviations when we're jumping around
|
|
|
|
// the PCH file during deserialization.
|
|
|
|
Record.insert(Record.end(),
|
|
|
|
E->getStrData(), E->getStrData() + E->getByteLength());
|
|
|
|
for (unsigned I = 0, N = E->getNumConcatenated(); I != N; ++I)
|
|
|
|
Writer.AddSourceLocation(E->getStrTokenLoc(I), Record);
|
|
|
|
Code = pch::EXPR_STRING_LITERAL;
|
|
|
|
}
|
|
|
|
|
2009-04-15 05:18:50 +08:00
|
|
|
void PCHStmtWriter::VisitCharacterLiteral(CharacterLiteral *E) {
|
|
|
|
VisitExpr(E);
|
|
|
|
Record.push_back(E->getValue());
|
|
|
|
Writer.AddSourceLocation(E->getLoc(), Record);
|
|
|
|
Record.push_back(E->isWide());
|
|
|
|
Code = pch::EXPR_CHARACTER_LITERAL;
|
|
|
|
}
|
|
|
|
|
2009-04-15 07:59:37 +08:00
|
|
|
void PCHStmtWriter::VisitParenExpr(ParenExpr *E) {
|
|
|
|
VisitExpr(E);
|
|
|
|
Writer.AddSourceLocation(E->getLParen(), Record);
|
|
|
|
Writer.AddSourceLocation(E->getRParen(), Record);
|
2009-04-17 06:23:12 +08:00
|
|
|
Writer.WriteSubStmt(E->getSubExpr());
|
2009-04-15 07:59:37 +08:00
|
|
|
Code = pch::EXPR_PAREN;
|
|
|
|
}
|
|
|
|
|
2009-04-15 23:58:59 +08:00
|
|
|
void PCHStmtWriter::VisitUnaryOperator(UnaryOperator *E) {
|
|
|
|
VisitExpr(E);
|
2009-04-17 06:23:12 +08:00
|
|
|
Writer.WriteSubStmt(E->getSubExpr());
|
2009-04-15 23:58:59 +08:00
|
|
|
Record.push_back(E->getOpcode()); // FIXME: stable encoding
|
|
|
|
Writer.AddSourceLocation(E->getOperatorLoc(), Record);
|
|
|
|
Code = pch::EXPR_UNARY_OPERATOR;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PCHStmtWriter::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) {
|
|
|
|
VisitExpr(E);
|
|
|
|
Record.push_back(E->isSizeOf());
|
|
|
|
if (E->isArgumentType())
|
|
|
|
Writer.AddTypeRef(E->getArgumentType(), Record);
|
|
|
|
else {
|
|
|
|
Record.push_back(0);
|
2009-04-17 06:23:12 +08:00
|
|
|
Writer.WriteSubStmt(E->getArgumentExpr());
|
2009-04-15 23:58:59 +08:00
|
|
|
}
|
|
|
|
Writer.AddSourceLocation(E->getOperatorLoc(), Record);
|
|
|
|
Writer.AddSourceLocation(E->getRParenLoc(), Record);
|
|
|
|
Code = pch::EXPR_SIZEOF_ALIGN_OF;
|
|
|
|
}
|
|
|
|
|
2009-04-16 06:19:53 +08:00
|
|
|
void PCHStmtWriter::VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
|
|
|
|
VisitExpr(E);
|
2009-04-17 06:23:12 +08:00
|
|
|
Writer.WriteSubStmt(E->getLHS());
|
|
|
|
Writer.WriteSubStmt(E->getRHS());
|
2009-04-16 06:19:53 +08:00
|
|
|
Writer.AddSourceLocation(E->getRBracketLoc(), Record);
|
|
|
|
Code = pch::EXPR_ARRAY_SUBSCRIPT;
|
|
|
|
}
|
|
|
|
|
2009-04-16 01:43:59 +08:00
|
|
|
void PCHStmtWriter::VisitCallExpr(CallExpr *E) {
|
|
|
|
VisitExpr(E);
|
|
|
|
Record.push_back(E->getNumArgs());
|
|
|
|
Writer.AddSourceLocation(E->getRParenLoc(), Record);
|
2009-04-17 06:23:12 +08:00
|
|
|
Writer.WriteSubStmt(E->getCallee());
|
2009-04-16 01:43:59 +08:00
|
|
|
for (CallExpr::arg_iterator Arg = E->arg_begin(), ArgEnd = E->arg_end();
|
|
|
|
Arg != ArgEnd; ++Arg)
|
2009-04-17 06:23:12 +08:00
|
|
|
Writer.WriteSubStmt(*Arg);
|
2009-04-16 01:43:59 +08:00
|
|
|
Code = pch::EXPR_CALL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PCHStmtWriter::VisitMemberExpr(MemberExpr *E) {
|
|
|
|
VisitExpr(E);
|
2009-04-17 06:23:12 +08:00
|
|
|
Writer.WriteSubStmt(E->getBase());
|
2009-04-16 01:43:59 +08:00
|
|
|
Writer.AddDeclRef(E->getMemberDecl(), Record);
|
|
|
|
Writer.AddSourceLocation(E->getMemberLoc(), Record);
|
|
|
|
Record.push_back(E->isArrow());
|
|
|
|
Code = pch::EXPR_MEMBER;
|
|
|
|
}
|
|
|
|
|
2009-04-15 07:32:43 +08:00
|
|
|
void PCHStmtWriter::VisitCastExpr(CastExpr *E) {
|
|
|
|
VisitExpr(E);
|
2009-04-17 06:23:12 +08:00
|
|
|
Writer.WriteSubStmt(E->getSubExpr());
|
2009-04-15 07:32:43 +08:00
|
|
|
}
|
|
|
|
|
2009-04-15 08:25:59 +08:00
|
|
|
void PCHStmtWriter::VisitBinaryOperator(BinaryOperator *E) {
|
|
|
|
VisitExpr(E);
|
2009-04-17 06:23:12 +08:00
|
|
|
Writer.WriteSubStmt(E->getLHS());
|
|
|
|
Writer.WriteSubStmt(E->getRHS());
|
2009-04-15 08:25:59 +08:00
|
|
|
Record.push_back(E->getOpcode()); // FIXME: stable encoding
|
|
|
|
Writer.AddSourceLocation(E->getOperatorLoc(), Record);
|
|
|
|
Code = pch::EXPR_BINARY_OPERATOR;
|
|
|
|
}
|
|
|
|
|
2009-04-16 06:40:36 +08:00
|
|
|
void PCHStmtWriter::VisitCompoundAssignOperator(CompoundAssignOperator *E) {
|
|
|
|
VisitBinaryOperator(E);
|
|
|
|
Writer.AddTypeRef(E->getComputationLHSType(), Record);
|
|
|
|
Writer.AddTypeRef(E->getComputationResultType(), Record);
|
|
|
|
Code = pch::EXPR_COMPOUND_ASSIGN_OPERATOR;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PCHStmtWriter::VisitConditionalOperator(ConditionalOperator *E) {
|
|
|
|
VisitExpr(E);
|
2009-04-17 06:23:12 +08:00
|
|
|
Writer.WriteSubStmt(E->getCond());
|
|
|
|
Writer.WriteSubStmt(E->getLHS());
|
|
|
|
Writer.WriteSubStmt(E->getRHS());
|
2009-04-16 06:40:36 +08:00
|
|
|
Code = pch::EXPR_CONDITIONAL_OPERATOR;
|
|
|
|
}
|
|
|
|
|
2009-04-15 07:32:43 +08:00
|
|
|
void PCHStmtWriter::VisitImplicitCastExpr(ImplicitCastExpr *E) {
|
|
|
|
VisitCastExpr(E);
|
|
|
|
Record.push_back(E->isLvalueCast());
|
|
|
|
Code = pch::EXPR_IMPLICIT_CAST;
|
|
|
|
}
|
|
|
|
|
2009-04-15 08:25:59 +08:00
|
|
|
void PCHStmtWriter::VisitExplicitCastExpr(ExplicitCastExpr *E) {
|
|
|
|
VisitCastExpr(E);
|
|
|
|
Writer.AddTypeRef(E->getTypeAsWritten(), Record);
|
|
|
|
}
|
|
|
|
|
|
|
|
void PCHStmtWriter::VisitCStyleCastExpr(CStyleCastExpr *E) {
|
|
|
|
VisitExplicitCastExpr(E);
|
|
|
|
Writer.AddSourceLocation(E->getLParenLoc(), Record);
|
|
|
|
Writer.AddSourceLocation(E->getRParenLoc(), Record);
|
|
|
|
Code = pch::EXPR_CSTYLE_CAST;
|
|
|
|
}
|
|
|
|
|
2009-04-16 10:33:48 +08:00
|
|
|
void PCHStmtWriter::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) {
|
|
|
|
VisitExpr(E);
|
|
|
|
Writer.AddSourceLocation(E->getLParenLoc(), Record);
|
2009-04-17 06:23:12 +08:00
|
|
|
Writer.WriteSubStmt(E->getInitializer());
|
2009-04-16 10:33:48 +08:00
|
|
|
Record.push_back(E->isFileScope());
|
|
|
|
Code = pch::EXPR_COMPOUND_LITERAL;
|
|
|
|
}
|
|
|
|
|
2009-04-16 07:02:49 +08:00
|
|
|
void PCHStmtWriter::VisitExtVectorElementExpr(ExtVectorElementExpr *E) {
|
|
|
|
VisitExpr(E);
|
2009-04-17 06:23:12 +08:00
|
|
|
Writer.WriteSubStmt(E->getBase());
|
2009-04-16 07:02:49 +08:00
|
|
|
Writer.AddIdentifierRef(&E->getAccessor(), Record);
|
|
|
|
Writer.AddSourceLocation(E->getAccessorLoc(), Record);
|
|
|
|
Code = pch::EXPR_EXT_VECTOR_ELEMENT;
|
|
|
|
}
|
|
|
|
|
2009-04-16 08:55:48 +08:00
|
|
|
void PCHStmtWriter::VisitInitListExpr(InitListExpr *E) {
|
|
|
|
VisitExpr(E);
|
|
|
|
Record.push_back(E->getNumInits());
|
|
|
|
for (unsigned I = 0, N = E->getNumInits(); I != N; ++I)
|
2009-04-17 06:23:12 +08:00
|
|
|
Writer.WriteSubStmt(E->getInit(I));
|
|
|
|
Writer.WriteSubStmt(E->getSyntacticForm());
|
2009-04-16 08:55:48 +08:00
|
|
|
Writer.AddSourceLocation(E->getLBraceLoc(), Record);
|
|
|
|
Writer.AddSourceLocation(E->getRBraceLoc(), Record);
|
|
|
|
Writer.AddDeclRef(E->getInitializedFieldInUnion(), Record);
|
|
|
|
Record.push_back(E->hadArrayRangeDesignator());
|
|
|
|
Code = pch::EXPR_INIT_LIST;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PCHStmtWriter::VisitDesignatedInitExpr(DesignatedInitExpr *E) {
|
|
|
|
VisitExpr(E);
|
|
|
|
Record.push_back(E->getNumSubExprs());
|
|
|
|
for (unsigned I = 0, N = E->getNumSubExprs(); I != N; ++I)
|
2009-04-17 06:23:12 +08:00
|
|
|
Writer.WriteSubStmt(E->getSubExpr(I));
|
2009-04-16 08:55:48 +08:00
|
|
|
Writer.AddSourceLocation(E->getEqualOrColonLoc(), Record);
|
|
|
|
Record.push_back(E->usesGNUSyntax());
|
|
|
|
for (DesignatedInitExpr::designators_iterator D = E->designators_begin(),
|
|
|
|
DEnd = E->designators_end();
|
|
|
|
D != DEnd; ++D) {
|
|
|
|
if (D->isFieldDesignator()) {
|
|
|
|
if (FieldDecl *Field = D->getField()) {
|
|
|
|
Record.push_back(pch::DESIG_FIELD_DECL);
|
|
|
|
Writer.AddDeclRef(Field, Record);
|
|
|
|
} else {
|
|
|
|
Record.push_back(pch::DESIG_FIELD_NAME);
|
|
|
|
Writer.AddIdentifierRef(D->getFieldName(), Record);
|
|
|
|
}
|
|
|
|
Writer.AddSourceLocation(D->getDotLoc(), Record);
|
|
|
|
Writer.AddSourceLocation(D->getFieldLoc(), Record);
|
|
|
|
} else if (D->isArrayDesignator()) {
|
|
|
|
Record.push_back(pch::DESIG_ARRAY);
|
|
|
|
Record.push_back(D->getFirstExprIndex());
|
|
|
|
Writer.AddSourceLocation(D->getLBracketLoc(), Record);
|
|
|
|
Writer.AddSourceLocation(D->getRBracketLoc(), Record);
|
|
|
|
} else {
|
|
|
|
assert(D->isArrayRangeDesignator() && "Unknown designator");
|
|
|
|
Record.push_back(pch::DESIG_ARRAY_RANGE);
|
|
|
|
Record.push_back(D->getFirstExprIndex());
|
|
|
|
Writer.AddSourceLocation(D->getLBracketLoc(), Record);
|
|
|
|
Writer.AddSourceLocation(D->getEllipsisLoc(), Record);
|
|
|
|
Writer.AddSourceLocation(D->getRBracketLoc(), Record);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Code = pch::EXPR_DESIGNATED_INIT;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PCHStmtWriter::VisitImplicitValueInitExpr(ImplicitValueInitExpr *E) {
|
|
|
|
VisitExpr(E);
|
|
|
|
Code = pch::EXPR_IMPLICIT_VALUE_INIT;
|
|
|
|
}
|
|
|
|
|
2009-04-16 07:02:49 +08:00
|
|
|
void PCHStmtWriter::VisitVAArgExpr(VAArgExpr *E) {
|
|
|
|
VisitExpr(E);
|
2009-04-17 06:23:12 +08:00
|
|
|
Writer.WriteSubStmt(E->getSubExpr());
|
2009-04-16 07:02:49 +08:00
|
|
|
Writer.AddSourceLocation(E->getBuiltinLoc(), Record);
|
|
|
|
Writer.AddSourceLocation(E->getRParenLoc(), Record);
|
|
|
|
Code = pch::EXPR_VA_ARG;
|
|
|
|
}
|
|
|
|
|
2009-04-18 02:58:21 +08:00
|
|
|
void PCHStmtWriter::VisitAddrLabelExpr(AddrLabelExpr *E) {
|
|
|
|
VisitExpr(E);
|
|
|
|
Writer.AddSourceLocation(E->getAmpAmpLoc(), Record);
|
|
|
|
Writer.AddSourceLocation(E->getLabelLoc(), Record);
|
|
|
|
Record.push_back(Writer.GetLabelID(E->getLabel()));
|
|
|
|
Code = pch::EXPR_ADDR_LABEL;
|
|
|
|
}
|
|
|
|
|
2009-04-18 03:05:30 +08:00
|
|
|
void PCHStmtWriter::VisitStmtExpr(StmtExpr *E) {
|
|
|
|
VisitExpr(E);
|
|
|
|
Writer.WriteSubStmt(E->getSubStmt());
|
|
|
|
Writer.AddSourceLocation(E->getLParenLoc(), Record);
|
|
|
|
Writer.AddSourceLocation(E->getRParenLoc(), Record);
|
|
|
|
Code = pch::EXPR_STMT;
|
|
|
|
}
|
|
|
|
|
2009-04-16 07:33:31 +08:00
|
|
|
void PCHStmtWriter::VisitTypesCompatibleExpr(TypesCompatibleExpr *E) {
|
|
|
|
VisitExpr(E);
|
|
|
|
Writer.AddTypeRef(E->getArgType1(), Record);
|
|
|
|
Writer.AddTypeRef(E->getArgType2(), Record);
|
|
|
|
Writer.AddSourceLocation(E->getBuiltinLoc(), Record);
|
|
|
|
Writer.AddSourceLocation(E->getRParenLoc(), Record);
|
|
|
|
Code = pch::EXPR_TYPES_COMPATIBLE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PCHStmtWriter::VisitChooseExpr(ChooseExpr *E) {
|
|
|
|
VisitExpr(E);
|
2009-04-17 06:23:12 +08:00
|
|
|
Writer.WriteSubStmt(E->getCond());
|
|
|
|
Writer.WriteSubStmt(E->getLHS());
|
|
|
|
Writer.WriteSubStmt(E->getRHS());
|
2009-04-16 07:33:31 +08:00
|
|
|
Writer.AddSourceLocation(E->getBuiltinLoc(), Record);
|
|
|
|
Writer.AddSourceLocation(E->getRParenLoc(), Record);
|
|
|
|
Code = pch::EXPR_CHOOSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PCHStmtWriter::VisitGNUNullExpr(GNUNullExpr *E) {
|
|
|
|
VisitExpr(E);
|
|
|
|
Writer.AddSourceLocation(E->getTokenLocation(), Record);
|
|
|
|
Code = pch::EXPR_GNU_NULL;
|
|
|
|
}
|
|
|
|
|
2009-04-16 08:01:45 +08:00
|
|
|
void PCHStmtWriter::VisitShuffleVectorExpr(ShuffleVectorExpr *E) {
|
|
|
|
VisitExpr(E);
|
|
|
|
Record.push_back(E->getNumSubExprs());
|
|
|
|
for (unsigned I = 0, N = E->getNumSubExprs(); I != N; ++I)
|
2009-04-17 06:23:12 +08:00
|
|
|
Writer.WriteSubStmt(E->getExpr(I));
|
2009-04-16 08:01:45 +08:00
|
|
|
Writer.AddSourceLocation(E->getBuiltinLoc(), Record);
|
|
|
|
Writer.AddSourceLocation(E->getRParenLoc(), Record);
|
|
|
|
Code = pch::EXPR_SHUFFLE_VECTOR;
|
|
|
|
}
|
|
|
|
|
2009-04-18 03:21:43 +08:00
|
|
|
void PCHStmtWriter::VisitBlockExpr(BlockExpr *E) {
|
|
|
|
VisitExpr(E);
|
|
|
|
Writer.AddDeclRef(E->getBlockDecl(), Record);
|
|
|
|
Record.push_back(E->hasBlockDeclRefExprs());
|
|
|
|
Code = pch::EXPR_BLOCK;
|
|
|
|
}
|
|
|
|
|
2009-04-16 08:01:45 +08:00
|
|
|
void PCHStmtWriter::VisitBlockDeclRefExpr(BlockDeclRefExpr *E) {
|
|
|
|
VisitExpr(E);
|
|
|
|
Writer.AddDeclRef(E->getDecl(), Record);
|
|
|
|
Writer.AddSourceLocation(E->getLocation(), Record);
|
|
|
|
Record.push_back(E->isByRef());
|
|
|
|
Code = pch::EXPR_BLOCK_DECL_REF;
|
|
|
|
}
|
|
|
|
|
2009-04-22 13:57:30 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Objective-C Expressions and Statements.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2009-04-22 14:29:42 +08:00
|
|
|
void PCHStmtWriter::VisitObjCStringLiteral(ObjCStringLiteral *E) {
|
|
|
|
VisitExpr(E);
|
|
|
|
Writer.WriteSubStmt(E->getString());
|
|
|
|
Writer.AddSourceLocation(E->getAtLoc(), Record);
|
|
|
|
Code = pch::EXPR_OBJC_STRING_LITERAL;
|
|
|
|
}
|
|
|
|
|
2009-04-22 13:57:30 +08:00
|
|
|
void PCHStmtWriter::VisitObjCEncodeExpr(ObjCEncodeExpr *E) {
|
|
|
|
VisitExpr(E);
|
|
|
|
Writer.AddTypeRef(E->getEncodedType(), Record);
|
|
|
|
Writer.AddSourceLocation(E->getAtLoc(), Record);
|
|
|
|
Writer.AddSourceLocation(E->getRParenLoc(), Record);
|
|
|
|
Code = pch::EXPR_OBJC_ENCODE;
|
|
|
|
}
|
|
|
|
|
2009-04-22 14:29:42 +08:00
|
|
|
void PCHStmtWriter::VisitObjCSelectorExpr(ObjCSelectorExpr *E) {
|
|
|
|
VisitExpr(E);
|
2009-04-23 18:39:46 +08:00
|
|
|
Writer.AddSelectorRef(E->getSelector(), Record);
|
2009-04-22 14:29:42 +08:00
|
|
|
Writer.AddSourceLocation(E->getAtLoc(), Record);
|
|
|
|
Writer.AddSourceLocation(E->getRParenLoc(), Record);
|
|
|
|
Code = pch::EXPR_OBJC_SELECTOR_EXPR;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PCHStmtWriter::VisitObjCProtocolExpr(ObjCProtocolExpr *E) {
|
|
|
|
VisitExpr(E);
|
|
|
|
Writer.AddDeclRef(E->getProtocol(), Record);
|
|
|
|
Writer.AddSourceLocation(E->getAtLoc(), Record);
|
|
|
|
Writer.AddSourceLocation(E->getRParenLoc(), Record);
|
|
|
|
Code = pch::EXPR_OBJC_PROTOCOL_EXPR;
|
|
|
|
}
|
|
|
|
|
2009-04-26 08:44:05 +08:00
|
|
|
void PCHStmtWriter::VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) {
|
|
|
|
VisitExpr(E);
|
|
|
|
Writer.AddDeclRef(E->getDecl(), Record);
|
|
|
|
Writer.AddSourceLocation(E->getLocation(), Record);
|
|
|
|
Writer.WriteSubStmt(E->getBase());
|
|
|
|
Record.push_back(E->isArrow());
|
|
|
|
Record.push_back(E->isFreeIvar());
|
2009-04-26 22:11:39 +08:00
|
|
|
Code = pch::EXPR_OBJC_IVAR_REF_EXPR;
|
2009-04-26 08:44:05 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void PCHStmtWriter::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E) {
|
|
|
|
VisitExpr(E);
|
|
|
|
Writer.AddDeclRef(E->getProperty(), Record);
|
|
|
|
Writer.AddSourceLocation(E->getLocation(), Record);
|
|
|
|
Writer.WriteSubStmt(E->getBase());
|
2009-04-26 22:11:39 +08:00
|
|
|
Code = pch::EXPR_OBJC_PROPERTY_REF_EXPR;
|
2009-04-26 08:44:05 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void PCHStmtWriter::VisitObjCKVCRefExpr(ObjCKVCRefExpr *E) {
|
|
|
|
VisitExpr(E);
|
|
|
|
Writer.AddDeclRef(E->getGetterMethod(), Record);
|
|
|
|
Writer.AddDeclRef(E->getSetterMethod(), Record);
|
|
|
|
|
|
|
|
// NOTE: ClassProp and Base are mutually exclusive.
|
|
|
|
Writer.AddDeclRef(E->getClassProp(), Record);
|
|
|
|
Writer.WriteSubStmt(E->getBase());
|
|
|
|
Writer.AddSourceLocation(E->getLocation(), Record);
|
|
|
|
Writer.AddSourceLocation(E->getClassLoc(), Record);
|
2009-04-26 22:11:39 +08:00
|
|
|
Code = pch::EXPR_OBJC_KVC_REF_EXPR;
|
2009-04-26 08:44:05 +08:00
|
|
|
}
|
|
|
|
|
2009-04-25 22:04:28 +08:00
|
|
|
void PCHStmtWriter::VisitObjCMessageExpr(ObjCMessageExpr *E) {
|
|
|
|
VisitExpr(E);
|
|
|
|
Record.push_back(E->getNumArgs());
|
2009-04-26 08:44:05 +08:00
|
|
|
Writer.AddSourceLocation(E->getLeftLoc(), Record);
|
|
|
|
Writer.AddSourceLocation(E->getRightLoc(), Record);
|
2009-04-25 22:04:28 +08:00
|
|
|
Writer.AddSelectorRef(E->getSelector(), Record);
|
|
|
|
Writer.AddDeclRef(E->getMethodDecl(), Record); // optional
|
2009-04-26 08:44:05 +08:00
|
|
|
|
|
|
|
ObjCMessageExpr::ClassInfo CI = E->getClassInfo();
|
2009-04-25 22:04:28 +08:00
|
|
|
Writer.WriteSubStmt(E->getReceiver());
|
2009-04-26 08:44:05 +08:00
|
|
|
Writer.AddDeclRef(CI.first, Record);
|
|
|
|
Writer.AddIdentifierRef(CI.second, Record);
|
|
|
|
|
2009-04-25 22:04:28 +08:00
|
|
|
for (CallExpr::arg_iterator Arg = E->arg_begin(), ArgEnd = E->arg_end();
|
|
|
|
Arg != ArgEnd; ++Arg)
|
|
|
|
Writer.WriteSubStmt(*Arg);
|
|
|
|
Code = pch::EXPR_OBJC_MESSAGE_EXPR;
|
|
|
|
}
|
|
|
|
|
2009-04-26 08:44:05 +08:00
|
|
|
void PCHStmtWriter::VisitObjCSuperExpr(ObjCSuperExpr *E) {
|
|
|
|
VisitExpr(E);
|
|
|
|
Writer.AddSourceLocation(E->getLoc(), Record);
|
2009-04-26 22:11:39 +08:00
|
|
|
Code = pch::EXPR_OBJC_SUPER_EXPR;
|
2009-04-26 08:44:05 +08:00
|
|
|
}
|
|
|
|
|
2009-04-27 02:52:16 +08:00
|
|
|
void PCHStmtWriter::VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) {
|
|
|
|
VisitStmt(S);
|
|
|
|
Writer.WriteSubStmt(S->getElement());
|
|
|
|
Writer.WriteSubStmt(S->getCollection());
|
|
|
|
Writer.WriteSubStmt(S->getBody());
|
|
|
|
Writer.AddSourceLocation(S->getForLoc(), Record);
|
|
|
|
Writer.AddSourceLocation(S->getRParenLoc(), Record);
|
|
|
|
Code = pch::STMT_OBJC_FOR_COLLECTION;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PCHStmtWriter::VisitObjCCatchStmt(ObjCAtCatchStmt *S) {
|
|
|
|
Writer.WriteSubStmt(S->getCatchBody());
|
|
|
|
Writer.WriteSubStmt(S->getNextCatchStmt());
|
|
|
|
Writer.AddDeclRef(S->getCatchParamDecl(), Record);
|
|
|
|
Writer.AddSourceLocation(S->getAtCatchLoc(), Record);
|
|
|
|
Writer.AddSourceLocation(S->getRParenLoc(), Record);
|
|
|
|
Code = pch::STMT_OBJC_CATCH;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PCHStmtWriter::VisitObjCFinallyStmt(ObjCAtFinallyStmt *S) {
|
|
|
|
Writer.WriteSubStmt(S->getFinallyBody());
|
|
|
|
Writer.AddSourceLocation(S->getAtFinallyLoc(), Record);
|
|
|
|
Code = pch::STMT_OBJC_FINALLY;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PCHStmtWriter::VisitObjCAtTryStmt(ObjCAtTryStmt *S) {
|
|
|
|
Writer.WriteSubStmt(S->getTryBody());
|
|
|
|
Writer.WriteSubStmt(S->getCatchStmts());
|
|
|
|
Writer.WriteSubStmt(S->getFinallyStmt());
|
|
|
|
Writer.AddSourceLocation(S->getAtTryLoc(), Record);
|
|
|
|
Code = pch::STMT_OBJC_AT_TRY;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PCHStmtWriter::VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *S) {
|
|
|
|
Writer.WriteSubStmt(S->getSynchExpr());
|
|
|
|
Writer.WriteSubStmt(S->getSynchBody());
|
|
|
|
Writer.AddSourceLocation(S->getAtSynchronizedLoc(), Record);
|
|
|
|
Code = pch::STMT_OBJC_AT_SYNCHRONIZED;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PCHStmtWriter::VisitObjCAtThrowStmt(ObjCAtThrowStmt *S) {
|
|
|
|
Writer.WriteSubStmt(S->getThrowExpr());
|
|
|
|
Writer.AddSourceLocation(S->getThrowLoc(), Record);
|
|
|
|
Code = pch::STMT_OBJC_AT_THROW;
|
|
|
|
}
|
2009-04-22 13:57:30 +08:00
|
|
|
|
2009-04-10 06:27:44 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// PCHWriter Implementation
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2009-04-11 05:16:55 +08:00
|
|
|
/// \brief Write the target triple (e.g., i686-apple-darwin9).
|
|
|
|
void PCHWriter::WriteTargetTriple(const TargetInfo &Target) {
|
|
|
|
using namespace llvm;
|
|
|
|
BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(pch::TARGET_TRIPLE));
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Triple name
|
2009-04-17 06:23:12 +08:00
|
|
|
unsigned TripleAbbrev = Stream.EmitAbbrev(Abbrev);
|
2009-04-11 05:16:55 +08:00
|
|
|
|
|
|
|
RecordData Record;
|
|
|
|
Record.push_back(pch::TARGET_TRIPLE);
|
|
|
|
const char *Triple = Target.getTargetTriple();
|
2009-04-17 06:23:12 +08:00
|
|
|
Stream.EmitRecordWithBlob(TripleAbbrev, Record, Triple, strlen(Triple));
|
2009-04-11 05:16:55 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Write the LangOptions structure.
|
2009-04-11 04:39:37 +08:00
|
|
|
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.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.NoExtensions); // All extensions are disabled, strict mode.
|
|
|
|
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.PascalStrings); // Allow Pascal strings
|
|
|
|
Record.push_back(LangOpts.Boolean); // Allow bool/true/false
|
|
|
|
Record.push_back(LangOpts.WritableStrings); // Allow writable strings
|
|
|
|
Record.push_back(LangOpts.LaxVectorConversions);
|
|
|
|
Record.push_back(LangOpts.Exceptions); // Support exception handling.
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
|
|
|
Record.push_back(LangOpts.ThreadsafeStatics); // Whether static initializers are protected
|
|
|
|
// by locks.
|
|
|
|
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.OverflowChecking); // Extension to call a handler function when
|
|
|
|
// signed integer arithmetic overflows.
|
|
|
|
|
|
|
|
Record.push_back(LangOpts.HeinousExtensions); // Extensions that we really don't like and
|
|
|
|
// may be ripped out at any time.
|
|
|
|
|
|
|
|
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.getGCMode());
|
|
|
|
Record.push_back(LangOpts.getVisibilityMode());
|
|
|
|
Record.push_back(LangOpts.InstantiationDepth);
|
2009-04-17 06:23:12 +08:00
|
|
|
Stream.EmitRecord(pch::LANGUAGE_OPTIONS, Record);
|
2009-04-11 04:39:37 +08:00
|
|
|
}
|
|
|
|
|
2009-04-10 11:52:48 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Source Manager Serialization
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
/// \brief Create an abbreviation for the SLocEntry that refers to a
|
|
|
|
/// file.
|
2009-04-17 06:23:12 +08:00
|
|
|
static unsigned CreateSLocFileAbbrev(llvm::BitstreamWriter &Stream) {
|
2009-04-10 11:52:48 +08:00
|
|
|
using namespace llvm;
|
|
|
|
BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(pch::SM_SLOC_FILE_ENTRY));
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Offset
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Include location
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // Characteristic
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Line directives
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name
|
2009-04-17 06:23:12 +08:00
|
|
|
return Stream.EmitAbbrev(Abbrev);
|
2009-04-10 11:52:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Create an abbreviation for the SLocEntry that refers to a
|
|
|
|
/// buffer.
|
2009-04-17 06:23:12 +08:00
|
|
|
static unsigned CreateSLocBufferAbbrev(llvm::BitstreamWriter &Stream) {
|
2009-04-10 11:52:48 +08:00
|
|
|
using namespace llvm;
|
|
|
|
BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(pch::SM_SLOC_BUFFER_ENTRY));
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Offset
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Include location
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // Characteristic
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Line directives
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Buffer name blob
|
2009-04-17 06:23:12 +08:00
|
|
|
return Stream.EmitAbbrev(Abbrev);
|
2009-04-10 11:52:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Create an abbreviation for the SLocEntry that refers to a
|
|
|
|
/// buffer's blob.
|
2009-04-17 06:23:12 +08:00
|
|
|
static unsigned CreateSLocBufferBlobAbbrev(llvm::BitstreamWriter &Stream) {
|
2009-04-10 11:52:48 +08:00
|
|
|
using namespace llvm;
|
|
|
|
BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(pch::SM_SLOC_BUFFER_BLOB));
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Blob
|
2009-04-17 06:23:12 +08:00
|
|
|
return Stream.EmitAbbrev(Abbrev);
|
2009-04-10 11:52:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Create an abbreviation for the SLocEntry that refers to an
|
|
|
|
/// buffer.
|
2009-04-17 06:23:12 +08:00
|
|
|
static unsigned CreateSLocInstantiationAbbrev(llvm::BitstreamWriter &Stream) {
|
2009-04-10 11:52:48 +08:00
|
|
|
using namespace llvm;
|
|
|
|
BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(pch::SM_SLOC_INSTANTIATION_ENTRY));
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Offset
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Spelling location
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Start location
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // End location
|
2009-04-16 02:05:10 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Token length
|
2009-04-17 06:23:12 +08:00
|
|
|
return Stream.EmitAbbrev(Abbrev);
|
2009-04-10 11:52:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Writes the block containing the serialized form of the
|
|
|
|
/// source manager.
|
|
|
|
///
|
|
|
|
/// TODO: We should probably use an on-disk hash table (stored in a
|
|
|
|
/// blob), indexed based on the file name, so that we only create
|
|
|
|
/// entries for files that we actually need. In the common case (no
|
|
|
|
/// errors), we probably won't have to create file entries for any of
|
|
|
|
/// the files in the AST.
|
2009-04-26 08:07:37 +08:00
|
|
|
void PCHWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
|
|
|
|
const Preprocessor &PP) {
|
2009-04-11 01:16:57 +08:00
|
|
|
// Enter the source manager block.
|
2009-04-17 06:23:12 +08:00
|
|
|
Stream.EnterSubblock(pch::SOURCE_MANAGER_BLOCK_ID, 3);
|
2009-04-10 11:52:48 +08:00
|
|
|
|
|
|
|
// Abbreviations for the various kinds of source-location entries.
|
|
|
|
int SLocFileAbbrv = -1;
|
|
|
|
int SLocBufferAbbrv = -1;
|
|
|
|
int SLocBufferBlobAbbrv = -1;
|
|
|
|
int SLocInstantiationAbbrv = -1;
|
|
|
|
|
|
|
|
// Write out the source location entry table. We skip the first
|
|
|
|
// entry, which is always the same dummy entry.
|
|
|
|
RecordData Record;
|
|
|
|
for (SourceManager::sloc_entry_iterator
|
|
|
|
SLoc = SourceMgr.sloc_entry_begin() + 1,
|
|
|
|
SLocEnd = SourceMgr.sloc_entry_end();
|
|
|
|
SLoc != SLocEnd; ++SLoc) {
|
|
|
|
// Figure out which record code to use.
|
|
|
|
unsigned Code;
|
|
|
|
if (SLoc->isFile()) {
|
|
|
|
if (SLoc->getFile().getContentCache()->Entry)
|
|
|
|
Code = pch::SM_SLOC_FILE_ENTRY;
|
|
|
|
else
|
|
|
|
Code = pch::SM_SLOC_BUFFER_ENTRY;
|
|
|
|
} else
|
|
|
|
Code = pch::SM_SLOC_INSTANTIATION_ENTRY;
|
|
|
|
Record.push_back(Code);
|
|
|
|
|
|
|
|
Record.push_back(SLoc->getOffset());
|
|
|
|
if (SLoc->isFile()) {
|
|
|
|
const SrcMgr::FileInfo &File = SLoc->getFile();
|
|
|
|
Record.push_back(File.getIncludeLoc().getRawEncoding());
|
|
|
|
Record.push_back(File.getFileCharacteristic()); // FIXME: stable encoding
|
2009-04-14 00:31:14 +08:00
|
|
|
Record.push_back(File.hasLineDirectives());
|
2009-04-10 11:52:48 +08:00
|
|
|
|
|
|
|
const SrcMgr::ContentCache *Content = File.getContentCache();
|
|
|
|
if (Content->Entry) {
|
|
|
|
// The source location entry is a file. The blob associated
|
|
|
|
// with this entry is the file name.
|
|
|
|
if (SLocFileAbbrv == -1)
|
2009-04-17 06:23:12 +08:00
|
|
|
SLocFileAbbrv = CreateSLocFileAbbrev(Stream);
|
|
|
|
Stream.EmitRecordWithBlob(SLocFileAbbrv, Record,
|
2009-04-10 11:52:48 +08:00
|
|
|
Content->Entry->getName(),
|
|
|
|
strlen(Content->Entry->getName()));
|
|
|
|
} else {
|
|
|
|
// The source location entry is a buffer. The blob associated
|
|
|
|
// with this entry contains the contents of the buffer.
|
|
|
|
if (SLocBufferAbbrv == -1) {
|
2009-04-17 06:23:12 +08:00
|
|
|
SLocBufferAbbrv = CreateSLocBufferAbbrev(Stream);
|
|
|
|
SLocBufferBlobAbbrv = CreateSLocBufferBlobAbbrev(Stream);
|
2009-04-10 11:52:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// We add one to the size so that we capture the trailing NULL
|
|
|
|
// that is required by llvm::MemoryBuffer::getMemBuffer (on
|
|
|
|
// the reader side).
|
|
|
|
const llvm::MemoryBuffer *Buffer = Content->getBuffer();
|
|
|
|
const char *Name = Buffer->getBufferIdentifier();
|
2009-04-17 06:23:12 +08:00
|
|
|
Stream.EmitRecordWithBlob(SLocBufferAbbrv, Record, Name, strlen(Name) + 1);
|
2009-04-10 11:52:48 +08:00
|
|
|
Record.clear();
|
|
|
|
Record.push_back(pch::SM_SLOC_BUFFER_BLOB);
|
2009-04-17 06:23:12 +08:00
|
|
|
Stream.EmitRecordWithBlob(SLocBufferBlobAbbrv, Record,
|
2009-04-10 11:52:48 +08:00
|
|
|
Buffer->getBufferStart(),
|
|
|
|
Buffer->getBufferSize() + 1);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// The source location entry is an instantiation.
|
|
|
|
const SrcMgr::InstantiationInfo &Inst = SLoc->getInstantiation();
|
|
|
|
Record.push_back(Inst.getSpellingLoc().getRawEncoding());
|
|
|
|
Record.push_back(Inst.getInstantiationLocStart().getRawEncoding());
|
|
|
|
Record.push_back(Inst.getInstantiationLocEnd().getRawEncoding());
|
|
|
|
|
2009-04-16 02:05:10 +08:00
|
|
|
// Compute the token length for this macro expansion.
|
|
|
|
unsigned NextOffset = SourceMgr.getNextOffset();
|
|
|
|
SourceManager::sloc_entry_iterator NextSLoc = SLoc;
|
|
|
|
if (++NextSLoc != SLocEnd)
|
|
|
|
NextOffset = NextSLoc->getOffset();
|
|
|
|
Record.push_back(NextOffset - SLoc->getOffset() - 1);
|
|
|
|
|
2009-04-10 11:52:48 +08:00
|
|
|
if (SLocInstantiationAbbrv == -1)
|
2009-04-17 06:23:12 +08:00
|
|
|
SLocInstantiationAbbrv = CreateSLocInstantiationAbbrev(Stream);
|
|
|
|
Stream.EmitRecordWithAbbrev(SLocInstantiationAbbrv, Record);
|
2009-04-10 11:52:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
Record.clear();
|
|
|
|
}
|
|
|
|
|
2009-04-14 00:31:14 +08:00
|
|
|
// Write the line table.
|
|
|
|
if (SourceMgr.hasLineTable()) {
|
|
|
|
LineTableInfo &LineTable = SourceMgr.getLineTable();
|
|
|
|
|
|
|
|
// Emit the file names
|
|
|
|
Record.push_back(LineTable.getNumFilenames());
|
|
|
|
for (unsigned I = 0, N = LineTable.getNumFilenames(); I != N; ++I) {
|
|
|
|
// Emit the file name
|
|
|
|
const char *Filename = LineTable.getFilename(I);
|
|
|
|
unsigned FilenameLen = Filename? strlen(Filename) : 0;
|
|
|
|
Record.push_back(FilenameLen);
|
|
|
|
if (FilenameLen)
|
|
|
|
Record.insert(Record.end(), Filename, Filename + FilenameLen);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Emit the line entries
|
|
|
|
for (LineTableInfo::iterator L = LineTable.begin(), LEnd = LineTable.end();
|
|
|
|
L != LEnd; ++L) {
|
|
|
|
// Emit the file ID
|
|
|
|
Record.push_back(L->first);
|
|
|
|
|
|
|
|
// Emit the line entries
|
|
|
|
Record.push_back(L->second.size());
|
|
|
|
for (std::vector<LineEntry>::iterator LE = L->second.begin(),
|
|
|
|
LEEnd = L->second.end();
|
|
|
|
LE != LEEnd; ++LE) {
|
|
|
|
Record.push_back(LE->FileOffset);
|
|
|
|
Record.push_back(LE->LineNo);
|
|
|
|
Record.push_back(LE->FilenameID);
|
|
|
|
Record.push_back((unsigned)LE->FileKind);
|
|
|
|
Record.push_back(LE->IncludeOffset);
|
|
|
|
}
|
2009-04-17 06:23:12 +08:00
|
|
|
Stream.EmitRecord(pch::SM_LINE_TABLE, Record);
|
2009-04-14 00:31:14 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-04-26 08:07:37 +08:00
|
|
|
// Loop over all the header files.
|
|
|
|
HeaderSearch &HS = PP.getHeaderSearchInfo();
|
|
|
|
for (HeaderSearch::header_file_iterator I = HS.header_file_begin(),
|
|
|
|
E = HS.header_file_end();
|
|
|
|
I != E; ++I) {
|
|
|
|
Record.push_back(I->isImport);
|
|
|
|
Record.push_back(I->DirInfo);
|
|
|
|
Record.push_back(I->NumIncludes);
|
|
|
|
if (I->ControllingMacro)
|
|
|
|
AddIdentifierRef(I->ControllingMacro, Record);
|
|
|
|
else
|
|
|
|
Record.push_back(0);
|
|
|
|
Stream.EmitRecord(pch::SM_HEADER_FILE_INFO, Record);
|
|
|
|
Record.clear();
|
|
|
|
}
|
|
|
|
|
2009-04-17 06:23:12 +08:00
|
|
|
Stream.ExitBlock();
|
2009-04-10 11:52:48 +08:00
|
|
|
}
|
|
|
|
|
2009-04-11 01:15:23 +08:00
|
|
|
/// \brief Writes the block containing the serialized form of the
|
|
|
|
/// preprocessor.
|
|
|
|
///
|
2009-04-11 02:08:30 +08:00
|
|
|
void PCHWriter::WritePreprocessor(const Preprocessor &PP) {
|
2009-04-11 02:00:12 +08:00
|
|
|
RecordData Record;
|
|
|
|
|
2009-04-13 09:29:17 +08:00
|
|
|
// If the preprocessor __COUNTER__ value has been bumped, remember it.
|
|
|
|
if (PP.getCounterValue() != 0) {
|
|
|
|
Record.push_back(PP.getCounterValue());
|
2009-04-17 06:23:12 +08:00
|
|
|
Stream.EmitRecord(pch::PP_COUNTER_VALUE, Record);
|
2009-04-13 09:29:17 +08:00
|
|
|
Record.clear();
|
2009-04-26 08:07:37 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Enter the preprocessor block.
|
|
|
|
Stream.EnterSubblock(pch::PREPROCESSOR_BLOCK_ID, 2);
|
2009-04-13 09:29:17 +08:00
|
|
|
|
2009-04-26 08:07:37 +08:00
|
|
|
// If the PCH file contains __DATE__ or __TIME__ emit a warning about this.
|
|
|
|
// FIXME: use diagnostics subsystem for localization etc.
|
|
|
|
if (PP.SawDateOrTime())
|
|
|
|
fprintf(stderr, "warning: precompiled header used __DATE__ or __TIME__.\n");
|
|
|
|
|
2009-04-11 02:00:12 +08:00
|
|
|
// Loop over all the macro definitions that are live at the end of the file,
|
|
|
|
// emitting each to the PP section.
|
|
|
|
for (Preprocessor::macro_iterator I = PP.macro_begin(), E = PP.macro_end();
|
|
|
|
I != E; ++I) {
|
2009-04-11 05:41:48 +08:00
|
|
|
// FIXME: This emits macros in hash table order, we should do it in a stable
|
|
|
|
// order so that output is reproducible.
|
2009-04-11 02:00:12 +08:00
|
|
|
MacroInfo *MI = I->second;
|
|
|
|
|
|
|
|
// Don't emit builtin macros like __LINE__ to the PCH file unless they have
|
|
|
|
// been redefined by the header (in which case they are not isBuiltinMacro).
|
|
|
|
if (MI->isBuiltinMacro())
|
|
|
|
continue;
|
|
|
|
|
2009-04-22 07:56:24 +08:00
|
|
|
// FIXME: Remove this identifier reference?
|
2009-04-12 05:15:38 +08:00
|
|
|
AddIdentifierRef(I->first, Record);
|
2009-04-22 07:56:24 +08:00
|
|
|
MacroOffsets[I->first] = Stream.GetCurrentBitNo();
|
2009-04-11 02:00:12 +08:00
|
|
|
Record.push_back(MI->getDefinitionLoc().getRawEncoding());
|
|
|
|
Record.push_back(MI->isUsed());
|
|
|
|
|
|
|
|
unsigned Code;
|
|
|
|
if (MI->isObjectLike()) {
|
|
|
|
Code = pch::PP_MACRO_OBJECT_LIKE;
|
|
|
|
} else {
|
|
|
|
Code = pch::PP_MACRO_FUNCTION_LIKE;
|
|
|
|
|
|
|
|
Record.push_back(MI->isC99Varargs());
|
|
|
|
Record.push_back(MI->isGNUVarargs());
|
|
|
|
Record.push_back(MI->getNumArgs());
|
|
|
|
for (MacroInfo::arg_iterator I = MI->arg_begin(), E = MI->arg_end();
|
|
|
|
I != E; ++I)
|
2009-04-12 05:15:38 +08:00
|
|
|
AddIdentifierRef(*I, Record);
|
2009-04-11 02:00:12 +08:00
|
|
|
}
|
2009-04-17 06:23:12 +08:00
|
|
|
Stream.EmitRecord(Code, Record);
|
2009-04-11 02:00:12 +08:00
|
|
|
Record.clear();
|
2009-04-11 01:16:57 +08:00
|
|
|
|
2009-04-11 02:08:30 +08:00
|
|
|
// Emit the tokens array.
|
|
|
|
for (unsigned TokNo = 0, e = MI->getNumTokens(); TokNo != e; ++TokNo) {
|
|
|
|
// Note that we know that the preprocessor does not have any annotation
|
|
|
|
// tokens in it because they are created by the parser, and thus can't be
|
|
|
|
// in a macro definition.
|
|
|
|
const Token &Tok = MI->getReplacementToken(TokNo);
|
|
|
|
|
|
|
|
Record.push_back(Tok.getLocation().getRawEncoding());
|
|
|
|
Record.push_back(Tok.getLength());
|
|
|
|
|
|
|
|
// FIXME: When reading literal tokens, reconstruct the literal pointer if
|
|
|
|
// it is needed.
|
2009-04-12 05:15:38 +08:00
|
|
|
AddIdentifierRef(Tok.getIdentifierInfo(), Record);
|
2009-04-11 02:08:30 +08:00
|
|
|
|
|
|
|
// FIXME: Should translate token kind to a stable encoding.
|
|
|
|
Record.push_back(Tok.getKind());
|
|
|
|
// FIXME: Should translate token flags to a stable encoding.
|
|
|
|
Record.push_back(Tok.getFlags());
|
|
|
|
|
2009-04-17 06:23:12 +08:00
|
|
|
Stream.EmitRecord(pch::PP_TOKEN, Record);
|
2009-04-11 02:08:30 +08:00
|
|
|
Record.clear();
|
|
|
|
}
|
2009-04-22 07:56:24 +08:00
|
|
|
++NumMacros;
|
2009-04-11 02:00:12 +08:00
|
|
|
}
|
2009-04-17 06:23:12 +08:00
|
|
|
Stream.ExitBlock();
|
2009-04-11 01:15:23 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-04-10 06:27:44 +08:00
|
|
|
/// \brief Write the representation of a type to the PCH stream.
|
|
|
|
void PCHWriter::WriteType(const Type *T) {
|
2009-04-11 01:25:41 +08:00
|
|
|
pch::TypeID &ID = TypeIDs[T];
|
2009-04-11 01:16:57 +08:00
|
|
|
if (ID == 0) // we haven't seen this type before.
|
2009-04-10 06:27:44 +08:00
|
|
|
ID = NextTypeID++;
|
|
|
|
|
|
|
|
// Record the offset for this type.
|
|
|
|
if (TypeOffsets.size() == ID - pch::NUM_PREDEF_TYPE_IDS)
|
2009-04-17 06:23:12 +08:00
|
|
|
TypeOffsets.push_back(Stream.GetCurrentBitNo());
|
2009-04-10 06:27:44 +08:00
|
|
|
else if (TypeOffsets.size() < ID - pch::NUM_PREDEF_TYPE_IDS) {
|
|
|
|
TypeOffsets.resize(ID + 1 - pch::NUM_PREDEF_TYPE_IDS);
|
2009-04-17 06:23:12 +08:00
|
|
|
TypeOffsets[ID - pch::NUM_PREDEF_TYPE_IDS] = Stream.GetCurrentBitNo();
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
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.
|
2009-04-17 06:23:12 +08:00
|
|
|
Stream.EmitRecord(W.Code, Record);
|
2009-04-15 05:18:50 +08:00
|
|
|
|
|
|
|
// Flush any expressions that were written as part of this type.
|
2009-04-17 06:23:12 +08:00
|
|
|
FlushStmts();
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Write a block containing all of the types.
|
|
|
|
void PCHWriter::WriteTypesBlock(ASTContext &Context) {
|
2009-04-11 01:16:57 +08:00
|
|
|
// Enter the types block.
|
2009-04-17 06:23:12 +08:00
|
|
|
Stream.EnterSubblock(pch::TYPES_BLOCK_ID, 2);
|
2009-04-10 06:27:44 +08:00
|
|
|
|
2009-04-26 11:49:13 +08:00
|
|
|
// Emit all of the types that need to be emitted (so far).
|
|
|
|
while (!TypesToEmit.empty()) {
|
|
|
|
const Type *T = TypesToEmit.front();
|
|
|
|
TypesToEmit.pop();
|
|
|
|
assert(!isa<BuiltinType>(T) && "Built-in types are not serialized");
|
|
|
|
WriteType(T);
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Exit the types block
|
2009-04-17 06:23:12 +08:00
|
|
|
Stream.ExitBlock();
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// \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) {
|
2009-04-11 01:25:41 +08:00
|
|
|
if (DC->decls_empty(Context))
|
2009-04-10 06:27:44 +08:00
|
|
|
return 0;
|
|
|
|
|
2009-04-17 06:23:12 +08:00
|
|
|
uint64_t Offset = Stream.GetCurrentBitNo();
|
2009-04-10 06:27:44 +08:00
|
|
|
RecordData Record;
|
|
|
|
for (DeclContext::decl_iterator D = DC->decls_begin(Context),
|
|
|
|
DEnd = DC->decls_end(Context);
|
|
|
|
D != DEnd; ++D)
|
|
|
|
AddDeclRef(*D, Record);
|
|
|
|
|
2009-04-23 06:34:57 +08:00
|
|
|
++NumLexicalDeclContexts;
|
2009-04-17 06:23:12 +08:00
|
|
|
Stream.EmitRecord(pch::DECL_CONTEXT_LEXICAL, Record);
|
2009-04-10 06:27:44 +08:00
|
|
|
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;
|
|
|
|
|
2009-04-22 06:32:33 +08:00
|
|
|
// Since there is no name lookup into functions or methods, and we
|
|
|
|
// perform name lookup for the translation unit via the
|
|
|
|
// IdentifierInfo chains, don't bother to build a
|
|
|
|
// visible-declarations table for these entities.
|
|
|
|
if (DC->isFunctionOrMethod() || DC->isTranslationUnit())
|
2009-04-18 23:49:20 +08:00
|
|
|
return 0;
|
|
|
|
|
2009-04-10 06:27:44 +08:00
|
|
|
// 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.
|
2009-04-17 06:23:12 +08:00
|
|
|
uint64_t Offset = Stream.GetCurrentBitNo();
|
2009-04-10 06:27:44 +08:00
|
|
|
RecordData Record;
|
|
|
|
StoredDeclsMap *Map = static_cast<StoredDeclsMap*>(DC->getLookupPtr());
|
2009-04-14 05:20:57 +08:00
|
|
|
if (!Map)
|
|
|
|
return 0;
|
|
|
|
|
2009-04-10 06:27:44 +08:00
|
|
|
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;
|
|
|
|
|
2009-04-17 06:23:12 +08:00
|
|
|
Stream.EmitRecord(pch::DECL_CONTEXT_VISIBLE, Record);
|
2009-04-23 06:34:57 +08:00
|
|
|
++NumVisibleDeclContexts;
|
2009-04-10 06:27:44 +08:00
|
|
|
return Offset;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Write a block containing all of the declarations.
|
|
|
|
void PCHWriter::WriteDeclsBlock(ASTContext &Context) {
|
2009-04-11 01:16:57 +08:00
|
|
|
// Enter the declarations block.
|
2009-04-17 06:23:12 +08:00
|
|
|
Stream.EnterSubblock(pch::DECLS_BLOCK_ID, 2);
|
2009-04-10 06:27:44 +08:00
|
|
|
|
|
|
|
// Emit all of the declarations.
|
|
|
|
RecordData Record;
|
2009-04-18 08:02:19 +08:00
|
|
|
PCHDeclWriter W(*this, Context, Record);
|
2009-04-10 06:27:44 +08:00
|
|
|
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
|
2009-04-11 01:25:41 +08:00
|
|
|
pch::DeclID ID = DeclIDs[D];
|
2009-04-10 06:27:44 +08:00
|
|
|
if (ID == 0)
|
|
|
|
ID = DeclIDs.size();
|
|
|
|
|
|
|
|
unsigned Index = ID - 1;
|
|
|
|
|
|
|
|
// Record the offset for this declaration
|
|
|
|
if (DeclOffsets.size() == Index)
|
2009-04-17 06:23:12 +08:00
|
|
|
DeclOffsets.push_back(Stream.GetCurrentBitNo());
|
2009-04-10 06:27:44 +08:00
|
|
|
else if (DeclOffsets.size() < Index) {
|
|
|
|
DeclOffsets.resize(Index+1);
|
2009-04-17 06:23:12 +08:00
|
|
|
DeclOffsets[Index] = Stream.GetCurrentBitNo();
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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);
|
2009-04-23 07:20:34 +08:00
|
|
|
|
|
|
|
if (!W.Code) {
|
|
|
|
fprintf(stderr, "Cannot serialize declaration of kind %s\n",
|
|
|
|
D->getDeclKindName());
|
|
|
|
assert(false && "Unhandled declaration kind while generating PCH");
|
|
|
|
exit(-1);
|
|
|
|
}
|
2009-04-17 06:23:12 +08:00
|
|
|
Stream.EmitRecord(W.Code, Record);
|
2009-04-14 08:24:19 +08:00
|
|
|
|
2009-04-16 05:30:51 +08:00
|
|
|
// If the declaration had any attributes, write them now.
|
|
|
|
if (D->hasAttrs())
|
|
|
|
WriteAttributeRecord(D->getAttrs());
|
|
|
|
|
2009-04-15 05:18:50 +08:00
|
|
|
// Flush any expressions that were written as part of this declaration.
|
2009-04-17 06:23:12 +08:00
|
|
|
FlushStmts();
|
2009-04-15 05:18:50 +08:00
|
|
|
|
2009-04-14 08:24:19 +08:00
|
|
|
// Note external declarations so that we can add them to a record
|
|
|
|
// in the PCH file later.
|
|
|
|
if (isa<FileScopeAsmDecl>(D))
|
|
|
|
ExternalDefinitions.push_back(ID);
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Exit the declarations block
|
2009-04-17 06:23:12 +08:00
|
|
|
Stream.ExitBlock();
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
|
|
|
|
2009-04-25 05:10:55 +08:00
|
|
|
namespace {
|
|
|
|
// Trait used for the on-disk hash table used in the method pool.
|
|
|
|
class VISIBILITY_HIDDEN PCHMethodPoolTrait {
|
|
|
|
PCHWriter &Writer;
|
|
|
|
|
|
|
|
public:
|
|
|
|
typedef Selector key_type;
|
|
|
|
typedef key_type key_type_ref;
|
|
|
|
|
|
|
|
typedef std::pair<ObjCMethodList, ObjCMethodList> data_type;
|
|
|
|
typedef const data_type& data_type_ref;
|
|
|
|
|
|
|
|
explicit PCHMethodPoolTrait(PCHWriter &Writer) : Writer(Writer) { }
|
|
|
|
|
|
|
|
static unsigned ComputeHash(Selector Sel) {
|
|
|
|
unsigned N = Sel.getNumArgs();
|
|
|
|
if (N == 0)
|
|
|
|
++N;
|
|
|
|
unsigned R = 5381;
|
|
|
|
for (unsigned I = 0; I != N; ++I)
|
|
|
|
if (IdentifierInfo *II = Sel.getIdentifierInfoForSlot(I))
|
|
|
|
R = clang::BernsteinHashPartial(II->getName(), II->getLength(), R);
|
|
|
|
return R;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::pair<unsigned,unsigned>
|
|
|
|
EmitKeyDataLength(llvm::raw_ostream& Out, Selector Sel,
|
|
|
|
data_type_ref Methods) {
|
|
|
|
unsigned KeyLen = 2 + (Sel.getNumArgs()? Sel.getNumArgs() * 4 : 4);
|
|
|
|
clang::io::Emit16(Out, KeyLen);
|
|
|
|
unsigned DataLen = 2 + 2; // 2 bytes for each of the method counts
|
|
|
|
for (const ObjCMethodList *Method = &Methods.first; Method;
|
|
|
|
Method = Method->Next)
|
|
|
|
if (Method->Method)
|
|
|
|
DataLen += 4;
|
|
|
|
for (const ObjCMethodList *Method = &Methods.second; Method;
|
|
|
|
Method = Method->Next)
|
|
|
|
if (Method->Method)
|
|
|
|
DataLen += 4;
|
|
|
|
clang::io::Emit16(Out, DataLen);
|
|
|
|
return std::make_pair(KeyLen, DataLen);
|
|
|
|
}
|
|
|
|
|
2009-04-26 01:48:32 +08:00
|
|
|
void EmitKey(llvm::raw_ostream& Out, Selector Sel, unsigned) {
|
|
|
|
uint64_t Start = Out.tell();
|
|
|
|
assert((Start >> 32) == 0 && "Selector key offset too large");
|
|
|
|
Writer.SetSelectorOffset(Sel, Start);
|
2009-04-25 05:10:55 +08:00
|
|
|
unsigned N = Sel.getNumArgs();
|
|
|
|
clang::io::Emit16(Out, N);
|
|
|
|
if (N == 0)
|
|
|
|
N = 1;
|
|
|
|
for (unsigned I = 0; I != N; ++I)
|
|
|
|
clang::io::Emit32(Out,
|
|
|
|
Writer.getIdentifierRef(Sel.getIdentifierInfoForSlot(I)));
|
|
|
|
}
|
|
|
|
|
|
|
|
void EmitData(llvm::raw_ostream& Out, key_type_ref,
|
2009-04-25 05:49:02 +08:00
|
|
|
data_type_ref Methods, unsigned DataLen) {
|
|
|
|
uint64_t Start = Out.tell(); (void)Start;
|
2009-04-25 05:10:55 +08:00
|
|
|
unsigned NumInstanceMethods = 0;
|
|
|
|
for (const ObjCMethodList *Method = &Methods.first; Method;
|
|
|
|
Method = Method->Next)
|
|
|
|
if (Method->Method)
|
|
|
|
++NumInstanceMethods;
|
|
|
|
|
|
|
|
unsigned NumFactoryMethods = 0;
|
|
|
|
for (const ObjCMethodList *Method = &Methods.second; Method;
|
|
|
|
Method = Method->Next)
|
|
|
|
if (Method->Method)
|
|
|
|
++NumFactoryMethods;
|
|
|
|
|
|
|
|
clang::io::Emit16(Out, NumInstanceMethods);
|
|
|
|
clang::io::Emit16(Out, NumFactoryMethods);
|
|
|
|
for (const ObjCMethodList *Method = &Methods.first; Method;
|
|
|
|
Method = Method->Next)
|
|
|
|
if (Method->Method)
|
|
|
|
clang::io::Emit32(Out, Writer.getDeclID(Method->Method));
|
|
|
|
for (const ObjCMethodList *Method = &Methods.second; Method;
|
|
|
|
Method = Method->Next)
|
|
|
|
if (Method->Method)
|
|
|
|
clang::io::Emit32(Out, Writer.getDeclID(Method->Method));
|
2009-04-25 05:49:02 +08:00
|
|
|
|
|
|
|
assert(Out.tell() - Start == DataLen && "Data length is wrong");
|
2009-04-25 05:10:55 +08:00
|
|
|
}
|
|
|
|
};
|
|
|
|
} // end anonymous namespace
|
|
|
|
|
|
|
|
/// \brief Write the method pool into the PCH file.
|
|
|
|
///
|
|
|
|
/// The method pool contains both instance and factory methods, stored
|
|
|
|
/// in an on-disk hash table indexed by the selector.
|
|
|
|
void PCHWriter::WriteMethodPool(Sema &SemaRef) {
|
|
|
|
using namespace llvm;
|
|
|
|
|
|
|
|
// Create and write out the blob that contains the instance and
|
|
|
|
// factor method pools.
|
|
|
|
bool Empty = true;
|
|
|
|
{
|
|
|
|
OnDiskChainedHashTableGenerator<PCHMethodPoolTrait> Generator;
|
|
|
|
|
|
|
|
// Create the on-disk hash table representation. Start by
|
|
|
|
// iterating through the instance method pool.
|
|
|
|
PCHMethodPoolTrait::key_type Key;
|
2009-04-26 01:48:32 +08:00
|
|
|
unsigned NumSelectorsInMethodPool = 0;
|
2009-04-25 05:10:55 +08:00
|
|
|
for (llvm::DenseMap<Selector, ObjCMethodList>::iterator
|
|
|
|
Instance = SemaRef.InstanceMethodPool.begin(),
|
|
|
|
InstanceEnd = SemaRef.InstanceMethodPool.end();
|
|
|
|
Instance != InstanceEnd; ++Instance) {
|
|
|
|
// Check whether there is a factory method with the same
|
|
|
|
// selector.
|
|
|
|
llvm::DenseMap<Selector, ObjCMethodList>::iterator Factory
|
|
|
|
= SemaRef.FactoryMethodPool.find(Instance->first);
|
|
|
|
|
|
|
|
if (Factory == SemaRef.FactoryMethodPool.end())
|
|
|
|
Generator.insert(Instance->first,
|
|
|
|
std::make_pair(Instance->second,
|
|
|
|
ObjCMethodList()));
|
|
|
|
else
|
|
|
|
Generator.insert(Instance->first,
|
|
|
|
std::make_pair(Instance->second, Factory->second));
|
|
|
|
|
2009-04-26 01:48:32 +08:00
|
|
|
++NumSelectorsInMethodPool;
|
2009-04-25 05:10:55 +08:00
|
|
|
Empty = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now iterate through the factory method pool, to pick up any
|
|
|
|
// selectors that weren't already in the instance method pool.
|
|
|
|
for (llvm::DenseMap<Selector, ObjCMethodList>::iterator
|
|
|
|
Factory = SemaRef.FactoryMethodPool.begin(),
|
|
|
|
FactoryEnd = SemaRef.FactoryMethodPool.end();
|
|
|
|
Factory != FactoryEnd; ++Factory) {
|
|
|
|
// Check whether there is an instance method with the same
|
|
|
|
// selector. If so, there is no work to do here.
|
|
|
|
llvm::DenseMap<Selector, ObjCMethodList>::iterator Instance
|
|
|
|
= SemaRef.InstanceMethodPool.find(Factory->first);
|
|
|
|
|
2009-04-26 01:48:32 +08:00
|
|
|
if (Instance == SemaRef.InstanceMethodPool.end()) {
|
2009-04-25 05:10:55 +08:00
|
|
|
Generator.insert(Factory->first,
|
|
|
|
std::make_pair(ObjCMethodList(), Factory->second));
|
2009-04-26 01:48:32 +08:00
|
|
|
++NumSelectorsInMethodPool;
|
|
|
|
}
|
2009-04-25 05:10:55 +08:00
|
|
|
|
|
|
|
Empty = false;
|
|
|
|
}
|
|
|
|
|
2009-04-26 01:48:32 +08:00
|
|
|
if (Empty && SelectorOffsets.empty())
|
2009-04-25 05:10:55 +08:00
|
|
|
return;
|
|
|
|
|
|
|
|
// Create the on-disk hash table in a buffer.
|
|
|
|
llvm::SmallVector<char, 4096> MethodPool;
|
|
|
|
uint32_t BucketOffset;
|
2009-04-26 01:48:32 +08:00
|
|
|
SelectorOffsets.resize(SelVector.size());
|
2009-04-25 05:10:55 +08:00
|
|
|
{
|
|
|
|
PCHMethodPoolTrait Trait(*this);
|
|
|
|
llvm::raw_svector_ostream Out(MethodPool);
|
|
|
|
// Make sure that no bucket is at offset 0
|
2009-04-25 05:49:02 +08:00
|
|
|
clang::io::Emit32(Out, 0);
|
2009-04-25 05:10:55 +08:00
|
|
|
BucketOffset = Generator.Emit(Out, Trait);
|
2009-04-26 01:48:32 +08:00
|
|
|
|
|
|
|
// For every selector that we have seen but which was not
|
|
|
|
// written into the hash table, write the selector itself and
|
|
|
|
// record it's offset.
|
|
|
|
for (unsigned I = 0, N = SelVector.size(); I != N; ++I)
|
|
|
|
if (SelectorOffsets[I] == 0)
|
|
|
|
Trait.EmitKey(Out, SelVector[I], 0);
|
2009-04-25 05:10:55 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Create a blob abbreviation
|
|
|
|
BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(pch::METHOD_POOL));
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
|
2009-04-26 01:48:32 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
|
2009-04-25 05:10:55 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
|
|
|
|
unsigned MethodPoolAbbrev = Stream.EmitAbbrev(Abbrev);
|
|
|
|
|
2009-04-26 01:48:32 +08:00
|
|
|
// Write the method pool
|
2009-04-25 05:10:55 +08:00
|
|
|
RecordData Record;
|
|
|
|
Record.push_back(pch::METHOD_POOL);
|
|
|
|
Record.push_back(BucketOffset);
|
2009-04-26 01:48:32 +08:00
|
|
|
Record.push_back(NumSelectorsInMethodPool);
|
2009-04-25 05:10:55 +08:00
|
|
|
Stream.EmitRecordWithBlob(MethodPoolAbbrev, Record,
|
|
|
|
&MethodPool.front(),
|
|
|
|
MethodPool.size());
|
2009-04-26 01:48:32 +08:00
|
|
|
|
|
|
|
// Create a blob abbreviation for the selector table offsets.
|
|
|
|
Abbrev = new BitCodeAbbrev();
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(pch::SELECTOR_OFFSETS));
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // index
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
|
|
|
|
unsigned SelectorOffsetAbbrev = Stream.EmitAbbrev(Abbrev);
|
|
|
|
|
|
|
|
// Write the selector offsets table.
|
|
|
|
Record.clear();
|
|
|
|
Record.push_back(pch::SELECTOR_OFFSETS);
|
|
|
|
Record.push_back(SelectorOffsets.size());
|
|
|
|
Stream.EmitRecordWithBlob(SelectorOffsetAbbrev, Record,
|
|
|
|
(const char *)&SelectorOffsets.front(),
|
|
|
|
SelectorOffsets.size() * 4);
|
2009-04-25 05:10:55 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-04-21 04:36:09 +08:00
|
|
|
namespace {
|
|
|
|
class VISIBILITY_HIDDEN PCHIdentifierTableTrait {
|
|
|
|
PCHWriter &Writer;
|
2009-04-22 07:56:24 +08:00
|
|
|
Preprocessor &PP;
|
2009-04-21 04:36:09 +08:00
|
|
|
|
|
|
|
public:
|
|
|
|
typedef const IdentifierInfo* key_type;
|
|
|
|
typedef key_type key_type_ref;
|
|
|
|
|
|
|
|
typedef pch::IdentID data_type;
|
|
|
|
typedef data_type data_type_ref;
|
|
|
|
|
2009-04-22 07:56:24 +08:00
|
|
|
PCHIdentifierTableTrait(PCHWriter &Writer, Preprocessor &PP)
|
|
|
|
: Writer(Writer), PP(PP) { }
|
2009-04-21 04:36:09 +08:00
|
|
|
|
|
|
|
static unsigned ComputeHash(const IdentifierInfo* II) {
|
|
|
|
return clang::BernsteinHash(II->getName());
|
|
|
|
}
|
|
|
|
|
2009-04-22 07:56:24 +08:00
|
|
|
std::pair<unsigned,unsigned>
|
2009-04-21 04:36:09 +08:00
|
|
|
EmitKeyDataLength(llvm::raw_ostream& Out, const IdentifierInfo* II,
|
|
|
|
pch::IdentID ID) {
|
|
|
|
unsigned KeyLen = strlen(II->getName()) + 1;
|
Lazy deserialization of the declaration chains associated with
identifiers from a precompiled header.
This patch changes the primary name lookup method for entities within
a precompiled header. Previously, we would load all of the names of
declarations at translation unit scope into a large DenseMap (inside
the TranslationUnitDecl's DeclContext), and then perform a special
"last resort" lookup into this DeclContext when we knew there was a
PCH file (see Sema::LookupName). Now, when we see an identifier named
for the first time, we load all of the declarations with that name
that are visible from the translation unit into the IdentifierInfo's
chain of declarations. Thus, the explicit "look into the translation
unit's DeclContext" code is gone, and Sema effectively uses the same
IdentifierInfo-based name lookup mechanism whether we are using a PCH
file or not.
This approach should help PCH scale with the size of the input program
rather than the size of the PCH file. The "Hello, World!" application
with Carbon.h as a PCH file now loads 20% of the identifiers in the
PCH file rather than 85% of the identifiers.
90% of the 20% of identifiers loaded are actually loaded when we
deserialize the preprocessor state. The next step is to make the
preprocessor load macros lazily, which should drastically reduce the
number of types, declarations, and identifiers loaded for "Hello,
World".
llvm-svn: 69737
2009-04-22 06:25:48 +08:00
|
|
|
unsigned DataLen = 4 + 4; // 4 bytes for token ID, builtin, flags
|
|
|
|
// 4 bytes for the persistent ID
|
2009-04-22 07:56:24 +08:00
|
|
|
if (II->hasMacroDefinition() &&
|
|
|
|
!PP.getMacroInfo(const_cast<IdentifierInfo *>(II))->isBuiltinMacro())
|
|
|
|
DataLen += 8;
|
2009-04-21 04:36:09 +08:00
|
|
|
for (IdentifierResolver::iterator D = IdentifierResolver::begin(II),
|
|
|
|
DEnd = IdentifierResolver::end();
|
|
|
|
D != DEnd; ++D)
|
|
|
|
DataLen += sizeof(pch::DeclID);
|
2009-04-26 05:04:17 +08:00
|
|
|
// We emit the key length after the data length so that the
|
|
|
|
// "uninteresting" identifiers following the identifier hash table
|
|
|
|
// structure will have the same (key length, key characters)
|
|
|
|
// layout as the keys in the hash table. This also matches the
|
|
|
|
// format for identifiers in pretokenized headers.
|
Lazy deserialization of the declaration chains associated with
identifiers from a precompiled header.
This patch changes the primary name lookup method for entities within
a precompiled header. Previously, we would load all of the names of
declarations at translation unit scope into a large DenseMap (inside
the TranslationUnitDecl's DeclContext), and then perform a special
"last resort" lookup into this DeclContext when we knew there was a
PCH file (see Sema::LookupName). Now, when we see an identifier named
for the first time, we load all of the declarations with that name
that are visible from the translation unit into the IdentifierInfo's
chain of declarations. Thus, the explicit "look into the translation
unit's DeclContext" code is gone, and Sema effectively uses the same
IdentifierInfo-based name lookup mechanism whether we are using a PCH
file or not.
This approach should help PCH scale with the size of the input program
rather than the size of the PCH file. The "Hello, World!" application
with Carbon.h as a PCH file now loads 20% of the identifiers in the
PCH file rather than 85% of the identifiers.
90% of the 20% of identifiers loaded are actually loaded when we
deserialize the preprocessor state. The next step is to make the
preprocessor load macros lazily, which should drastically reduce the
number of types, declarations, and identifiers loaded for "Hello,
World".
llvm-svn: 69737
2009-04-22 06:25:48 +08:00
|
|
|
clang::io::Emit16(Out, DataLen);
|
2009-04-26 05:04:17 +08:00
|
|
|
clang::io::Emit16(Out, KeyLen);
|
2009-04-21 04:36:09 +08:00
|
|
|
return std::make_pair(KeyLen, DataLen);
|
|
|
|
}
|
|
|
|
|
|
|
|
void EmitKey(llvm::raw_ostream& Out, const IdentifierInfo* II,
|
|
|
|
unsigned KeyLen) {
|
|
|
|
// Record the location of the key data. This is used when generating
|
|
|
|
// the mapping from persistent IDs to strings.
|
|
|
|
Writer.SetIdentifierOffset(II, Out.tell());
|
|
|
|
Out.write(II->getName(), KeyLen);
|
|
|
|
}
|
|
|
|
|
|
|
|
void EmitData(llvm::raw_ostream& Out, const IdentifierInfo* II,
|
|
|
|
pch::IdentID ID, unsigned) {
|
|
|
|
uint32_t Bits = 0;
|
2009-04-22 07:56:24 +08:00
|
|
|
bool hasMacroDefinition =
|
|
|
|
II->hasMacroDefinition() &&
|
|
|
|
!PP.getMacroInfo(const_cast<IdentifierInfo *>(II))->isBuiltinMacro();
|
2009-04-21 04:36:09 +08:00
|
|
|
Bits = Bits | (uint32_t)II->getTokenID();
|
2009-04-23 02:49:13 +08:00
|
|
|
Bits = (Bits << 10) | (uint32_t)II->getObjCOrBuiltinID();
|
|
|
|
Bits = (Bits << 1) | hasMacroDefinition;
|
2009-04-21 04:36:09 +08:00
|
|
|
Bits = (Bits << 1) | II->isExtensionToken();
|
|
|
|
Bits = (Bits << 1) | II->isPoisoned();
|
|
|
|
Bits = (Bits << 1) | II->isCPlusPlusOperatorKeyword();
|
|
|
|
clang::io::Emit32(Out, Bits);
|
|
|
|
clang::io::Emit32(Out, ID);
|
|
|
|
|
2009-04-22 07:56:24 +08:00
|
|
|
if (hasMacroDefinition)
|
|
|
|
clang::io::Emit64(Out, Writer.getMacroOffset(II));
|
|
|
|
|
Lazy deserialization of the declaration chains associated with
identifiers from a precompiled header.
This patch changes the primary name lookup method for entities within
a precompiled header. Previously, we would load all of the names of
declarations at translation unit scope into a large DenseMap (inside
the TranslationUnitDecl's DeclContext), and then perform a special
"last resort" lookup into this DeclContext when we knew there was a
PCH file (see Sema::LookupName). Now, when we see an identifier named
for the first time, we load all of the declarations with that name
that are visible from the translation unit into the IdentifierInfo's
chain of declarations. Thus, the explicit "look into the translation
unit's DeclContext" code is gone, and Sema effectively uses the same
IdentifierInfo-based name lookup mechanism whether we are using a PCH
file or not.
This approach should help PCH scale with the size of the input program
rather than the size of the PCH file. The "Hello, World!" application
with Carbon.h as a PCH file now loads 20% of the identifiers in the
PCH file rather than 85% of the identifiers.
90% of the 20% of identifiers loaded are actually loaded when we
deserialize the preprocessor state. The next step is to make the
preprocessor load macros lazily, which should drastically reduce the
number of types, declarations, and identifiers loaded for "Hello,
World".
llvm-svn: 69737
2009-04-22 06:25:48 +08:00
|
|
|
// Emit the declaration IDs in reverse order, because the
|
|
|
|
// IdentifierResolver provides the declarations as they would be
|
|
|
|
// visible (e.g., the function "stat" would come before the struct
|
|
|
|
// "stat"), but IdentifierResolver::AddDeclToIdentifierChain()
|
|
|
|
// adds declarations to the end of the list (so we need to see the
|
|
|
|
// struct "status" before the function "status").
|
|
|
|
llvm::SmallVector<Decl *, 16> Decls(IdentifierResolver::begin(II),
|
|
|
|
IdentifierResolver::end());
|
|
|
|
for (llvm::SmallVector<Decl *, 16>::reverse_iterator D = Decls.rbegin(),
|
|
|
|
DEnd = Decls.rend();
|
2009-04-21 04:36:09 +08:00
|
|
|
D != DEnd; ++D)
|
Lazy deserialization of the declaration chains associated with
identifiers from a precompiled header.
This patch changes the primary name lookup method for entities within
a precompiled header. Previously, we would load all of the names of
declarations at translation unit scope into a large DenseMap (inside
the TranslationUnitDecl's DeclContext), and then perform a special
"last resort" lookup into this DeclContext when we knew there was a
PCH file (see Sema::LookupName). Now, when we see an identifier named
for the first time, we load all of the declarations with that name
that are visible from the translation unit into the IdentifierInfo's
chain of declarations. Thus, the explicit "look into the translation
unit's DeclContext" code is gone, and Sema effectively uses the same
IdentifierInfo-based name lookup mechanism whether we are using a PCH
file or not.
This approach should help PCH scale with the size of the input program
rather than the size of the PCH file. The "Hello, World!" application
with Carbon.h as a PCH file now loads 20% of the identifiers in the
PCH file rather than 85% of the identifiers.
90% of the 20% of identifiers loaded are actually loaded when we
deserialize the preprocessor state. The next step is to make the
preprocessor load macros lazily, which should drastically reduce the
number of types, declarations, and identifiers loaded for "Hello,
World".
llvm-svn: 69737
2009-04-22 06:25:48 +08:00
|
|
|
clang::io::Emit32(Out, Writer.getDeclID(*D));
|
2009-04-21 04:36:09 +08:00
|
|
|
}
|
|
|
|
};
|
|
|
|
} // end anonymous namespace
|
|
|
|
|
2009-04-11 08:14:32 +08:00
|
|
|
/// \brief Write the identifier table into the PCH file.
|
|
|
|
///
|
|
|
|
/// The identifier table consists of a blob containing string data
|
|
|
|
/// (the actual identifiers themselves) and a separate "offsets" index
|
|
|
|
/// that maps identifier IDs to locations within the blob.
|
2009-04-22 07:56:24 +08:00
|
|
|
void PCHWriter::WriteIdentifierTable(Preprocessor &PP) {
|
2009-04-11 08:14:32 +08:00
|
|
|
using namespace llvm;
|
|
|
|
|
|
|
|
// Create and write out the blob that contains the identifier
|
|
|
|
// strings.
|
2009-04-21 04:36:09 +08:00
|
|
|
IdentifierOffsets.resize(IdentifierIDs.size());
|
2009-04-11 08:14:32 +08:00
|
|
|
{
|
2009-04-21 04:36:09 +08:00
|
|
|
OnDiskChainedHashTableGenerator<PCHIdentifierTableTrait> Generator;
|
|
|
|
|
2009-04-26 05:04:17 +08:00
|
|
|
llvm::SmallVector<const IdentifierInfo *, 32> UninterestingIdentifiers;
|
|
|
|
|
2009-04-21 04:36:09 +08:00
|
|
|
// Create the on-disk hash table representation.
|
2009-04-11 08:14:32 +08:00
|
|
|
for (llvm::DenseMap<const IdentifierInfo *, pch::IdentID>::iterator
|
|
|
|
ID = IdentifierIDs.begin(), IDEnd = IdentifierIDs.end();
|
|
|
|
ID != IDEnd; ++ID) {
|
|
|
|
assert(ID->first && "NULL identifier in identifier table");
|
2009-04-26 05:04:17 +08:00
|
|
|
|
|
|
|
// Classify each identifier as either "interesting" or "not
|
|
|
|
// interesting". Interesting identifiers are those that have
|
|
|
|
// additional information that needs to be read from the PCH
|
|
|
|
// file, e.g., a built-in ID, declaration chain, or macro
|
|
|
|
// definition. These identifiers are placed into the hash table
|
|
|
|
// so that they can be found when looked up in the user program.
|
|
|
|
// All other identifiers are "uninteresting", which means that
|
|
|
|
// the IdentifierInfo built by default has all of the
|
|
|
|
// information we care about. Such identifiers are placed after
|
|
|
|
// the hash table.
|
|
|
|
const IdentifierInfo *II = ID->first;
|
|
|
|
if (II->isPoisoned() ||
|
|
|
|
II->isExtensionToken() ||
|
|
|
|
II->hasMacroDefinition() ||
|
|
|
|
II->getObjCOrBuiltinID() ||
|
|
|
|
II->getFETokenInfo<void>())
|
|
|
|
Generator.insert(ID->first, ID->second);
|
|
|
|
else
|
|
|
|
UninterestingIdentifiers.push_back(II);
|
2009-04-21 04:36:09 +08:00
|
|
|
}
|
2009-04-11 08:14:32 +08:00
|
|
|
|
2009-04-21 04:36:09 +08:00
|
|
|
// Create the on-disk hash table in a buffer.
|
|
|
|
llvm::SmallVector<char, 4096> IdentifierTable;
|
Lazy deserialization of the declaration chains associated with
identifiers from a precompiled header.
This patch changes the primary name lookup method for entities within
a precompiled header. Previously, we would load all of the names of
declarations at translation unit scope into a large DenseMap (inside
the TranslationUnitDecl's DeclContext), and then perform a special
"last resort" lookup into this DeclContext when we knew there was a
PCH file (see Sema::LookupName). Now, when we see an identifier named
for the first time, we load all of the declarations with that name
that are visible from the translation unit into the IdentifierInfo's
chain of declarations. Thus, the explicit "look into the translation
unit's DeclContext" code is gone, and Sema effectively uses the same
IdentifierInfo-based name lookup mechanism whether we are using a PCH
file or not.
This approach should help PCH scale with the size of the input program
rather than the size of the PCH file. The "Hello, World!" application
with Carbon.h as a PCH file now loads 20% of the identifiers in the
PCH file rather than 85% of the identifiers.
90% of the 20% of identifiers loaded are actually loaded when we
deserialize the preprocessor state. The next step is to make the
preprocessor load macros lazily, which should drastically reduce the
number of types, declarations, and identifiers loaded for "Hello,
World".
llvm-svn: 69737
2009-04-22 06:25:48 +08:00
|
|
|
uint32_t BucketOffset;
|
2009-04-21 04:36:09 +08:00
|
|
|
{
|
2009-04-22 07:56:24 +08:00
|
|
|
PCHIdentifierTableTrait Trait(*this, PP);
|
2009-04-21 04:36:09 +08:00
|
|
|
llvm::raw_svector_ostream Out(IdentifierTable);
|
2009-04-25 05:10:55 +08:00
|
|
|
// Make sure that no bucket is at offset 0
|
2009-04-25 05:49:02 +08:00
|
|
|
clang::io::Emit32(Out, 0);
|
Lazy deserialization of the declaration chains associated with
identifiers from a precompiled header.
This patch changes the primary name lookup method for entities within
a precompiled header. Previously, we would load all of the names of
declarations at translation unit scope into a large DenseMap (inside
the TranslationUnitDecl's DeclContext), and then perform a special
"last resort" lookup into this DeclContext when we knew there was a
PCH file (see Sema::LookupName). Now, when we see an identifier named
for the first time, we load all of the declarations with that name
that are visible from the translation unit into the IdentifierInfo's
chain of declarations. Thus, the explicit "look into the translation
unit's DeclContext" code is gone, and Sema effectively uses the same
IdentifierInfo-based name lookup mechanism whether we are using a PCH
file or not.
This approach should help PCH scale with the size of the input program
rather than the size of the PCH file. The "Hello, World!" application
with Carbon.h as a PCH file now loads 20% of the identifiers in the
PCH file rather than 85% of the identifiers.
90% of the 20% of identifiers loaded are actually loaded when we
deserialize the preprocessor state. The next step is to make the
preprocessor load macros lazily, which should drastically reduce the
number of types, declarations, and identifiers loaded for "Hello,
World".
llvm-svn: 69737
2009-04-22 06:25:48 +08:00
|
|
|
BucketOffset = Generator.Emit(Out, Trait);
|
2009-04-26 05:04:17 +08:00
|
|
|
|
|
|
|
for (unsigned I = 0, N = UninterestingIdentifiers.size(); I != N; ++I) {
|
|
|
|
const IdentifierInfo *II = UninterestingIdentifiers[I];
|
|
|
|
unsigned N = II->getLength() + 1;
|
|
|
|
clang::io::Emit16(Out, N);
|
|
|
|
SetIdentifierOffset(II, Out.tell());
|
|
|
|
Out.write(II->getName(), N);
|
|
|
|
}
|
2009-04-11 08:14:32 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Create a blob abbreviation
|
|
|
|
BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(pch::IDENTIFIER_TABLE));
|
Lazy deserialization of the declaration chains associated with
identifiers from a precompiled header.
This patch changes the primary name lookup method for entities within
a precompiled header. Previously, we would load all of the names of
declarations at translation unit scope into a large DenseMap (inside
the TranslationUnitDecl's DeclContext), and then perform a special
"last resort" lookup into this DeclContext when we knew there was a
PCH file (see Sema::LookupName). Now, when we see an identifier named
for the first time, we load all of the declarations with that name
that are visible from the translation unit into the IdentifierInfo's
chain of declarations. Thus, the explicit "look into the translation
unit's DeclContext" code is gone, and Sema effectively uses the same
IdentifierInfo-based name lookup mechanism whether we are using a PCH
file or not.
This approach should help PCH scale with the size of the input program
rather than the size of the PCH file. The "Hello, World!" application
with Carbon.h as a PCH file now loads 20% of the identifiers in the
PCH file rather than 85% of the identifiers.
90% of the 20% of identifiers loaded are actually loaded when we
deserialize the preprocessor state. The next step is to make the
preprocessor load macros lazily, which should drastically reduce the
number of types, declarations, and identifiers loaded for "Hello,
World".
llvm-svn: 69737
2009-04-22 06:25:48 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
|
2009-04-21 04:36:09 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
|
2009-04-17 06:23:12 +08:00
|
|
|
unsigned IDTableAbbrev = Stream.EmitAbbrev(Abbrev);
|
2009-04-11 08:14:32 +08:00
|
|
|
|
|
|
|
// Write the identifier table
|
|
|
|
RecordData Record;
|
|
|
|
Record.push_back(pch::IDENTIFIER_TABLE);
|
Lazy deserialization of the declaration chains associated with
identifiers from a precompiled header.
This patch changes the primary name lookup method for entities within
a precompiled header. Previously, we would load all of the names of
declarations at translation unit scope into a large DenseMap (inside
the TranslationUnitDecl's DeclContext), and then perform a special
"last resort" lookup into this DeclContext when we knew there was a
PCH file (see Sema::LookupName). Now, when we see an identifier named
for the first time, we load all of the declarations with that name
that are visible from the translation unit into the IdentifierInfo's
chain of declarations. Thus, the explicit "look into the translation
unit's DeclContext" code is gone, and Sema effectively uses the same
IdentifierInfo-based name lookup mechanism whether we are using a PCH
file or not.
This approach should help PCH scale with the size of the input program
rather than the size of the PCH file. The "Hello, World!" application
with Carbon.h as a PCH file now loads 20% of the identifiers in the
PCH file rather than 85% of the identifiers.
90% of the 20% of identifiers loaded are actually loaded when we
deserialize the preprocessor state. The next step is to make the
preprocessor load macros lazily, which should drastically reduce the
number of types, declarations, and identifiers loaded for "Hello,
World".
llvm-svn: 69737
2009-04-22 06:25:48 +08:00
|
|
|
Record.push_back(BucketOffset);
|
2009-04-21 04:36:09 +08:00
|
|
|
Stream.EmitRecordWithBlob(IDTableAbbrev, Record,
|
|
|
|
&IdentifierTable.front(),
|
|
|
|
IdentifierTable.size());
|
2009-04-11 08:14:32 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Write the offsets table for identifier IDs.
|
2009-04-26 03:10:14 +08:00
|
|
|
BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(pch::IDENTIFIER_OFFSET));
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of identifiers
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
|
|
|
|
unsigned IdentifierOffsetAbbrev = Stream.EmitAbbrev(Abbrev);
|
|
|
|
|
|
|
|
RecordData Record;
|
|
|
|
Record.push_back(pch::IDENTIFIER_OFFSET);
|
|
|
|
Record.push_back(IdentifierOffsets.size());
|
|
|
|
Stream.EmitRecordWithBlob(IdentifierOffsetAbbrev, Record,
|
|
|
|
(const char *)&IdentifierOffsets.front(),
|
|
|
|
IdentifierOffsets.size() * sizeof(uint32_t));
|
2009-04-11 08:14:32 +08:00
|
|
|
}
|
|
|
|
|
2009-04-16 05:30:51 +08:00
|
|
|
/// \brief Write a record containing the given attributes.
|
|
|
|
void PCHWriter::WriteAttributeRecord(const Attr *Attr) {
|
|
|
|
RecordData Record;
|
|
|
|
for (; Attr; Attr = Attr->getNext()) {
|
|
|
|
Record.push_back(Attr->getKind()); // FIXME: stable encoding
|
|
|
|
Record.push_back(Attr->isInherited());
|
|
|
|
switch (Attr->getKind()) {
|
|
|
|
case Attr::Alias:
|
|
|
|
AddString(cast<AliasAttr>(Attr)->getAliasee(), Record);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Attr::Aligned:
|
|
|
|
Record.push_back(cast<AlignedAttr>(Attr)->getAlignment());
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Attr::AlwaysInline:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Attr::AnalyzerNoReturn:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Attr::Annotate:
|
|
|
|
AddString(cast<AnnotateAttr>(Attr)->getAnnotation(), Record);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Attr::AsmLabel:
|
|
|
|
AddString(cast<AsmLabelAttr>(Attr)->getLabel(), Record);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Attr::Blocks:
|
|
|
|
Record.push_back(cast<BlocksAttr>(Attr)->getType()); // FIXME: stable
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Attr::Cleanup:
|
|
|
|
AddDeclRef(cast<CleanupAttr>(Attr)->getFunctionDecl(), Record);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Attr::Const:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Attr::Constructor:
|
|
|
|
Record.push_back(cast<ConstructorAttr>(Attr)->getPriority());
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Attr::DLLExport:
|
|
|
|
case Attr::DLLImport:
|
|
|
|
case Attr::Deprecated:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Attr::Destructor:
|
|
|
|
Record.push_back(cast<DestructorAttr>(Attr)->getPriority());
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Attr::FastCall:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Attr::Format: {
|
|
|
|
const FormatAttr *Format = cast<FormatAttr>(Attr);
|
|
|
|
AddString(Format->getType(), Record);
|
|
|
|
Record.push_back(Format->getFormatIdx());
|
|
|
|
Record.push_back(Format->getFirstArg());
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2009-04-21 03:12:28 +08:00
|
|
|
case Attr::GNUInline:
|
2009-04-16 05:30:51 +08:00
|
|
|
case Attr::IBOutletKind:
|
|
|
|
case Attr::NoReturn:
|
|
|
|
case Attr::NoThrow:
|
|
|
|
case Attr::Nodebug:
|
|
|
|
case Attr::Noinline:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Attr::NonNull: {
|
|
|
|
const NonNullAttr *NonNull = cast<NonNullAttr>(Attr);
|
|
|
|
Record.push_back(NonNull->size());
|
|
|
|
Record.insert(Record.end(), NonNull->begin(), NonNull->end());
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case Attr::ObjCException:
|
|
|
|
case Attr::ObjCNSObject:
|
2009-04-25 08:17:17 +08:00
|
|
|
case Attr::ObjCOwnershipRetain:
|
2009-04-25 07:09:54 +08:00
|
|
|
case Attr::ObjCOwnershipReturns:
|
2009-04-16 05:30:51 +08:00
|
|
|
case Attr::Overloadable:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Attr::Packed:
|
|
|
|
Record.push_back(cast<PackedAttr>(Attr)->getAlignment());
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Attr::Pure:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Attr::Regparm:
|
|
|
|
Record.push_back(cast<RegparmAttr>(Attr)->getNumParams());
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Attr::Section:
|
|
|
|
AddString(cast<SectionAttr>(Attr)->getName(), Record);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Attr::StdCall:
|
|
|
|
case Attr::TransparentUnion:
|
|
|
|
case Attr::Unavailable:
|
|
|
|
case Attr::Unused:
|
|
|
|
case Attr::Used:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Attr::Visibility:
|
|
|
|
// FIXME: stable encoding
|
|
|
|
Record.push_back(cast<VisibilityAttr>(Attr)->getVisibility());
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Attr::WarnUnusedResult:
|
|
|
|
case Attr::Weak:
|
|
|
|
case Attr::WeakImport:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-04-17 06:23:12 +08:00
|
|
|
Stream.EmitRecord(pch::DECL_ATTR, Record);
|
2009-04-16 05:30:51 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void PCHWriter::AddString(const std::string &Str, RecordData &Record) {
|
|
|
|
Record.push_back(Str.size());
|
|
|
|
Record.insert(Record.end(), Str.begin(), Str.end());
|
|
|
|
}
|
|
|
|
|
2009-04-21 04:36:09 +08:00
|
|
|
/// \brief Note that the identifier II occurs at the given offset
|
|
|
|
/// within the identifier table.
|
|
|
|
void PCHWriter::SetIdentifierOffset(const IdentifierInfo *II, uint32_t Offset) {
|
2009-04-26 03:10:14 +08:00
|
|
|
IdentifierOffsets[IdentifierIDs[II] - 1] = Offset;
|
2009-04-21 04:36:09 +08:00
|
|
|
}
|
|
|
|
|
2009-04-26 01:48:32 +08:00
|
|
|
/// \brief Note that the selector Sel occurs at the given offset
|
|
|
|
/// within the method pool/selector table.
|
|
|
|
void PCHWriter::SetSelectorOffset(Selector Sel, uint32_t Offset) {
|
|
|
|
unsigned ID = SelectorIDs[Sel];
|
|
|
|
assert(ID && "Unknown selector");
|
|
|
|
SelectorOffsets[ID - 1] = Offset;
|
|
|
|
}
|
|
|
|
|
2009-04-17 06:23:12 +08:00
|
|
|
PCHWriter::PCHWriter(llvm::BitstreamWriter &Stream)
|
2009-04-22 07:56:24 +08:00
|
|
|
: Stream(Stream), NextTypeID(pch::NUM_PREDEF_TYPE_IDS),
|
2009-04-23 06:34:57 +08:00
|
|
|
NumStatements(0), NumMacros(0), NumLexicalDeclContexts(0),
|
|
|
|
NumVisibleDeclContexts(0) { }
|
2009-04-10 06:27:44 +08:00
|
|
|
|
2009-04-20 23:53:59 +08:00
|
|
|
void PCHWriter::WritePCH(Sema &SemaRef) {
|
2009-04-26 02:35:21 +08:00
|
|
|
using namespace llvm;
|
|
|
|
|
2009-04-20 23:53:59 +08:00
|
|
|
ASTContext &Context = SemaRef.Context;
|
|
|
|
Preprocessor &PP = SemaRef.PP;
|
|
|
|
|
2009-04-10 06:27:44 +08:00
|
|
|
// Emit the file header.
|
2009-04-17 06:23:12 +08:00
|
|
|
Stream.Emit((unsigned)'C', 8);
|
|
|
|
Stream.Emit((unsigned)'P', 8);
|
|
|
|
Stream.Emit((unsigned)'C', 8);
|
|
|
|
Stream.Emit((unsigned)'H', 8);
|
2009-04-10 06:27:44 +08:00
|
|
|
|
|
|
|
// The translation unit is the first declaration we'll emit.
|
|
|
|
DeclIDs[Context.getTranslationUnitDecl()] = 1;
|
|
|
|
DeclsToEmit.push(Context.getTranslationUnitDecl());
|
|
|
|
|
2009-04-23 02:49:13 +08:00
|
|
|
// Make sure that we emit IdentifierInfos (and any attached
|
|
|
|
// declarations) for builtins.
|
|
|
|
{
|
|
|
|
IdentifierTable &Table = PP.getIdentifierTable();
|
|
|
|
llvm::SmallVector<const char *, 32> BuiltinNames;
|
|
|
|
Context.BuiltinInfo.GetBuiltinNames(BuiltinNames,
|
|
|
|
Context.getLangOptions().NoBuiltin);
|
|
|
|
for (unsigned I = 0, N = BuiltinNames.size(); I != N; ++I)
|
|
|
|
getIdentifierRef(&Table.get(BuiltinNames[I]));
|
|
|
|
}
|
|
|
|
|
2009-04-23 06:02:47 +08:00
|
|
|
// Build a record containing all of the tentative definitions in
|
|
|
|
// this header file. Generally, this record will be empty.
|
|
|
|
RecordData TentativeDefinitions;
|
|
|
|
for (llvm::DenseMap<DeclarationName, VarDecl *>::iterator
|
|
|
|
TD = SemaRef.TentativeDefinitions.begin(),
|
|
|
|
TDEnd = SemaRef.TentativeDefinitions.end();
|
|
|
|
TD != TDEnd; ++TD)
|
|
|
|
AddDeclRef(TD->second, TentativeDefinitions);
|
|
|
|
|
2009-04-23 06:18:58 +08:00
|
|
|
// Build a record containing all of the locally-scoped external
|
|
|
|
// declarations in this header file. Generally, this record will be
|
|
|
|
// empty.
|
|
|
|
RecordData LocallyScopedExternalDecls;
|
|
|
|
for (llvm::DenseMap<DeclarationName, NamedDecl *>::iterator
|
|
|
|
TD = SemaRef.LocallyScopedExternalDecls.begin(),
|
|
|
|
TDEnd = SemaRef.LocallyScopedExternalDecls.end();
|
|
|
|
TD != TDEnd; ++TD)
|
|
|
|
AddDeclRef(TD->second, LocallyScopedExternalDecls);
|
|
|
|
|
2009-04-10 06:27:44 +08:00
|
|
|
// Write the remaining PCH contents.
|
2009-04-18 13:55:16 +08:00
|
|
|
RecordData Record;
|
2009-04-26 02:35:21 +08:00
|
|
|
Stream.EnterSubblock(pch::PCH_BLOCK_ID, 4);
|
2009-04-11 05:16:55 +08:00
|
|
|
WriteTargetTriple(Context.Target);
|
2009-04-11 04:39:37 +08:00
|
|
|
WriteLanguageOptions(Context.getLangOptions());
|
2009-04-26 08:07:37 +08:00
|
|
|
WriteSourceManagerBlock(Context.getSourceManager(), PP);
|
2009-04-11 01:15:23 +08:00
|
|
|
WritePreprocessor(PP);
|
2009-04-26 11:49:13 +08:00
|
|
|
|
|
|
|
// Keep writing types and declarations until all types and
|
|
|
|
// declarations have been written.
|
|
|
|
do {
|
|
|
|
if (!DeclsToEmit.empty())
|
|
|
|
WriteDeclsBlock(Context);
|
|
|
|
if (!TypesToEmit.empty())
|
|
|
|
WriteTypesBlock(Context);
|
|
|
|
} while (!(DeclsToEmit.empty() && TypesToEmit.empty()));
|
|
|
|
|
2009-04-25 05:10:55 +08:00
|
|
|
WriteMethodPool(SemaRef);
|
2009-04-22 07:56:24 +08:00
|
|
|
WriteIdentifierTable(PP);
|
2009-04-26 02:35:21 +08:00
|
|
|
|
|
|
|
// Write the type offsets array
|
|
|
|
BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(pch::TYPE_OFFSET));
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of types
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // types block
|
|
|
|
unsigned TypeOffsetAbbrev = Stream.EmitAbbrev(Abbrev);
|
|
|
|
Record.clear();
|
|
|
|
Record.push_back(pch::TYPE_OFFSET);
|
|
|
|
Record.push_back(TypeOffsets.size());
|
|
|
|
Stream.EmitRecordWithBlob(TypeOffsetAbbrev, Record,
|
|
|
|
(const char *)&TypeOffsets.front(),
|
|
|
|
TypeOffsets.size() * sizeof(uint64_t));
|
|
|
|
|
|
|
|
// Write the declaration offsets array
|
|
|
|
Abbrev = new BitCodeAbbrev();
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(pch::DECL_OFFSET));
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of declarations
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // declarations block
|
|
|
|
unsigned DeclOffsetAbbrev = Stream.EmitAbbrev(Abbrev);
|
|
|
|
Record.clear();
|
|
|
|
Record.push_back(pch::DECL_OFFSET);
|
|
|
|
Record.push_back(DeclOffsets.size());
|
|
|
|
Stream.EmitRecordWithBlob(DeclOffsetAbbrev, Record,
|
|
|
|
(const char *)&DeclOffsets.front(),
|
|
|
|
DeclOffsets.size() * sizeof(uint64_t));
|
2009-04-18 13:55:16 +08:00
|
|
|
|
|
|
|
// Write the record of special types.
|
|
|
|
Record.clear();
|
|
|
|
AddTypeRef(Context.getBuiltinVaListType(), Record);
|
2009-04-24 06:29:11 +08:00
|
|
|
AddTypeRef(Context.getObjCIdType(), Record);
|
|
|
|
AddTypeRef(Context.getObjCSelType(), Record);
|
|
|
|
AddTypeRef(Context.getObjCProtoType(), Record);
|
|
|
|
AddTypeRef(Context.getObjCClassType(), Record);
|
|
|
|
AddTypeRef(Context.getRawCFConstantStringType(), Record);
|
|
|
|
AddTypeRef(Context.getRawObjCFastEnumerationStateType(), Record);
|
2009-04-18 13:55:16 +08:00
|
|
|
Stream.EmitRecord(pch::SPECIAL_TYPES, Record);
|
|
|
|
|
2009-04-23 06:02:47 +08:00
|
|
|
// Write the record containing external, unnamed definitions.
|
2009-04-14 08:24:19 +08:00
|
|
|
if (!ExternalDefinitions.empty())
|
2009-04-17 06:23:12 +08:00
|
|
|
Stream.EmitRecord(pch::EXTERNAL_DEFINITIONS, ExternalDefinitions);
|
2009-04-23 06:02:47 +08:00
|
|
|
|
|
|
|
// Write the record containing tentative definitions.
|
|
|
|
if (!TentativeDefinitions.empty())
|
|
|
|
Stream.EmitRecord(pch::TENTATIVE_DEFINITIONS, TentativeDefinitions);
|
2009-04-23 06:18:58 +08:00
|
|
|
|
|
|
|
// Write the record containing locally-scoped external definitions.
|
|
|
|
if (!LocallyScopedExternalDecls.empty())
|
|
|
|
Stream.EmitRecord(pch::LOCALLY_SCOPED_EXTERNAL_DECLS,
|
|
|
|
LocallyScopedExternalDecls);
|
2009-04-18 06:13:46 +08:00
|
|
|
|
|
|
|
// Some simple statistics
|
2009-04-18 13:55:16 +08:00
|
|
|
Record.clear();
|
2009-04-18 06:13:46 +08:00
|
|
|
Record.push_back(NumStatements);
|
2009-04-22 07:56:24 +08:00
|
|
|
Record.push_back(NumMacros);
|
2009-04-23 06:34:57 +08:00
|
|
|
Record.push_back(NumLexicalDeclContexts);
|
|
|
|
Record.push_back(NumVisibleDeclContexts);
|
2009-04-18 06:13:46 +08:00
|
|
|
Stream.EmitRecord(pch::STATISTICS, Record);
|
2009-04-17 06:23:12 +08:00
|
|
|
Stream.ExitBlock();
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
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]);
|
|
|
|
}
|
|
|
|
|
2009-04-14 02:14:40 +08:00
|
|
|
void PCHWriter::AddAPSInt(const llvm::APSInt &Value, RecordData &Record) {
|
|
|
|
Record.push_back(Value.isUnsigned());
|
|
|
|
AddAPInt(Value, Record);
|
|
|
|
}
|
|
|
|
|
2009-04-15 05:55:33 +08:00
|
|
|
void PCHWriter::AddAPFloat(const llvm::APFloat &Value, RecordData &Record) {
|
|
|
|
AddAPInt(Value.bitcastToAPInt(), Record);
|
|
|
|
}
|
|
|
|
|
2009-04-10 06:27:44 +08:00
|
|
|
void PCHWriter::AddIdentifierRef(const IdentifierInfo *II, RecordData &Record) {
|
2009-04-23 02:49:13 +08:00
|
|
|
Record.push_back(getIdentifierRef(II));
|
|
|
|
}
|
|
|
|
|
|
|
|
pch::IdentID PCHWriter::getIdentifierRef(const IdentifierInfo *II) {
|
|
|
|
if (II == 0)
|
|
|
|
return 0;
|
2009-04-11 08:14:32 +08:00
|
|
|
|
|
|
|
pch::IdentID &ID = IdentifierIDs[II];
|
|
|
|
if (ID == 0)
|
|
|
|
ID = IdentifierIDs.size();
|
2009-04-23 02:49:13 +08:00
|
|
|
return ID;
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
|
|
|
|
2009-04-23 18:39:46 +08:00
|
|
|
void PCHWriter::AddSelectorRef(const Selector SelRef, RecordData &Record) {
|
|
|
|
if (SelRef.getAsOpaquePtr() == 0) {
|
|
|
|
Record.push_back(0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
pch::SelectorID &SID = SelectorIDs[SelRef];
|
|
|
|
if (SID == 0) {
|
|
|
|
SID = SelectorIDs.size();
|
|
|
|
SelVector.push_back(SelRef);
|
|
|
|
}
|
|
|
|
Record.push_back(SID);
|
|
|
|
}
|
|
|
|
|
2009-04-10 06:27:44 +08:00
|
|
|
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())) {
|
2009-04-11 07:10:45 +08:00
|
|
|
pch::TypeID ID = 0;
|
2009-04-10 06:27:44 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2009-04-11 01:25:41 +08:00
|
|
|
pch::TypeID &ID = TypeIDs[T.getTypePtr()];
|
2009-04-26 11:49:13 +08:00
|
|
|
if (ID == 0) {
|
|
|
|
// We haven't seen this type before. Assign it a new ID and put it
|
|
|
|
// into the queu of types to emit.
|
2009-04-10 06:27:44 +08:00
|
|
|
ID = NextTypeID++;
|
2009-04-26 11:49:13 +08:00
|
|
|
TypesToEmit.push(T.getTypePtr());
|
|
|
|
}
|
2009-04-10 06:27:44 +08:00
|
|
|
|
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
2009-04-11 01:25:41 +08:00
|
|
|
pch::DeclID &ID = DeclIDs[D];
|
2009-04-10 06:27:44 +08:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2009-04-21 04:36:09 +08:00
|
|
|
pch::DeclID PCHWriter::getDeclID(const Decl *D) {
|
|
|
|
if (D == 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
assert(DeclIDs.find(D) != DeclIDs.end() && "Declaration not emitted!");
|
|
|
|
return DeclIDs[D];
|
|
|
|
}
|
|
|
|
|
2009-04-10 06:27:44 +08:00
|
|
|
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:
|
2009-04-23 18:39:46 +08:00
|
|
|
AddSelectorRef(Name.getObjCSelector(), Record);
|
2009-04-10 06:27:44 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
2009-04-15 05:18:50 +08:00
|
|
|
|
2009-04-17 06:23:12 +08:00
|
|
|
/// \brief Write the given substatement or subexpression to the
|
|
|
|
/// bitstream.
|
|
|
|
void PCHWriter::WriteSubStmt(Stmt *S) {
|
2009-04-15 07:32:43 +08:00
|
|
|
RecordData Record;
|
|
|
|
PCHStmtWriter Writer(*this, Record);
|
2009-04-18 06:13:46 +08:00
|
|
|
++NumStatements;
|
2009-04-15 07:32:43 +08:00
|
|
|
|
2009-04-17 06:23:12 +08:00
|
|
|
if (!S) {
|
|
|
|
Stream.EmitRecord(pch::STMT_NULL_PTR, Record);
|
2009-04-15 07:32:43 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-04-17 06:23:12 +08:00
|
|
|
Writer.Code = pch::STMT_NULL_PTR;
|
|
|
|
Writer.Visit(S);
|
|
|
|
assert(Writer.Code != pch::STMT_NULL_PTR &&
|
2009-04-15 07:32:43 +08:00
|
|
|
"Unhandled expression writing PCH file");
|
2009-04-17 06:23:12 +08:00
|
|
|
Stream.EmitRecord(Writer.Code, Record);
|
2009-04-15 07:32:43 +08:00
|
|
|
}
|
|
|
|
|
2009-04-17 06:23:12 +08:00
|
|
|
/// \brief Flush all of the statements that have been added to the
|
|
|
|
/// queue via AddStmt().
|
|
|
|
void PCHWriter::FlushStmts() {
|
2009-04-15 05:18:50 +08:00
|
|
|
RecordData Record;
|
|
|
|
PCHStmtWriter Writer(*this, Record);
|
|
|
|
|
2009-04-17 06:23:12 +08:00
|
|
|
for (unsigned I = 0, N = StmtsToEmit.size(); I != N; ++I) {
|
2009-04-18 06:13:46 +08:00
|
|
|
++NumStatements;
|
2009-04-17 06:23:12 +08:00
|
|
|
Stmt *S = StmtsToEmit[I];
|
2009-04-15 07:32:43 +08:00
|
|
|
|
2009-04-17 06:23:12 +08:00
|
|
|
if (!S) {
|
|
|
|
Stream.EmitRecord(pch::STMT_NULL_PTR, Record);
|
2009-04-15 05:18:50 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2009-04-17 06:23:12 +08:00
|
|
|
Writer.Code = pch::STMT_NULL_PTR;
|
|
|
|
Writer.Visit(S);
|
|
|
|
assert(Writer.Code != pch::STMT_NULL_PTR &&
|
2009-04-15 05:18:50 +08:00
|
|
|
"Unhandled expression writing PCH file");
|
2009-04-17 06:23:12 +08:00
|
|
|
Stream.EmitRecord(Writer.Code, Record);
|
2009-04-15 07:32:43 +08:00
|
|
|
|
2009-04-17 06:23:12 +08:00
|
|
|
assert(N == StmtsToEmit.size() &&
|
|
|
|
"Substatement writen via AddStmt rather than WriteSubStmt!");
|
2009-04-15 07:32:43 +08:00
|
|
|
|
|
|
|
// Note that we are at the end of a full expression. Any
|
|
|
|
// expression records that follow this one are part of a different
|
|
|
|
// expression.
|
|
|
|
Record.clear();
|
2009-04-17 06:23:12 +08:00
|
|
|
Stream.EmitRecord(pch::STMT_STOP, Record);
|
2009-04-15 05:18:50 +08:00
|
|
|
}
|
2009-04-15 07:32:43 +08:00
|
|
|
|
2009-04-17 06:23:12 +08:00
|
|
|
StmtsToEmit.clear();
|
2009-04-18 00:34:57 +08:00
|
|
|
SwitchCaseIDs.clear();
|
2009-04-15 05:18:50 +08:00
|
|
|
}
|
2009-04-17 08:04:06 +08:00
|
|
|
|
|
|
|
unsigned PCHWriter::RecordSwitchCaseID(SwitchCase *S) {
|
|
|
|
assert(SwitchCaseIDs.find(S) == SwitchCaseIDs.end() &&
|
|
|
|
"SwitchCase recorded twice");
|
|
|
|
unsigned NextID = SwitchCaseIDs.size();
|
|
|
|
SwitchCaseIDs[S] = NextID;
|
|
|
|
return NextID;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned PCHWriter::getSwitchCaseID(SwitchCase *S) {
|
|
|
|
assert(SwitchCaseIDs.find(S) != SwitchCaseIDs.end() &&
|
|
|
|
"SwitchCase hasn't been seen yet");
|
|
|
|
return SwitchCaseIDs[S];
|
|
|
|
}
|
2009-04-18 02:18:49 +08:00
|
|
|
|
|
|
|
/// \brief Retrieve the ID for the given label statement, which may
|
|
|
|
/// or may not have been emitted yet.
|
|
|
|
unsigned PCHWriter::GetLabelID(LabelStmt *S) {
|
|
|
|
std::map<LabelStmt *, unsigned>::iterator Pos = LabelIDs.find(S);
|
|
|
|
if (Pos != LabelIDs.end())
|
|
|
|
return Pos->second;
|
|
|
|
|
|
|
|
unsigned NextID = LabelIDs.size();
|
|
|
|
LabelIDs[S] = NextID;
|
|
|
|
return NextID;
|
|
|
|
}
|