blob: 7402961ae83c57348bc6732a8d3fe23a56309d16 [file] [log] [blame]
//===--- ASTWriter.cpp - AST File Writer ----------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the ASTWriter class, which writes AST files.
//
//===----------------------------------------------------------------------===//
#include "clang/Serialization/ASTWriter.h"
#include "ASTCommon.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclContextInternals.h"
#include "clang/AST/DeclFriend.h"
#include "clang/AST/DeclLookups.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/Type.h"
#include "clang/AST/TypeLocVisitor.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/FileSystemStatCache.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/SourceManagerInternals.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/TargetOptions.h"
#include "clang/Basic/Version.h"
#include "clang/Basic/VersionTuple.h"
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/HeaderSearchOptions.h"
#include "clang/Lex/MacroInfo.h"
#include "clang/Lex/PreprocessingRecord.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/PreprocessorOptions.h"
#include "clang/Sema/IdentifierResolver.h"
#include "clang/Sema/Sema.h"
#include "clang/Serialization/ASTReader.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Bitcode/BitstreamWriter.h"
#include "llvm/Support/EndianStream.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/OnDiskHashTable.h"
#include "llvm/Support/Path.h"
#include <algorithm>
#include <cstdio>
#include <string.h>
#include <utility>
using namespace clang;
using namespace clang::serialization;
template <typename T, typename Allocator>
static StringRef data(const std::vector<T, Allocator> &v) {
if (v.empty()) return StringRef();
return StringRef(reinterpret_cast<const char*>(&v[0]),
sizeof(T) * v.size());
}
template <typename T>
static StringRef data(const SmallVectorImpl<T> &v) {
return StringRef(reinterpret_cast<const char*>(v.data()),
sizeof(T) * v.size());
}
//===----------------------------------------------------------------------===//
// Type serialization
//===----------------------------------------------------------------------===//
namespace {
class ASTTypeWriter {
ASTWriter &Writer;
ASTWriter::RecordDataImpl &Record;
public:
/// \brief Type code that corresponds to the record generated.
TypeCode Code;
ASTTypeWriter(ASTWriter &Writer, ASTWriter::RecordDataImpl &Record)
: Writer(Writer), Record(Record), Code(TYPE_EXT_QUAL) { }
void VisitArrayType(const ArrayType *T);
void VisitFunctionType(const FunctionType *T);
void VisitTagType(const TagType *T);
#define TYPE(Class, Base) void Visit##Class##Type(const Class##Type *T);
#define ABSTRACT_TYPE(Class, Base)
#include "clang/AST/TypeNodes.def"
};
}
void ASTTypeWriter::VisitBuiltinType(const BuiltinType *T) {
llvm_unreachable("Built-in types are never serialized");
}
void ASTTypeWriter::VisitComplexType(const ComplexType *T) {
Writer.AddTypeRef(T->getElementType(), Record);
Code = TYPE_COMPLEX;
}
void ASTTypeWriter::VisitPointerType(const PointerType *T) {
Writer.AddTypeRef(T->getPointeeType(), Record);
Code = TYPE_POINTER;
}
void ASTTypeWriter::VisitDecayedType(const DecayedType *T) {
Writer.AddTypeRef(T->getOriginalType(), Record);
Code = TYPE_DECAYED;
}
void ASTTypeWriter::VisitAdjustedType(const AdjustedType *T) {
Writer.AddTypeRef(T->getOriginalType(), Record);
Writer.AddTypeRef(T->getAdjustedType(), Record);
Code = TYPE_ADJUSTED;
}
void ASTTypeWriter::VisitBlockPointerType(const BlockPointerType *T) {
Writer.AddTypeRef(T->getPointeeType(), Record);
Code = TYPE_BLOCK_POINTER;
}
void ASTTypeWriter::VisitLValueReferenceType(const LValueReferenceType *T) {
Writer.AddTypeRef(T->getPointeeTypeAsWritten(), Record);
Record.push_back(T->isSpelledAsLValue());
Code = TYPE_LVALUE_REFERENCE;
}
void ASTTypeWriter::VisitRValueReferenceType(const RValueReferenceType *T) {
Writer.AddTypeRef(T->getPointeeTypeAsWritten(), Record);
Code = TYPE_RVALUE_REFERENCE;
}
void ASTTypeWriter::VisitMemberPointerType(const MemberPointerType *T) {
Writer.AddTypeRef(T->getPointeeType(), Record);
Writer.AddTypeRef(QualType(T->getClass(), 0), Record);
Code = TYPE_MEMBER_POINTER;
}
void ASTTypeWriter::VisitArrayType(const ArrayType *T) {
Writer.AddTypeRef(T->getElementType(), Record);
Record.push_back(T->getSizeModifier()); // FIXME: stable values
Record.push_back(T->getIndexTypeCVRQualifiers()); // FIXME: stable values
}
void ASTTypeWriter::VisitConstantArrayType(const ConstantArrayType *T) {
VisitArrayType(T);
Writer.AddAPInt(T->getSize(), Record);
Code = TYPE_CONSTANT_ARRAY;
}
void ASTTypeWriter::VisitIncompleteArrayType(const IncompleteArrayType *T) {
VisitArrayType(T);
Code = TYPE_INCOMPLETE_ARRAY;
}
void ASTTypeWriter::VisitVariableArrayType(const VariableArrayType *T) {
VisitArrayType(T);
Writer.AddSourceLocation(T->getLBracketLoc(), Record);
Writer.AddSourceLocation(T->getRBracketLoc(), Record);
Writer.AddStmt(T->getSizeExpr());
Code = TYPE_VARIABLE_ARRAY;
}
void ASTTypeWriter::VisitVectorType(const VectorType *T) {
Writer.AddTypeRef(T->getElementType(), Record);
Record.push_back(T->getNumElements());
Record.push_back(T->getVectorKind());
Code = TYPE_VECTOR;
}
void ASTTypeWriter::VisitExtVectorType(const ExtVectorType *T) {
VisitVectorType(T);
Code = TYPE_EXT_VECTOR;
}
void ASTTypeWriter::VisitFunctionType(const FunctionType *T) {
Writer.AddTypeRef(T->getReturnType(), Record);
FunctionType::ExtInfo C = T->getExtInfo();
Record.push_back(C.getNoReturn());
Record.push_back(C.getHasRegParm());
Record.push_back(C.getRegParm());
// FIXME: need to stabilize encoding of calling convention...
Record.push_back(C.getCC());
Record.push_back(C.getProducesResult());
}
void ASTTypeWriter::VisitFunctionNoProtoType(const FunctionNoProtoType *T) {
VisitFunctionType(T);
Code = TYPE_FUNCTION_NO_PROTO;
}
static void addExceptionSpec(ASTWriter &Writer, const FunctionProtoType *T,
ASTWriter::RecordDataImpl &Record) {
Record.push_back(T->getExceptionSpecType());
if (T->getExceptionSpecType() == EST_Dynamic) {
Record.push_back(T->getNumExceptions());
for (unsigned I = 0, N = T->getNumExceptions(); I != N; ++I)
Writer.AddTypeRef(T->getExceptionType(I), Record);
} else if (T->getExceptionSpecType() == EST_ComputedNoexcept) {
Writer.AddStmt(T->getNoexceptExpr());
} else if (T->getExceptionSpecType() == EST_Uninstantiated) {
Writer.AddDeclRef(T->getExceptionSpecDecl(), Record);
Writer.AddDeclRef(T->getExceptionSpecTemplate(), Record);
} else if (T->getExceptionSpecType() == EST_Unevaluated) {
Writer.AddDeclRef(T->getExceptionSpecDecl(), Record);
}
}
void ASTTypeWriter::VisitFunctionProtoType(const FunctionProtoType *T) {
VisitFunctionType(T);
Record.push_back(T->getNumParams());
for (unsigned I = 0, N = T->getNumParams(); I != N; ++I)
Writer.AddTypeRef(T->getParamType(I), Record);
Record.push_back(T->isVariadic());
Record.push_back(T->hasTrailingReturn());
Record.push_back(T->getTypeQuals());
Record.push_back(static_cast<unsigned>(T->getRefQualifier()));
addExceptionSpec(Writer, T, Record);
Code = TYPE_FUNCTION_PROTO;
}
void ASTTypeWriter::VisitUnresolvedUsingType(const UnresolvedUsingType *T) {
Writer.AddDeclRef(T->getDecl(), Record);
Code = TYPE_UNRESOLVED_USING;
}
void ASTTypeWriter::VisitTypedefType(const TypedefType *T) {
Writer.AddDeclRef(T->getDecl(), Record);
assert(!T->isCanonicalUnqualified() && "Invalid typedef ?");
Writer.AddTypeRef(T->getCanonicalTypeInternal(), Record);
Code = TYPE_TYPEDEF;
}
void ASTTypeWriter::VisitTypeOfExprType(const TypeOfExprType *T) {
Writer.AddStmt(T->getUnderlyingExpr());
Code = TYPE_TYPEOF_EXPR;
}
void ASTTypeWriter::VisitTypeOfType(const TypeOfType *T) {
Writer.AddTypeRef(T->getUnderlyingType(), Record);
Code = TYPE_TYPEOF;
}
void ASTTypeWriter::VisitDecltypeType(const DecltypeType *T) {
Writer.AddTypeRef(T->getUnderlyingType(), Record);
Writer.AddStmt(T->getUnderlyingExpr());
Code = TYPE_DECLTYPE;
}
void ASTTypeWriter::VisitUnaryTransformType(const UnaryTransformType *T) {
Writer.AddTypeRef(T->getBaseType(), Record);
Writer.AddTypeRef(T->getUnderlyingType(), Record);
Record.push_back(T->getUTTKind());
Code = TYPE_UNARY_TRANSFORM;
}
void ASTTypeWriter::VisitAutoType(const AutoType *T) {
Writer.AddTypeRef(T->getDeducedType(), Record);
Record.push_back(T->isDecltypeAuto());
if (T->getDeducedType().isNull())
Record.push_back(T->isDependentType());
Code = TYPE_AUTO;
}
void ASTTypeWriter::VisitTagType(const TagType *T) {
Record.push_back(T->isDependentType());
Writer.AddDeclRef(T->getDecl()->getCanonicalDecl(), Record);
assert(!T->isBeingDefined() &&
"Cannot serialize in the middle of a type definition");
}
void ASTTypeWriter::VisitRecordType(const RecordType *T) {
VisitTagType(T);
Code = TYPE_RECORD;
}
void ASTTypeWriter::VisitEnumType(const EnumType *T) {
VisitTagType(T);
Code = TYPE_ENUM;
}
void ASTTypeWriter::VisitAttributedType(const AttributedType *T) {
Writer.AddTypeRef(T->getModifiedType(), Record);
Writer.AddTypeRef(T->getEquivalentType(), Record);
Record.push_back(T->getAttrKind());
Code = TYPE_ATTRIBUTED;
}
void
ASTTypeWriter::VisitSubstTemplateTypeParmType(
const SubstTemplateTypeParmType *T) {
Writer.AddTypeRef(QualType(T->getReplacedParameter(), 0), Record);
Writer.AddTypeRef(T->getReplacementType(), Record);
Code = TYPE_SUBST_TEMPLATE_TYPE_PARM;
}
void
ASTTypeWriter::VisitSubstTemplateTypeParmPackType(
const SubstTemplateTypeParmPackType *T) {
Writer.AddTypeRef(QualType(T->getReplacedParameter(), 0), Record);
Writer.AddTemplateArgument(T->getArgumentPack(), Record);
Code = TYPE_SUBST_TEMPLATE_TYPE_PARM_PACK;
}
void
ASTTypeWriter::VisitTemplateSpecializationType(
const TemplateSpecializationType *T) {
Record.push_back(T->isDependentType());
Writer.AddTemplateName(T->getTemplateName(), Record);
Record.push_back(T->getNumArgs());
for (TemplateSpecializationType::iterator ArgI = T->begin(), ArgE = T->end();
ArgI != ArgE; ++ArgI)
Writer.AddTemplateArgument(*ArgI, Record);
Writer.AddTypeRef(T->isTypeAlias() ? T->getAliasedType() :
T->isCanonicalUnqualified() ? QualType()
: T->getCanonicalTypeInternal(),
Record);
Code = TYPE_TEMPLATE_SPECIALIZATION;
}
void
ASTTypeWriter::VisitDependentSizedArrayType(const DependentSizedArrayType *T) {
VisitArrayType(T);
Writer.AddStmt(T->getSizeExpr());
Writer.AddSourceRange(T->getBracketsRange(), Record);
Code = TYPE_DEPENDENT_SIZED_ARRAY;
}
void
ASTTypeWriter::VisitDependentSizedExtVectorType(
const DependentSizedExtVectorType *T) {
// FIXME: Serialize this type (C++ only)
llvm_unreachable("Cannot serialize dependent sized extended vector types");
}
void
ASTTypeWriter::VisitTemplateTypeParmType(const TemplateTypeParmType *T) {
Record.push_back(T->getDepth());
Record.push_back(T->getIndex());
Record.push_back(T->isParameterPack());
Writer.AddDeclRef(T->getDecl(), Record);
Code = TYPE_TEMPLATE_TYPE_PARM;
}
void
ASTTypeWriter::VisitDependentNameType(const DependentNameType *T) {
Record.push_back(T->getKeyword());
Writer.AddNestedNameSpecifier(T->getQualifier(), Record);
Writer.AddIdentifierRef(T->getIdentifier(), Record);
Writer.AddTypeRef(T->isCanonicalUnqualified() ? QualType()
: T->getCanonicalTypeInternal(),
Record);
Code = TYPE_DEPENDENT_NAME;
}
void
ASTTypeWriter::VisitDependentTemplateSpecializationType(
const DependentTemplateSpecializationType *T) {
Record.push_back(T->getKeyword());
Writer.AddNestedNameSpecifier(T->getQualifier(), Record);
Writer.AddIdentifierRef(T->getIdentifier(), Record);
Record.push_back(T->getNumArgs());
for (DependentTemplateSpecializationType::iterator
I = T->begin(), E = T->end(); I != E; ++I)
Writer.AddTemplateArgument(*I, Record);
Code = TYPE_DEPENDENT_TEMPLATE_SPECIALIZATION;
}
void ASTTypeWriter::VisitPackExpansionType(const PackExpansionType *T) {
Writer.AddTypeRef(T->getPattern(), Record);
if (Optional<unsigned> NumExpansions = T->getNumExpansions())
Record.push_back(*NumExpansions + 1);
else
Record.push_back(0);
Code = TYPE_PACK_EXPANSION;
}
void ASTTypeWriter::VisitParenType(const ParenType *T) {
Writer.AddTypeRef(T->getInnerType(), Record);
Code = TYPE_PAREN;
}
void ASTTypeWriter::VisitElaboratedType(const ElaboratedType *T) {
Record.push_back(T->getKeyword());
Writer.AddNestedNameSpecifier(T->getQualifier(), Record);
Writer.AddTypeRef(T->getNamedType(), Record);
Code = TYPE_ELABORATED;
}
void ASTTypeWriter::VisitInjectedClassNameType(const InjectedClassNameType *T) {
Writer.AddDeclRef(T->getDecl()->getCanonicalDecl(), Record);
Writer.AddTypeRef(T->getInjectedSpecializationType(), Record);
Code = TYPE_INJECTED_CLASS_NAME;
}
void ASTTypeWriter::VisitObjCInterfaceType(const ObjCInterfaceType *T) {
Writer.AddDeclRef(T->getDecl()->getCanonicalDecl(), Record);
Code = TYPE_OBJC_INTERFACE;
}
void ASTTypeWriter::VisitObjCObjectType(const ObjCObjectType *T) {
Writer.AddTypeRef(T->getBaseType(), Record);
Record.push_back(T->getNumProtocols());
for (const auto *I : T->quals())
Writer.AddDeclRef(I, Record);
Code = TYPE_OBJC_OBJECT;
}
void
ASTTypeWriter::VisitObjCObjectPointerType(const ObjCObjectPointerType *T) {
Writer.AddTypeRef(T->getPointeeType(), Record);
Code = TYPE_OBJC_OBJECT_POINTER;
}
void
ASTTypeWriter::VisitAtomicType(const AtomicType *T) {
Writer.AddTypeRef(T->getValueType(), Record);
Code = TYPE_ATOMIC;
}
namespace {
class TypeLocWriter : public TypeLocVisitor<TypeLocWriter> {
ASTWriter &Writer;
ASTWriter::RecordDataImpl &Record;
public:
TypeLocWriter(ASTWriter &Writer, ASTWriter::RecordDataImpl &Record)
: Writer(Writer), Record(Record) { }
#define ABSTRACT_TYPELOC(CLASS, PARENT)
#define TYPELOC(CLASS, PARENT) \
void Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc);
#include "clang/AST/TypeLocNodes.def"
void VisitArrayTypeLoc(ArrayTypeLoc TyLoc);
void VisitFunctionTypeLoc(FunctionTypeLoc TyLoc);
};
}
void TypeLocWriter::VisitQualifiedTypeLoc(QualifiedTypeLoc TL) {
// nothing to do
}
void TypeLocWriter::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) {
Writer.AddSourceLocation(TL.getBuiltinLoc(), Record);
if (TL.needsExtraLocalData()) {
Record.push_back(TL.getWrittenTypeSpec());
Record.push_back(TL.getWrittenSignSpec());
Record.push_back(TL.getWrittenWidthSpec());
Record.push_back(TL.hasModeAttr());
}
}
void TypeLocWriter::VisitComplexTypeLoc(ComplexTypeLoc TL) {
Writer.AddSourceLocation(TL.getNameLoc(), Record);
}
void TypeLocWriter::VisitPointerTypeLoc(PointerTypeLoc TL) {
Writer.AddSourceLocation(TL.getStarLoc(), Record);
}
void TypeLocWriter::VisitDecayedTypeLoc(DecayedTypeLoc TL) {
// nothing to do
}
void TypeLocWriter::VisitAdjustedTypeLoc(AdjustedTypeLoc TL) {
// nothing to do
}
void TypeLocWriter::VisitBlockPointerTypeLoc(BlockPointerTypeLoc TL) {
Writer.AddSourceLocation(TL.getCaretLoc(), Record);
}
void TypeLocWriter::VisitLValueReferenceTypeLoc(LValueReferenceTypeLoc TL) {
Writer.AddSourceLocation(TL.getAmpLoc(), Record);
}
void TypeLocWriter::VisitRValueReferenceTypeLoc(RValueReferenceTypeLoc TL) {
Writer.AddSourceLocation(TL.getAmpAmpLoc(), Record);
}
void TypeLocWriter::VisitMemberPointerTypeLoc(MemberPointerTypeLoc TL) {
Writer.AddSourceLocation(TL.getStarLoc(), Record);
Writer.AddTypeSourceInfo(TL.getClassTInfo(), Record);
}
void TypeLocWriter::VisitArrayTypeLoc(ArrayTypeLoc TL) {
Writer.AddSourceLocation(TL.getLBracketLoc(), Record);
Writer.AddSourceLocation(TL.getRBracketLoc(), Record);
Record.push_back(TL.getSizeExpr() ? 1 : 0);
if (TL.getSizeExpr())
Writer.AddStmt(TL.getSizeExpr());
}
void TypeLocWriter::VisitConstantArrayTypeLoc(ConstantArrayTypeLoc TL) {
VisitArrayTypeLoc(TL);
}
void TypeLocWriter::VisitIncompleteArrayTypeLoc(IncompleteArrayTypeLoc TL) {
VisitArrayTypeLoc(TL);
}
void TypeLocWriter::VisitVariableArrayTypeLoc(VariableArrayTypeLoc TL) {
VisitArrayTypeLoc(TL);
}
void TypeLocWriter::VisitDependentSizedArrayTypeLoc(
DependentSizedArrayTypeLoc TL) {
VisitArrayTypeLoc(TL);
}
void TypeLocWriter::VisitDependentSizedExtVectorTypeLoc(
DependentSizedExtVectorTypeLoc TL) {
Writer.AddSourceLocation(TL.getNameLoc(), Record);
}
void TypeLocWriter::VisitVectorTypeLoc(VectorTypeLoc TL) {
Writer.AddSourceLocation(TL.getNameLoc(), Record);
}
void TypeLocWriter::VisitExtVectorTypeLoc(ExtVectorTypeLoc TL) {
Writer.AddSourceLocation(TL.getNameLoc(), Record);
}
void TypeLocWriter::VisitFunctionTypeLoc(FunctionTypeLoc TL) {
Writer.AddSourceLocation(TL.getLocalRangeBegin(), Record);
Writer.AddSourceLocation(TL.getLParenLoc(), Record);
Writer.AddSourceLocation(TL.getRParenLoc(), Record);
Writer.AddSourceLocation(TL.getLocalRangeEnd(), Record);
for (unsigned i = 0, e = TL.getNumParams(); i != e; ++i)
Writer.AddDeclRef(TL.getParam(i), Record);
}
void TypeLocWriter::VisitFunctionProtoTypeLoc(FunctionProtoTypeLoc TL) {
VisitFunctionTypeLoc(TL);
}
void TypeLocWriter::VisitFunctionNoProtoTypeLoc(FunctionNoProtoTypeLoc TL) {
VisitFunctionTypeLoc(TL);
}
void TypeLocWriter::VisitUnresolvedUsingTypeLoc(UnresolvedUsingTypeLoc TL) {
Writer.AddSourceLocation(TL.getNameLoc(), Record);
}
void TypeLocWriter::VisitTypedefTypeLoc(TypedefTypeLoc TL) {
Writer.AddSourceLocation(TL.getNameLoc(), Record);
}
void TypeLocWriter::VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL) {
Writer.AddSourceLocation(TL.getTypeofLoc(), Record);
Writer.AddSourceLocation(TL.getLParenLoc(), Record);
Writer.AddSourceLocation(TL.getRParenLoc(), Record);
}
void TypeLocWriter::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) {
Writer.AddSourceLocation(TL.getTypeofLoc(), Record);
Writer.AddSourceLocation(TL.getLParenLoc(), Record);
Writer.AddSourceLocation(TL.getRParenLoc(), Record);
Writer.AddTypeSourceInfo(TL.getUnderlyingTInfo(), Record);
}
void TypeLocWriter::VisitDecltypeTypeLoc(DecltypeTypeLoc TL) {
Writer.AddSourceLocation(TL.getNameLoc(), Record);
}
void TypeLocWriter::VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) {
Writer.AddSourceLocation(TL.getKWLoc(), Record);
Writer.AddSourceLocation(TL.getLParenLoc(), Record);
Writer.AddSourceLocation(TL.getRParenLoc(), Record);
Writer.AddTypeSourceInfo(TL.getUnderlyingTInfo(), Record);
}
void TypeLocWriter::VisitAutoTypeLoc(AutoTypeLoc TL) {
Writer.AddSourceLocation(TL.getNameLoc(), Record);
}
void TypeLocWriter::VisitRecordTypeLoc(RecordTypeLoc TL) {
Writer.AddSourceLocation(TL.getNameLoc(), Record);
}
void TypeLocWriter::VisitEnumTypeLoc(EnumTypeLoc TL) {
Writer.AddSourceLocation(TL.getNameLoc(), Record);
}
void TypeLocWriter::VisitAttributedTypeLoc(AttributedTypeLoc TL) {
Writer.AddSourceLocation(TL.getAttrNameLoc(), Record);
if (TL.hasAttrOperand()) {
SourceRange range = TL.getAttrOperandParensRange();
Writer.AddSourceLocation(range.getBegin(), Record);
Writer.AddSourceLocation(range.getEnd(), Record);
}
if (TL.hasAttrExprOperand()) {
Expr *operand = TL.getAttrExprOperand();
Record.push_back(operand ? 1 : 0);
if (operand) Writer.AddStmt(operand);
} else if (TL.hasAttrEnumOperand()) {
Writer.AddSourceLocation(TL.getAttrEnumOperandLoc(), Record);
}
}
void TypeLocWriter::VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) {
Writer.AddSourceLocation(TL.getNameLoc(), Record);
}
void TypeLocWriter::VisitSubstTemplateTypeParmTypeLoc(
SubstTemplateTypeParmTypeLoc TL) {
Writer.AddSourceLocation(TL.getNameLoc(), Record);
}
void TypeLocWriter::VisitSubstTemplateTypeParmPackTypeLoc(
SubstTemplateTypeParmPackTypeLoc TL) {
Writer.AddSourceLocation(TL.getNameLoc(), Record);
}
void TypeLocWriter::VisitTemplateSpecializationTypeLoc(
TemplateSpecializationTypeLoc TL) {
Writer.AddSourceLocation(TL.getTemplateKeywordLoc(), Record);
Writer.AddSourceLocation(TL.getTemplateNameLoc(), Record);
Writer.AddSourceLocation(TL.getLAngleLoc(), Record);
Writer.AddSourceLocation(TL.getRAngleLoc(), Record);
for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i)
Writer.AddTemplateArgumentLocInfo(TL.getArgLoc(i).getArgument().getKind(),
TL.getArgLoc(i).getLocInfo(), Record);
}
void TypeLocWriter::VisitParenTypeLoc(ParenTypeLoc TL) {
Writer.AddSourceLocation(TL.getLParenLoc(), Record);
Writer.AddSourceLocation(TL.getRParenLoc(), Record);
}
void TypeLocWriter::VisitElaboratedTypeLoc(ElaboratedTypeLoc TL) {
Writer.AddSourceLocation(TL.getElaboratedKeywordLoc(), Record);
Writer.AddNestedNameSpecifierLoc(TL.getQualifierLoc(), Record);
}
void TypeLocWriter::VisitInjectedClassNameTypeLoc(InjectedClassNameTypeLoc TL) {
Writer.AddSourceLocation(TL.getNameLoc(), Record);
}
void TypeLocWriter::VisitDependentNameTypeLoc(DependentNameTypeLoc TL) {
Writer.AddSourceLocation(TL.getElaboratedKeywordLoc(), Record);
Writer.AddNestedNameSpecifierLoc(TL.getQualifierLoc(), Record);
Writer.AddSourceLocation(TL.getNameLoc(), Record);
}
void TypeLocWriter::VisitDependentTemplateSpecializationTypeLoc(
DependentTemplateSpecializationTypeLoc TL) {
Writer.AddSourceLocation(TL.getElaboratedKeywordLoc(), Record);
Writer.AddNestedNameSpecifierLoc(TL.getQualifierLoc(), Record);
Writer.AddSourceLocation(TL.getTemplateKeywordLoc(), Record);
Writer.AddSourceLocation(TL.getTemplateNameLoc(), Record);
Writer.AddSourceLocation(TL.getLAngleLoc(), Record);
Writer.AddSourceLocation(TL.getRAngleLoc(), Record);
for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I)
Writer.AddTemplateArgumentLocInfo(TL.getArgLoc(I).getArgument().getKind(),
TL.getArgLoc(I).getLocInfo(), Record);
}
void TypeLocWriter::VisitPackExpansionTypeLoc(PackExpansionTypeLoc TL) {
Writer.AddSourceLocation(TL.getEllipsisLoc(), Record);
}
void TypeLocWriter::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) {
Writer.AddSourceLocation(TL.getNameLoc(), Record);
}
void TypeLocWriter::VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) {
Record.push_back(TL.hasBaseTypeAsWritten());
Writer.AddSourceLocation(TL.getLAngleLoc(), Record);
Writer.AddSourceLocation(TL.getRAngleLoc(), Record);
for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i)
Writer.AddSourceLocation(TL.getProtocolLoc(i), Record);
}
void TypeLocWriter::VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) {
Writer.AddSourceLocation(TL.getStarLoc(), Record);
}
void TypeLocWriter::VisitAtomicTypeLoc(AtomicTypeLoc TL) {
Writer.AddSourceLocation(TL.getKWLoc(), Record);
Writer.AddSourceLocation(TL.getLParenLoc(), Record);
Writer.AddSourceLocation(TL.getRParenLoc(), Record);
}
//===----------------------------------------------------------------------===//
// ASTWriter Implementation
//===----------------------------------------------------------------------===//
static void EmitBlockID(unsigned ID, const char *Name,
llvm::BitstreamWriter &Stream,
ASTWriter::RecordDataImpl &Record) {
Record.clear();
Record.push_back(ID);
Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETBID, Record);
// Emit the block name if present.
if (Name == 0 || Name[0] == 0) return;
Record.clear();
while (*Name)
Record.push_back(*Name++);
Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_BLOCKNAME, Record);
}
static void EmitRecordID(unsigned ID, const char *Name,
llvm::BitstreamWriter &Stream,
ASTWriter::RecordDataImpl &Record) {
Record.clear();
Record.push_back(ID);
while (*Name)
Record.push_back(*Name++);
Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, Record);
}
static void AddStmtsExprs(llvm::BitstreamWriter &Stream,
ASTWriter::RecordDataImpl &Record) {
#define RECORD(X) EmitRecordID(X, #X, Stream, Record)
RECORD(STMT_STOP);
RECORD(STMT_NULL_PTR);
RECORD(STMT_NULL);
RECORD(STMT_COMPOUND);
RECORD(STMT_CASE);
RECORD(STMT_DEFAULT);
RECORD(STMT_LABEL);
RECORD(STMT_ATTRIBUTED);
RECORD(STMT_IF);
RECORD(STMT_SWITCH);
RECORD(STMT_WHILE);
RECORD(STMT_DO);
RECORD(STMT_FOR);
RECORD(STMT_GOTO);
RECORD(STMT_INDIRECT_GOTO);
RECORD(STMT_CONTINUE);
RECORD(STMT_BREAK);
RECORD(STMT_RETURN);
RECORD(STMT_DECL);
RECORD(STMT_GCCASM);
RECORD(STMT_MSASM);
RECORD(EXPR_PREDEFINED);
RECORD(EXPR_DECL_REF);
RECORD(EXPR_INTEGER_LITERAL);
RECORD(EXPR_FLOATING_LITERAL);
RECORD(EXPR_IMAGINARY_LITERAL);
RECORD(EXPR_STRING_LITERAL);
RECORD(EXPR_CHARACTER_LITERAL);
RECORD(EXPR_PAREN);
RECORD(EXPR_UNARY_OPERATOR);
RECORD(EXPR_SIZEOF_ALIGN_OF);
RECORD(EXPR_ARRAY_SUBSCRIPT);
RECORD(EXPR_CALL);
RECORD(EXPR_MEMBER);
RECORD(EXPR_BINARY_OPERATOR);
RECORD(EXPR_COMPOUND_ASSIGN_OPERATOR);
RECORD(EXPR_CONDITIONAL_OPERATOR);
RECORD(EXPR_IMPLICIT_CAST);
RECORD(EXPR_CSTYLE_CAST);
RECORD(EXPR_COMPOUND_LITERAL);
RECORD(EXPR_EXT_VECTOR_ELEMENT);
RECORD(EXPR_INIT_LIST);
RECORD(EXPR_DESIGNATED_INIT);
RECORD(EXPR_IMPLICIT_VALUE_INIT);
RECORD(EXPR_VA_ARG);
RECORD(EXPR_ADDR_LABEL);
RECORD(EXPR_STMT);
RECORD(EXPR_CHOOSE);
RECORD(EXPR_GNU_NULL);
RECORD(EXPR_SHUFFLE_VECTOR);
RECORD(EXPR_BLOCK);
RECORD(EXPR_GENERIC_SELECTION);
RECORD(EXPR_OBJC_STRING_LITERAL);
RECORD(EXPR_OBJC_BOXED_EXPRESSION);
RECORD(EXPR_OBJC_ARRAY_LITERAL);
RECORD(EXPR_OBJC_DICTIONARY_LITERAL);
RECORD(EXPR_OBJC_ENCODE);
RECORD(EXPR_OBJC_SELECTOR_EXPR);
RECORD(EXPR_OBJC_PROTOCOL_EXPR);
RECORD(EXPR_OBJC_IVAR_REF_EXPR);
RECORD(EXPR_OBJC_PROPERTY_REF_EXPR);
RECORD(EXPR_OBJC_KVC_REF_EXPR);
RECORD(EXPR_OBJC_MESSAGE_EXPR);
RECORD(STMT_OBJC_FOR_COLLECTION);
RECORD(STMT_OBJC_CATCH);
RECORD(STMT_OBJC_FINALLY);
RECORD(STMT_OBJC_AT_TRY);
RECORD(STMT_OBJC_AT_SYNCHRONIZED);
RECORD(STMT_OBJC_AT_THROW);
RECORD(EXPR_OBJC_BOOL_LITERAL);
RECORD(EXPR_CXX_OPERATOR_CALL);
RECORD(EXPR_CXX_CONSTRUCT);
RECORD(EXPR_CXX_STATIC_CAST);
RECORD(EXPR_CXX_DYNAMIC_CAST);
RECORD(EXPR_CXX_REINTERPRET_CAST);
RECORD(EXPR_CXX_CONST_CAST);
RECORD(EXPR_CXX_FUNCTIONAL_CAST);
RECORD(EXPR_USER_DEFINED_LITERAL);
RECORD(EXPR_CXX_STD_INITIALIZER_LIST);
RECORD(EXPR_CXX_BOOL_LITERAL);
RECORD(EXPR_CXX_NULL_PTR_LITERAL);
RECORD(EXPR_CXX_TYPEID_EXPR);
RECORD(EXPR_CXX_TYPEID_TYPE);
RECORD(EXPR_CXX_UUIDOF_EXPR);
RECORD(EXPR_CXX_UUIDOF_TYPE);
RECORD(EXPR_CXX_THIS);
RECORD(EXPR_CXX_THROW);
RECORD(EXPR_CXX_DEFAULT_ARG);
RECORD(EXPR_CXX_BIND_TEMPORARY);
RECORD(EXPR_CXX_SCALAR_VALUE_INIT);
RECORD(EXPR_CXX_NEW);
RECORD(EXPR_CXX_DELETE);
RECORD(EXPR_CXX_PSEUDO_DESTRUCTOR);
RECORD(EXPR_EXPR_WITH_CLEANUPS);
RECORD(EXPR_CXX_DEPENDENT_SCOPE_MEMBER);
RECORD(EXPR_CXX_DEPENDENT_SCOPE_DECL_REF);
RECORD(EXPR_CXX_UNRESOLVED_CONSTRUCT);
RECORD(EXPR_CXX_UNRESOLVED_MEMBER);
RECORD(EXPR_CXX_UNRESOLVED_LOOKUP);
RECORD(EXPR_CXX_NOEXCEPT);
RECORD(EXPR_OPAQUE_VALUE);
RECORD(EXPR_PACK_EXPANSION);
RECORD(EXPR_SIZEOF_PACK);
RECORD(EXPR_SUBST_NON_TYPE_TEMPLATE_PARM_PACK);
RECORD(EXPR_CUDA_KERNEL_CALL);
#undef RECORD
}
void ASTWriter::WriteBlockInfoBlock() {
RecordData Record;
Stream.EnterSubblock(llvm::bitc::BLOCKINFO_BLOCK_ID, 3);
#define BLOCK(X) EmitBlockID(X ## _ID, #X, Stream, Record)
#define RECORD(X) EmitRecordID(X, #X, Stream, Record)
// Control Block.
BLOCK(CONTROL_BLOCK);
RECORD(METADATA);
RECORD(MODULE_NAME);
RECORD(MODULE_MAP_FILE);
RECORD(IMPORTS);
RECORD(LANGUAGE_OPTIONS);
RECORD(TARGET_OPTIONS);
RECORD(ORIGINAL_FILE);
RECORD(ORIGINAL_PCH_DIR);
RECORD(ORIGINAL_FILE_ID);
RECORD(INPUT_FILE_OFFSETS);
RECORD(DIAGNOSTIC_OPTIONS);
RECORD(FILE_SYSTEM_OPTIONS);
RECORD(HEADER_SEARCH_OPTIONS);
RECORD(PREPROCESSOR_OPTIONS);
BLOCK(INPUT_FILES_BLOCK);
RECORD(INPUT_FILE);
// AST Top-Level Block.
BLOCK(AST_BLOCK);
RECORD(TYPE_OFFSET);
RECORD(DECL_OFFSET);
RECORD(IDENTIFIER_OFFSET);
RECORD(IDENTIFIER_TABLE);
RECORD(EAGERLY_DESERIALIZED_DECLS);
RECORD(SPECIAL_TYPES);
RECORD(STATISTICS);
RECORD(TENTATIVE_DEFINITIONS);
RECORD(UNUSED_FILESCOPED_DECLS);
RECORD(LOCALLY_SCOPED_EXTERN_C_DECLS);
RECORD(SELECTOR_OFFSETS);
RECORD(METHOD_POOL);
RECORD(PP_COUNTER_VALUE);
RECORD(SOURCE_LOCATION_OFFSETS);
RECORD(SOURCE_LOCATION_PRELOADS);
RECORD(EXT_VECTOR_DECLS);
RECORD(PPD_ENTITIES_OFFSETS);
RECORD(REFERENCED_SELECTOR_POOL);
RECORD(TU_UPDATE_LEXICAL);
RECORD(LOCAL_REDECLARATIONS_MAP);
RECORD(SEMA_DECL_REFS);
RECORD(WEAK_UNDECLARED_IDENTIFIERS);
RECORD(PENDING_IMPLICIT_INSTANTIATIONS);
RECORD(DECL_REPLACEMENTS);
RECORD(UPDATE_VISIBLE);
RECORD(DECL_UPDATE_OFFSETS);
RECORD(DECL_UPDATES);
RECORD(CXX_BASE_SPECIFIER_OFFSETS);
RECORD(DIAG_PRAGMA_MAPPINGS);
RECORD(CUDA_SPECIAL_DECL_REFS);
RECORD(HEADER_SEARCH_TABLE);
RECORD(FP_PRAGMA_OPTIONS);
RECORD(OPENCL_EXTENSIONS);
RECORD(DELEGATING_CTORS);
RECORD(KNOWN_NAMESPACES);
RECORD(UNDEFINED_BUT_USED);
RECORD(MODULE_OFFSET_MAP);
RECORD(SOURCE_MANAGER_LINE_TABLE);
RECORD(OBJC_CATEGORIES_MAP);
RECORD(FILE_SORTED_DECLS);
RECORD(IMPORTED_MODULES);
RECORD(MERGED_DECLARATIONS);
RECORD(LOCAL_REDECLARATIONS);
RECORD(OBJC_CATEGORIES);
RECORD(MACRO_OFFSET);
RECORD(MACRO_TABLE);
RECORD(LATE_PARSED_TEMPLATE);
// SourceManager Block.
BLOCK(SOURCE_MANAGER_BLOCK);
RECORD(SM_SLOC_FILE_ENTRY);
RECORD(SM_SLOC_BUFFER_ENTRY);
RECORD(SM_SLOC_BUFFER_BLOB);
RECORD(SM_SLOC_EXPANSION_ENTRY);
// Preprocessor Block.
BLOCK(PREPROCESSOR_BLOCK);
RECORD(PP_MACRO_OBJECT_LIKE);
RECORD(PP_MACRO_FUNCTION_LIKE);
RECORD(PP_TOKEN);
// Decls and Types block.
BLOCK(DECLTYPES_BLOCK);
RECORD(TYPE_EXT_QUAL);
RECORD(TYPE_COMPLEX);
RECORD(TYPE_POINTER);
RECORD(TYPE_BLOCK_POINTER);
RECORD(TYPE_LVALUE_REFERENCE);
RECORD(TYPE_RVALUE_REFERENCE);
RECORD(TYPE_MEMBER_POINTER);
RECORD(TYPE_CONSTANT_ARRAY);
RECORD(TYPE_INCOMPLETE_ARRAY);
RECORD(TYPE_VARIABLE_ARRAY);
RECORD(TYPE_VECTOR);
RECORD(TYPE_EXT_VECTOR);
RECORD(TYPE_FUNCTION_PROTO);
RECORD(TYPE_FUNCTION_NO_PROTO);
RECORD(TYPE_TYPEDEF);
RECORD(TYPE_TYPEOF_EXPR);
RECORD(TYPE_TYPEOF);
RECORD(TYPE_RECORD);
RECORD(TYPE_ENUM);
RECORD(TYPE_OBJC_INTERFACE);
RECORD(TYPE_OBJC_OBJECT);
RECORD(TYPE_OBJC_OBJECT_POINTER);
RECORD(TYPE_DECLTYPE);
RECORD(TYPE_ELABORATED);
RECORD(TYPE_SUBST_TEMPLATE_TYPE_PARM);
RECORD(TYPE_UNRESOLVED_USING);
RECORD(TYPE_INJECTED_CLASS_NAME);
RECORD(TYPE_OBJC_OBJECT);
RECORD(TYPE_TEMPLATE_TYPE_PARM);
RECORD(TYPE_TEMPLATE_SPECIALIZATION);
RECORD(TYPE_DEPENDENT_NAME);
RECORD(TYPE_DEPENDENT_TEMPLATE_SPECIALIZATION);
RECORD(TYPE_DEPENDENT_SIZED_ARRAY);
RECORD(TYPE_PAREN);
RECORD(TYPE_PACK_EXPANSION);
RECORD(TYPE_ATTRIBUTED);
RECORD(TYPE_SUBST_TEMPLATE_TYPE_PARM_PACK);
RECORD(TYPE_ATOMIC);
RECORD(DECL_TYPEDEF);
RECORD(DECL_ENUM);
RECORD(DECL_RECORD);
RECORD(DECL_ENUM_CONSTANT);
RECORD(DECL_FUNCTION);
RECORD(DECL_OBJC_METHOD);
RECORD(DECL_OBJC_INTERFACE);
RECORD(DECL_OBJC_PROTOCOL);
RECORD(DECL_OBJC_IVAR);
RECORD(DECL_OBJC_AT_DEFS_FIELD);
RECORD(DECL_OBJC_CATEGORY);
RECORD(DECL_OBJC_CATEGORY_IMPL);
RECORD(DECL_OBJC_IMPLEMENTATION);
RECORD(DECL_OBJC_COMPATIBLE_ALIAS);
RECORD(DECL_OBJC_PROPERTY);
RECORD(DECL_OBJC_PROPERTY_IMPL);
RECORD(DECL_FIELD);
RECORD(DECL_MS_PROPERTY);
RECORD(DECL_VAR);
RECORD(DECL_IMPLICIT_PARAM);
RECORD(DECL_PARM_VAR);
RECORD(DECL_FILE_SCOPE_ASM);
RECORD(DECL_BLOCK);
RECORD(DECL_CONTEXT_LEXICAL);
RECORD(DECL_CONTEXT_VISIBLE);
RECORD(DECL_NAMESPACE);
RECORD(DECL_NAMESPACE_ALIAS);
RECORD(DECL_USING);
RECORD(DECL_USING_SHADOW);
RECORD(DECL_USING_DIRECTIVE);
RECORD(DECL_UNRESOLVED_USING_VALUE);
RECORD(DECL_UNRESOLVED_USING_TYPENAME);
RECORD(DECL_LINKAGE_SPEC);
RECORD(DECL_CXX_RECORD);
RECORD(DECL_CXX_METHOD);
RECORD(DECL_CXX_CONSTRUCTOR);
RECORD(DECL_CXX_DESTRUCTOR);
RECORD(DECL_CXX_CONVERSION);
RECORD(DECL_ACCESS_SPEC);
RECORD(DECL_FRIEND);
RECORD(DECL_FRIEND_TEMPLATE);
RECORD(DECL_CLASS_TEMPLATE);
RECORD(DECL_CLASS_TEMPLATE_SPECIALIZATION);
RECORD(DECL_CLASS_TEMPLATE_PARTIAL_SPECIALIZATION);
RECORD(DECL_VAR_TEMPLATE);
RECORD(DECL_VAR_TEMPLATE_SPECIALIZATION);
RECORD(DECL_VAR_TEMPLATE_PARTIAL_SPECIALIZATION);
RECORD(DECL_FUNCTION_TEMPLATE);
RECORD(DECL_TEMPLATE_TYPE_PARM);
RECORD(DECL_NON_TYPE_TEMPLATE_PARM);
RECORD(DECL_TEMPLATE_TEMPLATE_PARM);
RECORD(DECL_STATIC_ASSERT);
RECORD(DECL_CXX_BASE_SPECIFIERS);
RECORD(DECL_INDIRECTFIELD);
RECORD(DECL_EXPANDED_NON_TYPE_TEMPLATE_PARM_PACK);
// Statements and Exprs can occur in the Decls and Types block.
AddStmtsExprs(Stream, Record);
BLOCK(PREPROCESSOR_DETAIL_BLOCK);
RECORD(PPD_MACRO_EXPANSION);
RECORD(PPD_MACRO_DEFINITION);
RECORD(PPD_INCLUSION_DIRECTIVE);
#undef RECORD
#undef BLOCK
Stream.ExitBlock();
}
/// \brief Adjusts the given filename to only write out the portion of the
/// filename that is not part of the system root directory.
///
/// \param Filename the file name to adjust.
///
/// \param isysroot When non-NULL, the PCH file is a relocatable PCH file and
/// the returned filename will be adjusted by this system root.
///
/// \returns either the original filename (if it needs no adjustment) or the
/// adjusted filename (which points into the @p Filename parameter).
static const char *
adjustFilenameForRelocatablePCH(const char *Filename, StringRef isysroot) {
assert(Filename && "No file name to adjust?");
if (isysroot.empty())
return Filename;
// Verify that the filename and the system root have the same prefix.
unsigned Pos = 0;
for (; Filename[Pos] && Pos < isysroot.size(); ++Pos)
if (Filename[Pos] != isysroot[Pos])
return Filename; // Prefixes don't match.
// We hit the end of the filename before we hit the end of the system root.
if (!Filename[Pos])
return Filename;
// If the file name has a '/' at the current position, skip over the '/'.
// We distinguish sysroot-based includes from absolute includes by the
// absence of '/' at the beginning of sysroot-based includes.
if (Filename[Pos] == '/')
++Pos;
return Filename + Pos;
}
/// \brief Write the control block.
void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context,
StringRef isysroot,
const std::string &OutputFile) {
using namespace llvm;
Stream.EnterSubblock(CONTROL_BLOCK_ID, 5);
RecordData Record;
// Metadata
BitCodeAbbrev *MetadataAbbrev = new BitCodeAbbrev();
MetadataAbbrev->Add(BitCodeAbbrevOp(METADATA));
MetadataAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Major
MetadataAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Minor
MetadataAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Clang maj.
MetadataAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Clang min.
MetadataAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Relocatable
MetadataAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Errors
MetadataAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // SVN branch/tag
unsigned MetadataAbbrevCode = Stream.EmitAbbrev(MetadataAbbrev);
Record.push_back(METADATA);
Record.push_back(VERSION_MAJOR);
Record.push_back(VERSION_MINOR);
Record.push_back(CLANG_VERSION_MAJOR);
Record.push_back(CLANG_VERSION_MINOR);
Record.push_back(!isysroot.empty());
Record.push_back(ASTHasCompilerErrors);
Stream.EmitRecordWithBlob(MetadataAbbrevCode, Record,
getClangFullRepositoryVersion());
// Module name
if (WritingModule) {
BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(MODULE_NAME));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
unsigned AbbrevCode = Stream.EmitAbbrev(Abbrev);
RecordData Record;
Record.push_back(MODULE_NAME);
Stream.EmitRecordWithBlob(AbbrevCode, Record, WritingModule->Name);
}
// Module map file
if (WritingModule) {
BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(MODULE_MAP_FILE));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Filename
unsigned AbbrevCode = Stream.EmitAbbrev(Abbrev);
assert(WritingModule->ModuleMap && "missing module map");
SmallString<128> ModuleMap(WritingModule->ModuleMap->getName());
llvm::sys::fs::make_absolute(ModuleMap);
RecordData Record;
Record.push_back(MODULE_MAP_FILE);
Stream.EmitRecordWithBlob(AbbrevCode, Record, ModuleMap.str());
}
// Imports
if (Chain) {
serialization::ModuleManager &Mgr = Chain->getModuleManager();
Record.clear();
for (ModuleManager::ModuleIterator M = Mgr.begin(), MEnd = Mgr.end();
M != MEnd; ++M) {
// Skip modules that weren't directly imported.
if (!(*M)->isDirectlyImported())
continue;
Record.push_back((unsigned)(*M)->Kind); // FIXME: Stable encoding
AddSourceLocation((*M)->ImportLoc, Record);
Record.push_back((*M)->File->getSize());
Record.push_back((*M)->File->getModificationTime());
const std::string &FileName = (*M)->FileName;
Record.push_back(FileName.size());
Record.append(FileName.begin(), FileName.end());
}
Stream.EmitRecord(IMPORTS, Record);
}
// Language options.
Record.clear();
const LangOptions &LangOpts = Context.getLangOpts();
#define LANGOPT(Name, Bits, Default, Description) \
Record.push_back(LangOpts.Name);
#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \
Record.push_back(static_cast<unsigned>(LangOpts.get##Name()));
#include "clang/Basic/LangOptions.def"
#define SANITIZER(NAME, ID) Record.push_back(LangOpts.Sanitize.ID);
#include "clang/Basic/Sanitizers.def"
Record.push_back((unsigned) LangOpts.ObjCRuntime.getKind());
AddVersionTuple(LangOpts.ObjCRuntime.getVersion(), Record);
Record.push_back(LangOpts.CurrentModule.size());
Record.append(LangOpts.CurrentModule.begin(), LangOpts.CurrentModule.end());
// Comment options.
Record.push_back(LangOpts.CommentOpts.BlockCommandNames.size());
for (CommentOptions::BlockCommandNamesTy::const_iterator
I = LangOpts.CommentOpts.BlockCommandNames.begin(),
IEnd = LangOpts.CommentOpts.BlockCommandNames.end();
I != IEnd; ++I) {
AddString(*I, Record);
}
Record.push_back(LangOpts.CommentOpts.ParseAllComments);
Stream.EmitRecord(LANGUAGE_OPTIONS, Record);
// Target options.
Record.clear();
const TargetInfo &Target = Context.getTargetInfo();
const TargetOptions &TargetOpts = Target.getTargetOpts();
AddString(TargetOpts.Triple, Record);
AddString(TargetOpts.CPU, Record);
AddString(TargetOpts.ABI, Record);
AddString(TargetOpts.LinkerVersion, Record);
Record.push_back(TargetOpts.FeaturesAsWritten.size());
for (unsigned I = 0, N = TargetOpts.FeaturesAsWritten.size(); I != N; ++I) {
AddString(TargetOpts.FeaturesAsWritten[I], Record);
}
Record.push_back(TargetOpts.Features.size());
for (unsigned I = 0, N = TargetOpts.Features.size(); I != N; ++I) {
AddString(TargetOpts.Features[I], Record);
}
Stream.EmitRecord(TARGET_OPTIONS, Record);
// Diagnostic options.
Record.clear();
const DiagnosticOptions &DiagOpts
= Context.getDiagnostics().getDiagnosticOptions();
#define DIAGOPT(Name, Bits, Default) Record.push_back(DiagOpts.Name);
#define ENUM_DIAGOPT(Name, Type, Bits, Default) \
Record.push_back(static_cast<unsigned>(DiagOpts.get##Name()));
#include "clang/Basic/DiagnosticOptions.def"
Record.push_back(DiagOpts.Warnings.size());
for (unsigned I = 0, N = DiagOpts.Warnings.size(); I != N; ++I)
AddString(DiagOpts.Warnings[I], Record);
// Note: we don't serialize the log or serialization file names, because they
// are generally transient files and will almost always be overridden.
Stream.EmitRecord(DIAGNOSTIC_OPTIONS, Record);
// File system options.
Record.clear();
const FileSystemOptions &FSOpts
= Context.getSourceManager().getFileManager().getFileSystemOptions();
AddString(FSOpts.WorkingDir, Record);
Stream.EmitRecord(FILE_SYSTEM_OPTIONS, Record);
// Header search options.
Record.clear();
const HeaderSearchOptions &HSOpts
= PP.getHeaderSearchInfo().getHeaderSearchOpts();
AddString(HSOpts.Sysroot, Record);
// Include entries.
Record.push_back(HSOpts.UserEntries.size());
for (unsigned I = 0, N = HSOpts.UserEntries.size(); I != N; ++I) {
const HeaderSearchOptions::Entry &Entry = HSOpts.UserEntries[I];
AddString(Entry.Path, Record);
Record.push_back(static_cast<unsigned>(Entry.Group));
Record.push_back(Entry.IsFramework);
Record.push_back(Entry.IgnoreSysRoot);
}
// System header prefixes.
Record.push_back(HSOpts.SystemHeaderPrefixes.size());
for (unsigned I = 0, N = HSOpts.SystemHeaderPrefixes.size(); I != N; ++I) {
AddString(HSOpts.SystemHeaderPrefixes[I].Prefix, Record);
Record.push_back(HSOpts.SystemHeaderPrefixes[I].IsSystemHeader);
}
AddString(HSOpts.ResourceDir, Record);
AddString(HSOpts.ModuleCachePath, Record);
AddString(HSOpts.ModuleUserBuildPath, Record);
Record.push_back(HSOpts.DisableModuleHash);
Record.push_back(HSOpts.UseBuiltinIncludes);
Record.push_back(HSOpts.UseStandardSystemIncludes);
Record.push_back(HSOpts.UseStandardCXXIncludes);
Record.push_back(HSOpts.UseLibcxx);
Stream.EmitRecord(HEADER_SEARCH_OPTIONS, Record);
// Preprocessor options.
Record.clear();
const PreprocessorOptions &PPOpts = PP.getPreprocessorOpts();
// Macro definitions.
Record.push_back(PPOpts.Macros.size());
for (unsigned I = 0, N = PPOpts.Macros.size(); I != N; ++I) {
AddString(PPOpts.Macros[I].first, Record);
Record.push_back(PPOpts.Macros[I].second);
}
// Includes
Record.push_back(PPOpts.Includes.size());
for (unsigned I = 0, N = PPOpts.Includes.size(); I != N; ++I)
AddString(PPOpts.Includes[I], Record);
// Macro includes
Record.push_back(PPOpts.MacroIncludes.size());
for (unsigned I = 0, N = PPOpts.MacroIncludes.size(); I != N; ++I)
AddString(PPOpts.MacroIncludes[I], Record);
Record.push_back(PPOpts.UsePredefines);
// Detailed record is important since it is used for the module cache hash.
Record.push_back(PPOpts.DetailedRecord);
AddString(PPOpts.ImplicitPCHInclude, Record);
AddString(PPOpts.ImplicitPTHInclude, Record);
Record.push_back(static_cast<unsigned>(PPOpts.ObjCXXARCStandardLibrary));
Stream.EmitRecord(PREPROCESSOR_OPTIONS, Record);
// Original file name and file ID
SourceManager &SM = Context.getSourceManager();
if (const FileEntry *MainFile = SM.getFileEntryForID(SM.getMainFileID())) {
BitCodeAbbrev *FileAbbrev = new BitCodeAbbrev();
FileAbbrev->Add(BitCodeAbbrevOp(ORIGINAL_FILE));
FileAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // File ID
FileAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name
unsigned FileAbbrevCode = Stream.EmitAbbrev(FileAbbrev);
SmallString<128> MainFilePath(MainFile->getName());
llvm::sys::fs::make_absolute(MainFilePath);
const char *MainFileNameStr = MainFilePath.c_str();
MainFileNameStr = adjustFilenameForRelocatablePCH(MainFileNameStr,
isysroot);
Record.clear();
Record.push_back(ORIGINAL_FILE);
Record.push_back(SM.getMainFileID().getOpaqueValue());
Stream.EmitRecordWithBlob(FileAbbrevCode, Record, MainFileNameStr);
}
Record.clear();
Record.push_back(SM.getMainFileID().getOpaqueValue());
Stream.EmitRecord(ORIGINAL_FILE_ID, Record);
// Original PCH directory
if (!OutputFile.empty() && OutputFile != "-") {
BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(ORIGINAL_PCH_DIR));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name
unsigned AbbrevCode = Stream.EmitAbbrev(Abbrev);
SmallString<128> OutputPath(OutputFile);
llvm::sys::fs::make_absolute(OutputPath);
StringRef origDir = llvm::sys::path::parent_path(OutputPath);
RecordData Record;
Record.push_back(ORIGINAL_PCH_DIR);
Stream.EmitRecordWithBlob(AbbrevCode, Record, origDir);
}
WriteInputFiles(Context.SourceMgr,
PP.getHeaderSearchInfo().getHeaderSearchOpts(),
isysroot,
PP.getLangOpts().Modules);
Stream.ExitBlock();
}
namespace {
/// \brief An input file.
struct InputFileEntry {
const FileEntry *File;
bool IsSystemFile;
bool BufferOverridden;
};
}
void ASTWriter::WriteInputFiles(SourceManager &SourceMgr,
HeaderSearchOptions &HSOpts,
StringRef isysroot,
bool Modules) {
using namespace llvm;
Stream.EnterSubblock(INPUT_FILES_BLOCK_ID, 4);
RecordData Record;
// Create input-file abbreviation.
BitCodeAbbrev *IFAbbrev = new BitCodeAbbrev();
IFAbbrev->Add(BitCodeAbbrevOp(INPUT_FILE));
IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // ID
IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 12)); // Size
IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 32)); // Modification time
IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Overridden
IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name
unsigned IFAbbrevCode = Stream.EmitAbbrev(IFAbbrev);
// Get all ContentCache objects for files, sorted by whether the file is a
// system one or not. System files go at the back, users files at the front.
std::deque<InputFileEntry> SortedFiles;
for (unsigned I = 1, N = SourceMgr.local_sloc_entry_size(); I != N; ++I) {
// Get this source location entry.
const SrcMgr::SLocEntry *SLoc = &SourceMgr.getLocalSLocEntry(I);
assert(&SourceMgr.getSLocEntry(FileID::get(I)) == SLoc);
// We only care about file entries that were not overridden.
if (!SLoc->isFile())
continue;
const SrcMgr::ContentCache *Cache = SLoc->getFile().getContentCache();
if (!Cache->OrigEntry)
continue;
InputFileEntry Entry;
Entry.File = Cache->OrigEntry;
Entry.IsSystemFile = Cache->IsSystemFile;
Entry.BufferOverridden = Cache->BufferOverridden;
if (Cache->IsSystemFile)
SortedFiles.push_back(Entry);
else
SortedFiles.push_front(Entry);
}
unsigned UserFilesNum = 0;
// Write out all of the input files.
std::vector<uint32_t> InputFileOffsets;
for (std::deque<InputFileEntry>::iterator
I = SortedFiles.begin(), E = SortedFiles.end(); I != E; ++I) {
const InputFileEntry &Entry = *I;
uint32_t &InputFileID = InputFileIDs[Entry.File];
if (InputFileID != 0)
continue; // already recorded this file.
// Record this entry's offset.
InputFileOffsets.push_back(Stream.GetCurrentBitNo());
InputFileID = InputFileOffsets.size();
if (!Entry.IsSystemFile)
++UserFilesNum;
Record.clear();
Record.push_back(INPUT_FILE);
Record.push_back(InputFileOffsets.size());
// Emit size/modification time for this file.
Record.push_back(Entry.File->getSize());
Record.push_back(Entry.File->getModificationTime());
// Whether this file was overridden.
Record.push_back(Entry.BufferOverridden);
// Turn the file name into an absolute path, if it isn't already.
const char *Filename = Entry.File->getName();
SmallString<128> FilePath(Filename);
// Ask the file manager to fixup the relative path for us. This will
// honor the working directory.
SourceMgr.getFileManager().FixupRelativePath(FilePath);
// FIXME: This call to make_absolute shouldn't be necessary, the
// call to FixupRelativePath should always return an absolute path.
llvm::sys::fs::make_absolute(FilePath);
Filename = FilePath.c_str();
Filename = adjustFilenameForRelocatablePCH(Filename, isysroot);
Stream.EmitRecordWithBlob(IFAbbrevCode, Record, Filename);
}
Stream.ExitBlock();
// Create input file offsets abbreviation.
BitCodeAbbrev *OffsetsAbbrev = new BitCodeAbbrev();
OffsetsAbbrev->Add(BitCodeAbbrevOp(INPUT_FILE_OFFSETS));
OffsetsAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // # input files
OffsetsAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // # non-system
// input files
OffsetsAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Array
unsigned OffsetsAbbrevCode = Stream.EmitAbbrev(OffsetsAbbrev);
// Write input file offsets.
Record.clear();
Record.push_back(INPUT_FILE_OFFSETS);
Record.push_back(InputFileOffsets.size());
Record.push_back(UserFilesNum);
Stream.EmitRecordWithBlob(OffsetsAbbrevCode, Record, data(InputFileOffsets));
}
//===----------------------------------------------------------------------===//
// Source Manager Serialization
//===----------------------------------------------------------------------===//
/// \brief Create an abbreviation for the SLocEntry that refers to a
/// file.
static unsigned CreateSLocFileAbbrev(llvm::BitstreamWriter &Stream) {
using namespace llvm;
BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(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
// FileEntry fields.
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Input File ID
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // NumCreatedFIDs
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 24)); // FirstDeclIndex
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // NumDecls
return Stream.EmitAbbrev(Abbrev);
}
/// \brief Create an abbreviation for the SLocEntry that refers to a
/// buffer.
static unsigned CreateSLocBufferAbbrev(llvm::BitstreamWriter &Stream) {
using namespace llvm;
BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(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
return Stream.EmitAbbrev(Abbrev);
}
/// \brief Create an abbreviation for the SLocEntry that refers to a
/// buffer's blob.
static unsigned CreateSLocBufferBlobAbbrev(llvm::BitstreamWriter &Stream) {
using namespace llvm;
BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(SM_SLOC_BUFFER_BLOB));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Blob
return Stream.EmitAbbrev(Abbrev);
}
/// \brief Create an abbreviation for the SLocEntry that refers to a macro
/// expansion.
static unsigned CreateSLocExpansionAbbrev(llvm::BitstreamWriter &Stream) {
using namespace llvm;
BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(SM_SLOC_EXPANSION_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
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Token length
return Stream.EmitAbbrev(Abbrev);
}
namespace {
// Trait used for the on-disk hash table of header search information.
class HeaderFileInfoTrait {
ASTWriter &Writer;
const HeaderSearch &HS;
// Keep track of the framework names we've used during serialization.
SmallVector<char, 128> FrameworkStringData;
llvm::StringMap<unsigned> FrameworkNameOffset;
public:
HeaderFileInfoTrait(ASTWriter &Writer, const HeaderSearch &HS)
: Writer(Writer), HS(HS) { }
struct key_type {
const FileEntry *FE;
const char *Filename;
};
typedef const key_type &key_type_ref;
typedef HeaderFileInfo data_type;
typedef const data_type &data_type_ref;
typedef unsigned hash_value_type;
typedef unsigned offset_type;
static hash_value_type ComputeHash(key_type_ref key) {
// The hash is based only on size/time of the file, so that the reader can
// match even when symlinking or excess path elements ("foo/../", "../")
// change the form of the name. However, complete path is still the key.
return llvm::hash_combine(key.FE->getSize(),
key.FE->getModificationTime());
}
std::pair<unsigned,unsigned>
EmitKeyDataLength(raw_ostream& Out, key_type_ref key, data_type_ref Data) {
using namespace llvm::support;
endian::Writer<little> Writer(Out);
unsigned KeyLen = strlen(key.Filename) + 1 + 8 + 8;
Writer.write<uint16_t>(KeyLen);
unsigned DataLen = 1 + 2 + 4 + 4;
if (Data.isModuleHeader)
DataLen += 4;
Writer.write<uint8_t>(DataLen);
return std::make_pair(KeyLen, DataLen);
}
void EmitKey(raw_ostream& Out, key_type_ref key, unsigned KeyLen) {
using namespace llvm::support;
endian::Writer<little> LE(Out);
LE.write<uint64_t>(key.FE->getSize());
KeyLen -= 8;
LE.write<uint64_t>(key.FE->getModificationTime());
KeyLen -= 8;
Out.write(key.Filename, KeyLen);
}
void EmitData(raw_ostream &Out, key_type_ref key,
data_type_ref Data, unsigned DataLen) {
using namespace llvm::support;
endian::Writer<little> LE(Out);
uint64_t Start = Out.tell(); (void)Start;
unsigned char Flags = (Data.HeaderRole << 6)
| (Data.isImport << 5)
| (Data.isPragmaOnce << 4)
| (Data.DirInfo << 2)
| (Data.Resolved << 1)
| Data.IndexHeaderMapHeader;
LE.write<uint8_t>(Flags);
LE.write<uint16_t>(Data.NumIncludes);
if (!Data.ControllingMacro)
LE.write<uint32_t>(Data.ControllingMacroID);
else
LE.write<uint32_t>(Writer.getIdentifierRef(Data.ControllingMacro));
unsigned Offset = 0;
if (!Data.Framework.empty()) {
// If this header refers into a framework, save the framework name.
llvm::StringMap<unsigned>::iterator Pos
= FrameworkNameOffset.find(Data.Framework);
if (Pos == FrameworkNameOffset.end()) {
Offset = FrameworkStringData.size() + 1;
FrameworkStringData.append(Data.Framework.begin(),
Data.Framework.end());
FrameworkStringData.push_back(0);
FrameworkNameOffset[Data.Framework] = Offset;
} else
Offset = Pos->second;
}
LE.write<uint32_t>(Offset);
if (Data.isModuleHeader) {
Module *Mod = HS.findModuleForHeader(key.FE).getModule();
LE.write<uint32_t>(Writer.getExistingSubmoduleID(Mod));
}
assert(Out.tell() - Start == DataLen && "Wrong data length");
}
const char *strings_begin() const { return FrameworkStringData.begin(); }
const char *strings_end() const { return FrameworkStringData.end(); }
};
} // end anonymous namespace
/// \brief Write the header search block for the list of files that
///
/// \param HS The header search structure to save.
void ASTWriter::WriteHeaderSearch(const HeaderSearch &HS, StringRef isysroot) {
SmallVector<const FileEntry *, 16> FilesByUID;
HS.getFileMgr().GetUniqueIDMapping(FilesByUID);
if (FilesByUID.size() > HS.header_file_size())
FilesByUID.resize(HS.header_file_size());
HeaderFileInfoTrait GeneratorTrait(*this, HS);
llvm::OnDiskChainedHashTableGenerator<HeaderFileInfoTrait> Generator;
SmallVector<const char *, 4> SavedStrings;
unsigned NumHeaderSearchEntries = 0;
for (unsigned UID = 0, LastUID = FilesByUID.size(); UID != LastUID; ++UID) {
const FileEntry *File = FilesByUID[UID];
if (!File)
continue;
// Use HeaderSearch's getFileInfo to make sure we get the HeaderFileInfo
// from the external source if it was not provided already.
HeaderFileInfo HFI;
if (!HS.tryGetFileInfo(File, HFI) ||
(HFI.External && Chain) ||
(HFI.isModuleHeader && !HFI.isCompilingModuleHeader))
continue;
// Turn the file name into an absolute path, if it isn't already.
const char *Filename = File->getName();
Filename = adjustFilenameForRelocatablePCH(Filename, isysroot);
// If we performed any translation on the file name at all, we need to
// save this string, since the generator will refer to it later.
if (Filename != File->getName()) {
Filename = strdup(Filename);
SavedStrings.push_back(Filename);
}
HeaderFileInfoTrait::key_type key = { File, Filename };
Generator.insert(key, HFI, GeneratorTrait);
++NumHeaderSearchEntries;
}
// Create the on-disk hash table in a buffer.
SmallString<4096> TableData;
uint32_t BucketOffset;
{
using namespace llvm::support;
llvm::raw_svector_ostream Out(TableData);
// Make sure that no bucket is at offset 0
endian::Writer<little>(Out).write<uint32_t>(0);
BucketOffset = Generator.Emit(Out, GeneratorTrait);
}
// Create a blob abbreviation
using namespace llvm;
BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(HEADER_SEARCH_TABLE));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
unsigned TableAbbrev = Stream.EmitAbbrev(Abbrev);
// Write the header search table
RecordData Record;
Record.push_back(HEADER_SEARCH_TABLE);
Record.push_back(BucketOffset);
Record.push_back(NumHeaderSearchEntries);
Record.push_back(TableData.size());
TableData.append(GeneratorTrait.strings_begin(),GeneratorTrait.strings_end());
Stream.EmitRecordWithBlob(TableAbbrev, Record, TableData.str());
// Free all of the strings we had to duplicate.
for (unsigned I = 0, N = SavedStrings.size(); I != N; ++I)
free(const_cast<char *>(SavedStrings[I]));
}
/// \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.
void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
const Preprocessor &PP,
StringRef isysroot) {
RecordData Record;
// Enter the source manager block.
Stream.EnterSubblock(SOURCE_MANAGER_BLOCK_ID, 3);
// Abbreviations for the various kinds of source-location entries.
unsigned SLocFileAbbrv = CreateSLocFileAbbrev(Stream);
unsigned SLocBufferAbbrv = CreateSLocBufferAbbrev(Stream);
unsigned SLocBufferBlobAbbrv = CreateSLocBufferBlobAbbrev(Stream);
unsigned SLocExpansionAbbrv = CreateSLocExpansionAbbrev(Stream);
// Write out the source location entry table. We skip the first
// entry, which is always the same dummy entry.
std::vector<uint32_t> SLocEntryOffsets;
RecordData PreloadSLocs;
SLocEntryOffsets.reserve(SourceMgr.local_sloc_entry_size() - 1);
for (unsigned I = 1, N = SourceMgr.local_sloc_entry_size();
I != N; ++I) {
// Get this source location entry.
const SrcMgr::SLocEntry *SLoc = &SourceMgr.getLocalSLocEntry(I);
FileID FID = FileID::get(I);
assert(&SourceMgr.getSLocEntry(FID) == SLoc);
// Record the offset of this source-location entry.
SLocEntryOffsets.push_back(Stream.GetCurrentBitNo());
// Figure out which record code to use.
unsigned Code;
if (SLoc->isFile()) {
const SrcMgr::ContentCache *Cache = SLoc->getFile().getContentCache();
if (Cache->OrigEntry) {
Code = SM_SLOC_FILE_ENTRY;
} else
Code = SM_SLOC_BUFFER_ENTRY;
} else
Code = SM_SLOC_EXPANSION_ENTRY;
Record.clear();
Record.push_back(Code);
// Starting offset of this entry within this module, so skip the dummy.
Record.push_back(SLoc->getOffset() - 2);
if (SLoc->isFile()) {
const SrcMgr::FileInfo &File = SLoc->getFile();
Record.push_back(File.getIncludeLoc().getRawEncoding());
Record.push_back(File.getFileCharacteristic()); // FIXME: stable encoding
Record.push_back(File.hasLineDirectives());
const SrcMgr::ContentCache *Content = File.getContentCache();
if (Content->OrigEntry) {
assert(Content->OrigEntry == Content->ContentsEntry &&
"Writing to AST an overridden file is not supported");
// The source location entry is a file. Emit input file ID.
assert(InputFileIDs[Content->OrigEntry] != 0 && "Missed file entry");
Record.push_back(InputFileIDs[Content->OrigEntry]);
Record.push_back(File.NumCreatedFIDs);
FileDeclIDsTy::iterator FDI = FileDeclIDs.find(FID);
if (FDI != FileDeclIDs.end()) {
Record.push_back(FDI->second->FirstDeclIndex);
Record.push_back(FDI->second->DeclIDs.size());
} else {
Record.push_back(0);
Record.push_back(0);
}
Stream.EmitRecordWithAbbrev(SLocFileAbbrv, Record);
if (Content->BufferOverridden) {
Record.clear();
Record.push_back(SM_SLOC_BUFFER_BLOB);
const llvm::MemoryBuffer *Buffer
= Content->getBuffer(PP.getDiagnostics(), PP.getSourceManager());
Stream.EmitRecordWithBlob(SLocBufferBlobAbbrv, Record,
StringRef(Buffer->getBufferStart(),
Buffer->getBufferSize() + 1));
}
} else {
// The source location entry is a buffer. The blob associated
// with this entry contains the contents of the buffer.
// 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(PP.getDiagnostics(), PP.getSourceManager());
const char *Name = Buffer->getBufferIdentifier();
Stream.EmitRecordWithBlob(SLocBufferAbbrv, Record,
StringRef(Name, strlen(Name) + 1));
Record.clear();
Record.push_back(SM_SLOC_BUFFER_BLOB);
Stream.EmitRecordWithBlob(SLocBufferBlobAbbrv, Record,
StringRef(Buffer->getBufferStart(),
Buffer->getBufferSize() + 1));
if (strcmp(Name, "<built-in>") == 0) {
PreloadSLocs.push_back(SLocEntryOffsets.size());
}
}
} else {
// The source location entry is a macro expansion.
const SrcMgr::ExpansionInfo &Expansion = SLoc->getExpansion();
Record.push_back(Expansion.getSpellingLoc().getRawEncoding());
Record.push_back(Expansion.getExpansionLocStart().getRawEncoding());
Record.push_back(Expansion.isMacroArgExpansion() ? 0
: Expansion.getExpansionLocEnd().getRawEncoding());
// Compute the token length for this macro expansion.
unsigned NextOffset = SourceMgr.getNextLocalOffset();
if (I + 1 != N)
NextOffset = SourceMgr.getLocalSLocEntry(I + 1).getOffset();
Record.push_back(NextOffset - SLoc->getOffset() - 1);
Stream.EmitRecordWithAbbrev(SLocExpansionAbbrv, Record);
}
}
Stream.ExitBlock();
if (SLocEntryOffsets.empty())
return;
// Write the source-location offsets table into the AST block. This
// table is used for lazily loading source-location information.
using namespace llvm;
BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(SOURCE_LOCATION_OFFSETS));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 16)); // # of slocs
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 16)); // total size
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // offsets
unsigned SLocOffsetsAbbrev = Stream.EmitAbbrev(Abbrev);
Record.clear();
Record.push_back(SOURCE_LOCATION_OFFSETS);
Record.push_back(SLocEntryOffsets.size());
Record.push_back(SourceMgr.getNextLocalOffset() - 1); // skip dummy
Stream.EmitRecordWithBlob(SLocOffsetsAbbrev, Record, data(SLocEntryOffsets));
// Write the source location entry preloads array, telling the AST
// reader which source locations entries it should load eagerly.
Stream.EmitRecord(SOURCE_LOCATION_PRELOADS, PreloadSLocs);
// Write the line table. It depends on remapping working, so it must come
// after the source location offsets.
if (SourceMgr.hasLineTable()) {
LineTableInfo &LineTable = SourceMgr.getLineTable();
Record.clear();
// 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);
Filename = adjustFilenameForRelocatablePCH(Filename, isysroot);
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) {
// Only emit entries for local files.
if (L->first.ID < 0)
continue;
// Emit the file ID
Record.push_back(L->first.ID);
// 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);
}
}
Stream.EmitRecord(SOURCE_MANAGER_LINE_TABLE, Record);
}
}
//===----------------------------------------------------------------------===//
// Preprocessor Serialization
//===----------------------------------------------------------------------===//
namespace {
class ASTMacroTableTrait {
public:
typedef IdentID key_type;
typedef key_type key_type_ref;
struct Data {
uint32_t MacroDirectivesOffset;
};
typedef Data data_type;
typedef const data_type &data_type_ref;
typedef unsigned hash_value_type;
typedef unsigned offset_type;
static hash_value_type ComputeHash(IdentID IdID) {
return llvm::hash_value(IdID);
}
std::pair<unsigned,unsigned>
static EmitKeyDataLength(raw_ostream& Out,
key_type_ref Key, data_type_ref Data) {
unsigned KeyLen = 4; // IdentID.
unsigned DataLen = 4; // MacroDirectivesOffset.
return std::make_pair(KeyLen, DataLen);
}
static void EmitKey(raw_ostream& Out, key_type_ref Key, unsigned KeyLen) {
using namespace llvm::support;
endian::Writer<little>(Out).write<uint32_t>(Key);
}
static void EmitData(raw_ostream& Out, key_type_ref Key, data_type_ref Data,
unsigned) {
using namespace llvm::support;
endian::Writer<little>(Out).write<uint32_t>(Data.MacroDirectivesOffset);
}
};
} // end anonymous namespace
static int compareMacroDirectives(
const std::pair<const IdentifierInfo *, MacroDirective *> *X,
const std::pair<const IdentifierInfo *, MacroDirective *> *Y) {
return X->first->getName().compare(Y->first->getName());
}
static bool shouldIgnoreMacro(MacroDirective *MD, bool IsModule,
const Preprocessor &PP) {
if (MacroInfo *MI = MD->getMacroInfo())
if (MI->isBuiltinMacro())
return true;
if (IsModule) {
SourceLocation Loc = MD->getLocation();
if (Loc.isInvalid())
return true;
if (PP.getSourceManager().getFileID(Loc) == PP.getPredefinesFileID())
return true;
}
return false;
}
/// \brief Writes the block containing the serialized form of the
/// preprocessor.
///
void ASTWriter::WritePreprocessor(const Preprocessor &PP, bool IsModule) {
PreprocessingRecord *PPRec = PP.getPreprocessingRecord();
if (PPRec)
WritePreprocessorDetail(*PPRec);
RecordData Record;
// If the preprocessor __COUNTER__ value has been bumped, remember it.
if (PP.getCounterValue() != 0) {
Record.push_back(PP.getCounterValue());
Stream.EmitRecord(PP_COUNTER_VALUE, Record);
Record.clear();
}
// Enter the preprocessor block.
Stream.EnterSubblock(PREPROCESSOR_BLOCK_ID, 3);
// If the AST 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");
// Loop over all the macro directives that are live at the end of the file,
// emitting each to the PP section.
// Construct the list of macro directives that need to be serialized.
SmallVector<std::pair<const IdentifierInfo *, MacroDirective *>, 2>
MacroDirectives;
for (Preprocessor::macro_iterator
I = PP.macro_begin(/*IncludeExternalMacros=*/false),
E = PP.macro_end(/*IncludeExternalMacros=*/false);
I != E; ++I) {
MacroDirectives.push_back(std::make_pair(I->first, I->second));
}
// Sort the set of macro definitions that need to be serialized by the
// name of the macro, to provide a stable ordering.
llvm::array_pod_sort(MacroDirectives.begin(), MacroDirectives.end(),
&compareMacroDirectives);
llvm::OnDiskChainedHashTableGenerator<ASTMacroTableTrait> Generator;
// Emit the macro directives as a list and associate the offset with the
// identifier they belong to.
for (unsigned I = 0, N = MacroDirectives.size(); I != N; ++I) {
const IdentifierInfo *Name = MacroDirectives[I].first;
uint64_t MacroDirectiveOffset = Stream.GetCurrentBitNo();
MacroDirective *MD = MacroDirectives[I].second;
// If the macro or identifier need no updates, don't write the macro history
// for this one.
// FIXME: Chain the macro history instead of re-writing it.
if (MD->isFromPCH() &&
Name->isFromAST() && !Name->hasChangedSinceDeserialization())
continue;
// Emit the macro directives in reverse source order.
for (; MD; MD = MD->getPrevious()) {
if (shouldIgnoreMacro(MD, IsModule, PP))
continue;
AddSourceLocation(MD->getLocation(), Record);
Record.push_back(MD->getKind());
if (DefMacroDirective *DefMD = dyn_cast<DefMacroDirective>(MD)) {
MacroID InfoID = getMacroRef(DefMD->getInfo(), Name);
Record.push_back(InfoID);
Record.push_back(DefMD->isImported());
Record.push_back(DefMD->isAmbiguous());
} else if (VisibilityMacroDirective *
VisMD = dyn_cast<VisibilityMacroDirective>(MD)) {
Record.push_back(VisMD->isPublic());
}
}
if (Record.empty())
continue;
Stream.EmitRecord(PP_MACRO_DIRECTIVE_HISTORY, Record);
Record.clear();
IdentMacroDirectivesOffsetMap[Name] = MacroDirectiveOffset;
IdentID NameID = getIdentifierRef(Name);
ASTMacroTableTrait::Data data;
data.MacroDirectivesOffset = MacroDirectiveOffset;
Generator.insert(NameID, data);
}
/// \brief Offsets of each of the macros into the bitstream, indexed by
/// the local macro ID
///
/// For each identifier that is associated with a macro, this map
/// provides the offset into the bitstream where that macro is
/// defined.
std::vector<uint32_t> MacroOffsets;
for (unsigned I = 0, N = MacroInfosToEmit.size(); I != N; ++I) {
const IdentifierInfo *Name = MacroInfosToEmit[I].Name;
MacroInfo *MI = MacroInfosToEmit[I].MI;
MacroID ID = MacroInfosToEmit[I].ID;
if (ID < FirstMacroID) {
assert(0 && "Loaded MacroInfo entered MacroInfosToEmit ?");
continue;
}
// Record the local offset of this macro.
unsigned Index = ID - FirstMacroID;
if (Index == MacroOffsets.size())
MacroOffsets.push_back(Stream.GetCurrentBitNo());
else {
if (Index > MacroOffsets.size())
MacroOffsets.resize(Index + 1);
MacroOffsets[Index] = Stream.GetCurrentBitNo();
}
AddIdentifierRef(Name, Record);
Record.push_back(inferSubmoduleIDFromLocation(MI->getDefinitionLoc()));
AddSourceLocation(MI->getDefinitionLoc(), Record);
AddSourceLocation(MI->getDefinitionEndLoc(), Record);
Record.push_back(MI->isUsed());
Record.push_back(MI->isUsedForHeaderGuard());
unsigned Code;
if (MI->isObjectLike()) {
Code = PP_MACRO_OBJECT_LIKE;
} else {
Code = PP_MACRO_FUNCTION_LIKE;
Record.push_back(MI->isC99Varargs());
Record.push_back(MI->isGNUVarargs());
Record.push_back(MI->hasCommaPasting());
Record.push_back(MI->getNumArgs());
for (MacroInfo::arg_iterator I = MI->arg_begin(), E = MI->arg_end();
I != E; ++I)
AddIdentifierRef(*I, Record);
}
// If we have a detailed preprocessing record, record the macro definition
// ID that corresponds to this macro.
if (PPRec)
Record.push_back(MacroDefinitions[PPRec->findMacroDefinition(MI)]);
Stream.EmitRecord(Code, Record);
Record.clear();
// 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);
AddToken(Tok, Record);
Stream.EmitRecord(PP_TOKEN, Record);
Record.clear();
}
++NumMacros;
}
Stream.ExitBlock();
// Create the on-disk hash table in a buffer.
SmallString<4096> MacroTable;
uint32_t BucketOffset;
{
using namespace llvm::support;
llvm::raw_svector_ostream Out(MacroTable);
// Make sure that no bucket is at offset 0
endian::Writer<little>(Out).write<uint32_t>(0);
BucketOffset = Generator.Emit(Out);
}
// Write the macro table
using namespace llvm;
BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(MACRO_TABLE));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
unsigned MacroTableAbbrev = Stream.EmitAbbrev(Abbrev);
Record.push_back(MACRO_TABLE);
Record.push_back(BucketOffset);
Stream.EmitRecordWithBlob(MacroTableAbbrev, Record, MacroTable.str());
Record.clear();
// Write the offsets table for macro IDs.
using namespace llvm;
Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(MACRO_OFFSET));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of macros
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // first ID
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
unsigned MacroOffsetAbbrev = Stream.EmitAbbrev(Abbrev);
Record.clear();
Record.push_back(MACRO_OFFSET);
Record.push_back(MacroOffsets.size());
Record.push_back(FirstMacroID - NUM_PREDEF_MACRO_IDS);
Stream.EmitRecordWithBlob(MacroOffsetAbbrev, Record,
data(MacroOffsets));
}
void ASTWriter::WritePreprocessorDetail(PreprocessingRecord &PPRec) {
if (PPRec.local_begin() == PPRec.local_end())
return;
SmallVector<PPEntityOffset, 64> PreprocessedEntityOffsets;
// Enter the preprocessor block.
Stream.EnterSubblock(PREPROCESSOR_DETAIL_BLOCK_ID, 3);
// If the preprocessor has a preprocessing record, emit it.
unsigned NumPreprocessingRecords = 0;
using namespace llvm;
// Set up the abbreviation for
unsigned InclusionAbbrev = 0;
{
BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(PPD_INCLUSION_DIRECTIVE));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // filename length
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // in quotes
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // kind
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // imported module
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
InclusionAbbrev = Stream.EmitAbbrev(Abbrev);
}
unsigned FirstPreprocessorEntityID
= (Chain ? PPRec.getNumLoadedPreprocessedEntities() : 0)
+ NUM_PREDEF_PP_ENTITY_IDS;
unsigned NextPreprocessorEntityID = FirstPreprocessorEntityID;
RecordData Record;
for (PreprocessingRecord::iterator E = PPRec.local_begin(),
EEnd = PPRec.local_end();
E != EEnd;
(void)++E, ++NumPreprocessingRecords, ++NextPreprocessorEntityID) {
Record.clear();
PreprocessedEntityOffsets.push_back(PPEntityOffset((*E)->getSourceRange(),
Stream.GetCurrentBitNo()));
if (MacroDefinition *MD = dyn_cast<MacroDefinition>(*E)) {
// Record this macro definition's ID.
MacroDefinitions[MD] = NextPreprocessorEntityID;
AddIdentifierRef(MD->getName(), Record);
Stream.EmitRecord(PPD_MACRO_DEFINITION, Record);
continue;
}
if (MacroExpansion *ME = dyn_cast<MacroExpansion>(*E)) {
Record.push_back(ME->isBuiltinMacro());
if (ME->isBuiltinMacro())
AddIdentifierRef(ME->getName(), Record);
else
Record.push_back(MacroDefinitions[ME->getDefinition()]);
Stream.EmitRecord(PPD_MACRO_EXPANSION, Record);
continue;
}
if (InclusionDirective *ID = dyn_cast<InclusionDirective>(*E)) {
Record.push_back(PPD_INCLUSION_DIRECTIVE);
Record.push_back(ID->getFileName().size());
Record.push_back(ID->wasInQuotes());
Record.push_back(static_cast<unsigned>(ID->getKind()));
Record.push_back(ID->importedModule());
SmallString<64> Buffer;
Buffer += ID->getFileName();
// Check that the FileEntry is not null because it was not resolved and
// we create a PCH even with compiler errors.
if (ID->getFile())
Buffer += ID->getFile()->getName();
Stream.EmitRecordWithBlob(InclusionAbbrev, Record, Buffer);
continue;
}
llvm_unreachable("Unhandled PreprocessedEntity in ASTWriter");
}
Stream.ExitBlock();
// Write the offsets table for the preprocessing record.
if (NumPreprocessingRecords > 0) {
assert(PreprocessedEntityOffsets.size() == NumPreprocessingRecords);
// Write the offsets table for identifier IDs.
using namespace llvm;
BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(PPD_ENTITIES_OFFSETS));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // first pp entity
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
unsigned PPEOffsetAbbrev = Stream.EmitAbbrev(Abbrev);
Record.clear();
Record.push_back(PPD_ENTITIES_OFFSETS);
Record.push_back(FirstPreprocessorEntityID - NUM_PREDEF_PP_ENTITY_IDS);
Stream.EmitRecordWithBlob(PPEOffsetAbbrev, Record,
data(PreprocessedEntityOffsets));
}
}
unsigned ASTWriter::getSubmoduleID(Module *Mod) {
llvm::DenseMap<Module *, unsigned>::iterator Known = SubmoduleIDs.find(Mod);
if (Known != SubmoduleIDs.end())
return Known->second;
return SubmoduleIDs[Mod] = NextSubmoduleID++;
}
unsigned ASTWriter::getExistingSubmoduleID(Module *Mod) const {
if (!Mod)
return 0;
llvm::DenseMap<Module *, unsigned>::const_iterator
Known = SubmoduleIDs.find(Mod);
if (Known != SubmoduleIDs.end())
return Known->second;
return 0;
}
/// \brief Compute the number of modules within the given tree (including the
/// given module).
static unsigned getNumberOfModules(Module *Mod) {
unsigned ChildModules = 0;
for (Module::submodule_iterator Sub = Mod->submodule_begin(),
SubEnd = Mod->submodule_end();
Sub != SubEnd; ++Sub)
ChildModules += getNumberOfModules(*Sub);
return ChildModules + 1;
}
void ASTWriter::WriteSubmodules(Module *WritingModule) {
// Determine the dependencies of our module and each of it's submodules.
// FIXME: This feels like it belongs somewhere else, but there are no
// other consumers of this information.
SourceManager &SrcMgr = PP->getSourceManager();
ModuleMap &ModMap = PP->getHeaderSearchInfo().getModuleMap();
for (const auto *I : Context->local_imports()) {
if (Module *ImportedFrom
= ModMap.inferModuleFromLocation(FullSourceLoc(I->getLocation(),
SrcMgr))) {
ImportedFrom->Imports.push_back(I->getImportedModule());
}
}
// Enter the submodule description block.
Stream.EnterSubblock(SUBMODULE_BLOCK_ID, NUM_ALLOWED_ABBREVS_SIZE);
// Write the abbreviations needed for the submodules block.
using namespace llvm;
BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_DEFINITION));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // ID
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Parent
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsFramework
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsExplicit
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsSystem
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsExternC
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // InferSubmodules...
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // InferExplicit...
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // InferExportWild...
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // ConfigMacrosExh...
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
unsigned DefinitionAbbrev = Stream.EmitAbbrev(Abbrev);
Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_UMBRELLA_HEADER));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
unsigned UmbrellaAbbrev = Stream.EmitAbbrev(Abbrev);
Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_HEADER));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
unsigned HeaderAbbrev = Stream.EmitAbbrev(Abbrev);
Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_TOPHEADER));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
unsigned TopHeaderAbbrev = Stream.EmitAbbrev(Abbrev);
Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_UMBRELLA_DIR));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
unsigned UmbrellaDirAbbrev = Stream.EmitAbbrev(Abbrev);
Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_REQUIRES));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // State
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Feature
unsigned RequiresAbbrev = Stream.EmitAbbrev(Abbrev);
Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_EXCLUDED_HEADER));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
unsigned ExcludedHeaderAbbrev = Stream.EmitAbbrev(Abbrev);
Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_PRIVATE_HEADER));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
unsigned PrivateHeaderAbbrev = Stream.EmitAbbrev(Abbrev);
Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_LINK_LIBRARY));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsFramework
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
unsigned LinkLibraryAbbrev = Stream.EmitAbbrev(Abbrev);
Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_CONFIG_MACRO));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Macro name
unsigned ConfigMacroAbbrev = Stream.EmitAbbrev(Abbrev);
Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_CONFLICT));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Other module
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Message
unsigned ConflictAbbrev = Stream.EmitAbbrev(Abbrev);
// Write the submodule metadata block.
RecordData Record;
Record.push_back(getNumberOfModules(WritingModule));
Record.push_back(FirstSubmoduleID - NUM_PREDEF_SUBMODULE_IDS);
Stream.EmitRecord(SUBMODULE_METADATA, Record);
// Write all of the submodules.
std::queue<Module *> Q;
Q.push(WritingModule);
while (!Q.empty()) {
Module *Mod = Q.front();
Q.pop();
unsigned ID = getSubmoduleID(Mod);
// Emit the definition of the block.
Record.clear();
Record.push_back(SUBMODULE_DEFINITION);
Record.push_back(ID);
if (Mod->Parent) {
assert(SubmoduleIDs[Mod->Parent] && "Submodule parent not written?");
Record.push_back(SubmoduleIDs[Mod->Parent]);
} else {
Record.push_back(0);
}
Record.push_back(Mod->IsFramework);
Record.push_back(Mod->IsExplicit);
Record.push_back(Mod->IsSystem);
Record.push_back(Mod->IsExternC);
Record.push_back(Mod->InferSubmodules);
Record.push_back(Mod->InferExplicitSubmodules);
Record.push_back(Mod->InferExportWildcard);
Record.push_back(Mod->ConfigMacrosExhaustive);
Stream.EmitRecordWithBlob(DefinitionAbbrev, Record, Mod->Name);
// Emit the requirements.
for (unsigned I = 0, N = Mod->Requirements.size(); I != N; ++I) {
Record.clear();
Record.push_back(SUBMODULE_REQUIRES);
Record.push_back(Mod->Requirements[I].second);
Stream.EmitRecordWithBlob(RequiresAbbrev, Record,
Mod->Requirements[I].first);
}
// Emit the umbrella header, if there is one.
if (const FileEntry *UmbrellaHeader = Mod->getUmbrellaHeader()) {
Record.clear();
Record.push_back(SUBMODULE_UMBRELLA_HEADER);
Stream.EmitRecordWithBlob(UmbrellaAbbrev, Record,
UmbrellaHeader->getName());
} else if (const DirectoryEntry *UmbrellaDir = Mod->getUmbrellaDir()) {
Record.clear();
Record.push_back(SUBMODULE_UMBRELLA_DIR);
Stream.EmitRecordWithBlob(UmbrellaDirAbbrev, Record,
UmbrellaDir->getName());
}
// Emit the headers.
for (unsigned I = 0, N = Mod->NormalHeaders.size(); I != N; ++I) {
Record.clear();
Record.push_back(SUBMODULE_HEADER);
Stream.EmitRecordWithBlob(HeaderAbbrev, Record,
Mod->NormalHeaders[I]->getName());
}
// Emit the excluded headers.
for (unsigned I = 0, N = Mod->ExcludedHeaders.size(); I != N; ++I) {
Record.clear();
Record.push_back(SUBMODULE_EXCLUDED_HEADER);
Stream.EmitRecordWithBlob(ExcludedHeaderAbbrev