2010-08-19 07:56:31 +08:00
|
|
|
//===--- ASTWriter.cpp - AST File Writer ----------------------------------===//
|
2009-04-10 06:27:44 +08:00
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
2010-08-19 07:56:21 +08:00
|
|
|
// This file defines the ASTWriter class, which writes AST files.
|
2009-04-10 06:27:44 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2010-08-19 07:56:37 +08:00
|
|
|
#include "clang/Serialization/ASTWriter.h"
|
2010-08-21 00:03:52 +08:00
|
|
|
#include "ASTCommon.h"
|
2010-08-13 04:07:10 +08:00
|
|
|
#include "clang/Sema/Sema.h"
|
|
|
|
#include "clang/Sema/IdentifierResolver.h"
|
2009-04-10 06:27:44 +08:00
|
|
|
#include "clang/AST/ASTContext.h"
|
|
|
|
#include "clang/AST/Decl.h"
|
|
|
|
#include "clang/AST/DeclContextInternals.h"
|
2010-08-25 13:32:35 +08:00
|
|
|
#include "clang/AST/DeclTemplate.h"
|
2009-04-15 05:18:50 +08:00
|
|
|
#include "clang/AST/Expr.h"
|
2010-08-24 15:32:53 +08:00
|
|
|
#include "clang/AST/ExprCXX.h"
|
2009-04-10 06:27:44 +08:00
|
|
|
#include "clang/AST/Type.h"
|
2009-10-17 05:56:05 +08:00
|
|
|
#include "clang/AST/TypeLocVisitor.h"
|
2010-08-19 07:57:17 +08:00
|
|
|
#include "clang/Serialization/ASTReader.h"
|
2009-04-11 02:00:12 +08:00
|
|
|
#include "clang/Lex/MacroInfo.h"
|
Implement serialization and lazy deserialization of the preprocessing
record (which includes all macro instantiations and definitions). As
with all lay deserialization, this introduces a new external source
(here, an external preprocessing record source) that loads all of the
preprocessed entities prior to iterating over the entities.
The preprocessing record is an optional part of the precompiled header
that is disabled by default (enabled with
-detailed-preprocessing-record). When the preprocessor given to the
PCH writer has a preprocessing record, that record is written into the
PCH file. When the PCH reader is given a PCH file that contains a
preprocessing record, it will be lazily loaded (which, effectively,
implicitly adds -detailed-preprocessing-record). This is the first
case where we have sections of the precompiled header that are
added/removed based on a compilation flag, which is
unfortunate. However, this data consumes ~550k in the PCH file for
Cocoa.h (out of ~9.9MB), and there is a non-trivial cost to gathering
this detailed preprocessing information, so it's too expensive to turn
on by default. In the future, we should investigate a better encoding
of this information.
llvm-svn: 99002
2010-03-20 05:51:54 +08:00
|
|
|
#include "clang/Lex/PreprocessingRecord.h"
|
2009-04-11 02:00:12 +08:00
|
|
|
#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-28 06:23:34 +08:00
|
|
|
#include "clang/Basic/Version.h"
|
2009-04-15 05:55:33 +08:00
|
|
|
#include "llvm/ADT/APFloat.h"
|
|
|
|
#include "llvm/ADT/APInt.h"
|
2009-10-18 07:52:28 +08:00
|
|
|
#include "llvm/ADT/StringExtras.h"
|
2009-04-10 06:27:44 +08:00
|
|
|
#include "llvm/Bitcode/BitstreamWriter.h"
|
2009-04-10 11:52:48 +08:00
|
|
|
#include "llvm/Support/MemoryBuffer.h"
|
2009-05-12 09:31:05 +08:00
|
|
|
#include "llvm/System/Path.h"
|
2009-04-12 02:40:46 +08:00
|
|
|
#include <cstdio>
|
2009-04-10 06:27:44 +08:00
|
|
|
using namespace clang;
|
2010-08-19 07:57:32 +08:00
|
|
|
using namespace clang::serialization;
|
2009-04-10 06:27:44 +08:00
|
|
|
|
2010-07-31 01:03:48 +08:00
|
|
|
template <typename T, typename Allocator>
|
|
|
|
T *data(std::vector<T, Allocator> &v) {
|
|
|
|
return v.empty() ? 0 : &v.front();
|
|
|
|
}
|
|
|
|
template <typename T, typename Allocator>
|
|
|
|
const T *data(const std::vector<T, Allocator> &v) {
|
|
|
|
return v.empty() ? 0 : &v.front();
|
|
|
|
}
|
|
|
|
|
2009-04-10 06:27:44 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Type serialization
|
|
|
|
//===----------------------------------------------------------------------===//
|
2009-04-27 14:16:06 +08:00
|
|
|
|
2009-04-10 06:27:44 +08:00
|
|
|
namespace {
|
2010-08-19 07:56:27 +08:00
|
|
|
class ASTTypeWriter {
|
2010-08-19 07:56:21 +08:00
|
|
|
ASTWriter &Writer;
|
|
|
|
ASTWriter::RecordData &Record;
|
2009-04-10 06:27:44 +08:00
|
|
|
|
|
|
|
public:
|
|
|
|
/// \brief Type code that corresponds to the record generated.
|
2010-08-19 07:57:32 +08:00
|
|
|
TypeCode Code;
|
2009-04-10 06:27:44 +08:00
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
ASTTypeWriter(ASTWriter &Writer, ASTWriter::RecordData &Record)
|
2010-08-19 07:57:32 +08:00
|
|
|
: Writer(Writer), Record(Record), Code(TYPE_EXT_QUAL) { }
|
2009-04-10 06:27:44 +08:00
|
|
|
|
|
|
|
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"
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
void ASTTypeWriter::VisitBuiltinType(const BuiltinType *T) {
|
2009-04-10 06:27:44 +08:00
|
|
|
assert(false && "Built-in types are never serialized");
|
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
void ASTTypeWriter::VisitComplexType(const ComplexType *T) {
|
2009-04-10 06:27:44 +08:00
|
|
|
Writer.AddTypeRef(T->getElementType(), Record);
|
2010-08-19 07:57:32 +08:00
|
|
|
Code = TYPE_COMPLEX;
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
void ASTTypeWriter::VisitPointerType(const PointerType *T) {
|
2009-04-10 06:27:44 +08:00
|
|
|
Writer.AddTypeRef(T->getPointeeType(), Record);
|
2010-08-19 07:57:32 +08:00
|
|
|
Code = TYPE_POINTER;
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
void ASTTypeWriter::VisitBlockPointerType(const BlockPointerType *T) {
|
2009-09-09 23:08:12 +08:00
|
|
|
Writer.AddTypeRef(T->getPointeeType(), Record);
|
2010-08-19 07:57:32 +08:00
|
|
|
Code = TYPE_BLOCK_POINTER;
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
void ASTTypeWriter::VisitLValueReferenceType(const LValueReferenceType *T) {
|
2009-04-10 06:27:44 +08:00
|
|
|
Writer.AddTypeRef(T->getPointeeType(), Record);
|
2010-08-19 07:57:32 +08:00
|
|
|
Code = TYPE_LVALUE_REFERENCE;
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
void ASTTypeWriter::VisitRValueReferenceType(const RValueReferenceType *T) {
|
2009-04-10 06:27:44 +08:00
|
|
|
Writer.AddTypeRef(T->getPointeeType(), Record);
|
2010-08-19 07:57:32 +08:00
|
|
|
Code = TYPE_RVALUE_REFERENCE;
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
void ASTTypeWriter::VisitMemberPointerType(const MemberPointerType *T) {
|
2009-09-09 23:08:12 +08:00
|
|
|
Writer.AddTypeRef(T->getPointeeType(), Record);
|
|
|
|
Writer.AddTypeRef(QualType(T->getClass(), 0), Record);
|
2010-08-19 07:57:32 +08:00
|
|
|
Code = TYPE_MEMBER_POINTER;
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
void ASTTypeWriter::VisitArrayType(const ArrayType *T) {
|
2009-04-10 06:27:44 +08:00
|
|
|
Writer.AddTypeRef(T->getElementType(), Record);
|
|
|
|
Record.push_back(T->getSizeModifier()); // FIXME: stable values
|
2009-09-25 03:53:00 +08:00
|
|
|
Record.push_back(T->getIndexTypeCVRQualifiers()); // FIXME: stable values
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
void ASTTypeWriter::VisitConstantArrayType(const ConstantArrayType *T) {
|
2009-04-10 06:27:44 +08:00
|
|
|
VisitArrayType(T);
|
|
|
|
Writer.AddAPInt(T->getSize(), Record);
|
2010-08-19 07:57:32 +08:00
|
|
|
Code = TYPE_CONSTANT_ARRAY;
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
void ASTTypeWriter::VisitIncompleteArrayType(const IncompleteArrayType *T) {
|
2009-04-10 06:27:44 +08:00
|
|
|
VisitArrayType(T);
|
2010-08-19 07:57:32 +08:00
|
|
|
Code = TYPE_INCOMPLETE_ARRAY;
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
void ASTTypeWriter::VisitVariableArrayType(const VariableArrayType *T) {
|
2009-04-10 06:27:44 +08:00
|
|
|
VisitArrayType(T);
|
2009-07-06 23:59:29 +08:00
|
|
|
Writer.AddSourceLocation(T->getLBracketLoc(), Record);
|
|
|
|
Writer.AddSourceLocation(T->getRBracketLoc(), Record);
|
2009-04-17 06:23:12 +08:00
|
|
|
Writer.AddStmt(T->getSizeExpr());
|
2010-08-19 07:57:32 +08:00
|
|
|
Code = TYPE_VARIABLE_ARRAY;
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
void ASTTypeWriter::VisitVectorType(const VectorType *T) {
|
2009-04-10 06:27:44 +08:00
|
|
|
Writer.AddTypeRef(T->getElementType(), Record);
|
|
|
|
Record.push_back(T->getNumElements());
|
2010-06-23 14:00:24 +08:00
|
|
|
Record.push_back(T->getAltiVecSpecific());
|
2010-08-19 07:57:32 +08:00
|
|
|
Code = TYPE_VECTOR;
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
void ASTTypeWriter::VisitExtVectorType(const ExtVectorType *T) {
|
2009-04-10 06:27:44 +08:00
|
|
|
VisitVectorType(T);
|
2010-08-19 07:57:32 +08:00
|
|
|
Code = TYPE_EXT_VECTOR;
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
void ASTTypeWriter::VisitFunctionType(const FunctionType *T) {
|
2009-04-10 06:27:44 +08:00
|
|
|
Writer.AddTypeRef(T->getResultType(), Record);
|
2010-03-31 04:24:48 +08:00
|
|
|
FunctionType::ExtInfo C = T->getExtInfo();
|
|
|
|
Record.push_back(C.getNoReturn());
|
2010-03-31 06:15:11 +08:00
|
|
|
Record.push_back(C.getRegParm());
|
2010-01-19 01:14:39 +08:00
|
|
|
// FIXME: need to stabilize encoding of calling convention...
|
2010-03-31 04:24:48 +08:00
|
|
|
Record.push_back(C.getCC());
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
void ASTTypeWriter::VisitFunctionNoProtoType(const FunctionNoProtoType *T) {
|
2009-04-10 06:27:44 +08:00
|
|
|
VisitFunctionType(T);
|
2010-08-19 07:57:32 +08:00
|
|
|
Code = TYPE_FUNCTION_NO_PROTO;
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
void ASTTypeWriter::VisitFunctionProtoType(const FunctionProtoType *T) {
|
2009-04-10 06:27:44 +08:00
|
|
|
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());
|
2009-05-28 06:11:52 +08:00
|
|
|
Record.push_back(T->hasExceptionSpec());
|
|
|
|
Record.push_back(T->hasAnyExceptionSpec());
|
|
|
|
Record.push_back(T->getNumExceptions());
|
|
|
|
for (unsigned I = 0, N = T->getNumExceptions(); I != N; ++I)
|
|
|
|
Writer.AddTypeRef(T->getExceptionType(I), Record);
|
2010-08-19 07:57:32 +08:00
|
|
|
Code = TYPE_FUNCTION_PROTO;
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
void ASTTypeWriter::VisitUnresolvedUsingType(const UnresolvedUsingType *T) {
|
2009-12-05 06:46:56 +08:00
|
|
|
Writer.AddDeclRef(T->getDecl(), Record);
|
2010-08-19 07:57:32 +08:00
|
|
|
Code = TYPE_UNRESOLVED_USING;
|
2009-12-05 06:46:56 +08:00
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
void ASTTypeWriter::VisitTypedefType(const TypedefType *T) {
|
2009-04-10 06:27:44 +08:00
|
|
|
Writer.AddDeclRef(T->getDecl(), Record);
|
2010-07-02 19:55:11 +08:00
|
|
|
assert(!T->isCanonicalUnqualified() && "Invalid typedef ?");
|
|
|
|
Writer.AddTypeRef(T->getCanonicalTypeInternal(), Record);
|
2010-08-19 07:57:32 +08:00
|
|
|
Code = TYPE_TYPEDEF;
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
void ASTTypeWriter::VisitTypeOfExprType(const TypeOfExprType *T) {
|
2009-04-17 06:23:12 +08:00
|
|
|
Writer.AddStmt(T->getUnderlyingExpr());
|
2010-08-19 07:57:32 +08:00
|
|
|
Code = TYPE_TYPEOF_EXPR;
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
void ASTTypeWriter::VisitTypeOfType(const TypeOfType *T) {
|
2009-04-10 06:27:44 +08:00
|
|
|
Writer.AddTypeRef(T->getUnderlyingType(), Record);
|
2010-08-19 07:57:32 +08:00
|
|
|
Code = TYPE_TYPEOF;
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
void ASTTypeWriter::VisitDecltypeType(const DecltypeType *T) {
|
2009-06-25 03:06:50 +08:00
|
|
|
Writer.AddStmt(T->getUnderlyingExpr());
|
2010-08-19 07:57:32 +08:00
|
|
|
Code = TYPE_DECLTYPE;
|
2009-06-25 03:06:50 +08:00
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
void ASTTypeWriter::VisitTagType(const TagType *T) {
|
2010-07-08 21:09:53 +08:00
|
|
|
Record.push_back(T->isDependentType());
|
2009-04-10 06:27:44 +08:00
|
|
|
Writer.AddDeclRef(T->getDecl(), Record);
|
2009-09-09 23:08:12 +08:00
|
|
|
assert(!T->isBeingDefined() &&
|
2009-04-10 06:27:44 +08:00
|
|
|
"Cannot serialize in the middle of a type definition");
|
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
void ASTTypeWriter::VisitRecordType(const RecordType *T) {
|
2009-04-10 06:27:44 +08:00
|
|
|
VisitTagType(T);
|
2010-08-19 07:57:32 +08:00
|
|
|
Code = TYPE_RECORD;
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
void ASTTypeWriter::VisitEnumType(const EnumType *T) {
|
2009-04-10 06:27:44 +08:00
|
|
|
VisitTagType(T);
|
2010-08-19 07:57:32 +08:00
|
|
|
Code = TYPE_ENUM;
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
|
|
|
|
2009-10-18 17:09:24 +08:00
|
|
|
void
|
2010-08-19 07:56:27 +08:00
|
|
|
ASTTypeWriter::VisitSubstTemplateTypeParmType(
|
2009-10-18 17:09:24 +08:00
|
|
|
const SubstTemplateTypeParmType *T) {
|
|
|
|
Writer.AddTypeRef(QualType(T->getReplacedParameter(), 0), Record);
|
|
|
|
Writer.AddTypeRef(T->getReplacementType(), Record);
|
2010-08-19 07:57:32 +08:00
|
|
|
Code = TYPE_SUBST_TEMPLATE_TYPE_PARM;
|
2009-10-18 17:09:24 +08:00
|
|
|
}
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
void
|
2010-08-19 07:56:27 +08:00
|
|
|
ASTTypeWriter::VisitTemplateSpecializationType(
|
2009-04-10 06:27:44 +08:00
|
|
|
const TemplateSpecializationType *T) {
|
2010-07-08 21:09:53 +08:00
|
|
|
Record.push_back(T->isDependentType());
|
2010-06-20 03:28:53 +08:00
|
|
|
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);
|
2010-07-02 19:55:11 +08:00
|
|
|
Writer.AddTypeRef(T->isCanonicalUnqualified() ? QualType()
|
|
|
|
: T->getCanonicalTypeInternal(),
|
|
|
|
Record);
|
2010-08-19 07:57:32 +08:00
|
|
|
Code = TYPE_TEMPLATE_SPECIALIZATION;
|
2010-06-20 03:28:53 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2010-08-19 07:56:27 +08:00
|
|
|
ASTTypeWriter::VisitDependentSizedArrayType(const DependentSizedArrayType *T) {
|
2010-06-30 16:49:25 +08:00
|
|
|
VisitArrayType(T);
|
|
|
|
Writer.AddStmt(T->getSizeExpr());
|
|
|
|
Writer.AddSourceRange(T->getBracketsRange(), Record);
|
2010-08-19 07:57:32 +08:00
|
|
|
Code = TYPE_DEPENDENT_SIZED_ARRAY;
|
2010-06-20 03:28:53 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2010-08-19 07:56:27 +08:00
|
|
|
ASTTypeWriter::VisitDependentSizedExtVectorType(
|
2010-06-20 03:28:53 +08:00
|
|
|
const DependentSizedExtVectorType *T) {
|
|
|
|
// FIXME: Serialize this type (C++ only)
|
|
|
|
assert(false && "Cannot serialize dependent sized extended vector types");
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2010-08-19 07:56:27 +08:00
|
|
|
ASTTypeWriter::VisitTemplateTypeParmType(const TemplateTypeParmType *T) {
|
2010-06-20 03:28:53 +08:00
|
|
|
Record.push_back(T->getDepth());
|
|
|
|
Record.push_back(T->getIndex());
|
|
|
|
Record.push_back(T->isParameterPack());
|
|
|
|
Writer.AddIdentifierRef(T->getName(), Record);
|
2010-08-19 07:57:32 +08:00
|
|
|
Code = TYPE_TEMPLATE_TYPE_PARM;
|
2010-06-20 03:28:53 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2010-08-19 07:56:27 +08:00
|
|
|
ASTTypeWriter::VisitDependentNameType(const DependentNameType *T) {
|
2010-06-24 16:57:31 +08:00
|
|
|
Record.push_back(T->getKeyword());
|
|
|
|
Writer.AddNestedNameSpecifier(T->getQualifier(), Record);
|
|
|
|
Writer.AddIdentifierRef(T->getIdentifier(), Record);
|
2010-07-02 19:55:24 +08:00
|
|
|
Writer.AddTypeRef(T->isCanonicalUnqualified() ? QualType()
|
|
|
|
: T->getCanonicalTypeInternal(),
|
|
|
|
Record);
|
2010-08-19 07:57:32 +08:00
|
|
|
Code = TYPE_DEPENDENT_NAME;
|
2010-06-20 03:28:53 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2010-08-19 07:56:27 +08:00
|
|
|
ASTTypeWriter::VisitDependentTemplateSpecializationType(
|
2010-06-20 03:28:53 +08:00
|
|
|
const DependentTemplateSpecializationType *T) {
|
2010-06-26 00:24:58 +08:00
|
|
|
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);
|
2010-08-19 07:57:32 +08:00
|
|
|
Code = TYPE_DEPENDENT_TEMPLATE_SPECIALIZATION;
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
void ASTTypeWriter::VisitElaboratedType(const ElaboratedType *T) {
|
2010-05-12 05:36:43 +08:00
|
|
|
Record.push_back(T->getKeyword());
|
2010-06-26 00:24:58 +08:00
|
|
|
Writer.AddNestedNameSpecifier(T->getQualifier(), Record);
|
|
|
|
Writer.AddTypeRef(T->getNamedType(), Record);
|
2010-08-19 07:57:32 +08:00
|
|
|
Code = TYPE_ELABORATED;
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
void ASTTypeWriter::VisitInjectedClassNameType(const InjectedClassNameType *T) {
|
2010-03-10 11:28:59 +08:00
|
|
|
Writer.AddDeclRef(T->getDecl(), Record);
|
2010-04-27 08:57:59 +08:00
|
|
|
Writer.AddTypeRef(T->getInjectedSpecializationType(), Record);
|
2010-08-19 07:57:32 +08:00
|
|
|
Code = TYPE_INJECTED_CLASS_NAME;
|
2010-03-10 11:28:59 +08:00
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
void ASTTypeWriter::VisitObjCInterfaceType(const ObjCInterfaceType *T) {
|
2010-08-11 20:19:30 +08:00
|
|
|
Writer.AddDeclRef(T->getDecl(), Record);
|
2010-08-19 07:57:32 +08:00
|
|
|
Code = TYPE_OBJC_INTERFACE;
|
2010-05-15 19:32:37 +08:00
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
void ASTTypeWriter::VisitObjCObjectType(const ObjCObjectType *T) {
|
2010-05-15 19:32:37 +08:00
|
|
|
Writer.AddTypeRef(T->getBaseType(), Record);
|
2009-04-10 06:27:44 +08:00
|
|
|
Record.push_back(T->getNumProtocols());
|
2010-05-15 19:32:37 +08:00
|
|
|
for (ObjCObjectType::qual_iterator I = T->qual_begin(),
|
2009-05-28 00:21:00 +08:00
|
|
|
E = T->qual_end(); I != E; ++I)
|
|
|
|
Writer.AddDeclRef(*I, Record);
|
2010-08-19 07:57:32 +08:00
|
|
|
Code = TYPE_OBJC_OBJECT;
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
|
|
|
|
2009-06-18 06:40:22 +08:00
|
|
|
void
|
2010-08-19 07:56:27 +08:00
|
|
|
ASTTypeWriter::VisitObjCObjectPointerType(const ObjCObjectPointerType *T) {
|
2009-09-09 23:08:12 +08:00
|
|
|
Writer.AddTypeRef(T->getPointeeType(), Record);
|
2010-08-19 07:57:32 +08:00
|
|
|
Code = TYPE_OBJC_OBJECT_POINTER;
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
|
|
|
|
2009-10-17 05:56:05 +08:00
|
|
|
namespace {
|
|
|
|
|
|
|
|
class TypeLocWriter : public TypeLocVisitor<TypeLocWriter> {
|
2010-08-19 07:56:21 +08:00
|
|
|
ASTWriter &Writer;
|
|
|
|
ASTWriter::RecordData &Record;
|
2009-10-17 05:56:05 +08:00
|
|
|
|
|
|
|
public:
|
2010-08-19 07:56:21 +08:00
|
|
|
TypeLocWriter(ASTWriter &Writer, ASTWriter::RecordData &Record)
|
2009-10-17 05:56:05 +08:00
|
|
|
: Writer(Writer), Record(Record) { }
|
|
|
|
|
2009-10-18 09:05:36 +08:00
|
|
|
#define ABSTRACT_TYPELOC(CLASS, PARENT)
|
2009-10-17 05:56:05 +08:00
|
|
|
#define TYPELOC(CLASS, PARENT) \
|
2009-10-18 09:05:36 +08:00
|
|
|
void Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc);
|
2009-10-17 05:56:05 +08:00
|
|
|
#include "clang/AST/TypeLocNodes.def"
|
|
|
|
|
2009-10-18 09:05:36 +08:00
|
|
|
void VisitArrayTypeLoc(ArrayTypeLoc TyLoc);
|
|
|
|
void VisitFunctionTypeLoc(FunctionTypeLoc TyLoc);
|
2009-10-17 05:56:05 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2009-10-18 09:05:36 +08:00
|
|
|
void TypeLocWriter::VisitQualifiedTypeLoc(QualifiedTypeLoc TL) {
|
|
|
|
// nothing to do
|
|
|
|
}
|
|
|
|
void TypeLocWriter::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) {
|
2010-01-19 02:04:31 +08:00
|
|
|
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());
|
|
|
|
}
|
2009-10-18 09:05:36 +08:00
|
|
|
}
|
|
|
|
void TypeLocWriter::VisitComplexTypeLoc(ComplexTypeLoc TL) {
|
|
|
|
Writer.AddSourceLocation(TL.getNameLoc(), Record);
|
|
|
|
}
|
|
|
|
void TypeLocWriter::VisitPointerTypeLoc(PointerTypeLoc TL) {
|
|
|
|
Writer.AddSourceLocation(TL.getStarLoc(), Record);
|
|
|
|
}
|
|
|
|
void TypeLocWriter::VisitBlockPointerTypeLoc(BlockPointerTypeLoc TL) {
|
|
|
|
Writer.AddSourceLocation(TL.getCaretLoc(), Record);
|
|
|
|
}
|
|
|
|
void TypeLocWriter::VisitLValueReferenceTypeLoc(LValueReferenceTypeLoc TL) {
|
|
|
|
Writer.AddSourceLocation(TL.getAmpLoc(), Record);
|
|
|
|
}
|
|
|
|
void TypeLocWriter::VisitRValueReferenceTypeLoc(RValueReferenceTypeLoc TL) {
|
|
|
|
Writer.AddSourceLocation(TL.getAmpAmpLoc(), Record);
|
|
|
|
}
|
|
|
|
void TypeLocWriter::VisitMemberPointerTypeLoc(MemberPointerTypeLoc TL) {
|
|
|
|
Writer.AddSourceLocation(TL.getStarLoc(), Record);
|
|
|
|
}
|
|
|
|
void TypeLocWriter::VisitArrayTypeLoc(ArrayTypeLoc TL) {
|
|
|
|
Writer.AddSourceLocation(TL.getLBracketLoc(), Record);
|
|
|
|
Writer.AddSourceLocation(TL.getRBracketLoc(), Record);
|
|
|
|
Record.push_back(TL.getSizeExpr() ? 1 : 0);
|
|
|
|
if (TL.getSizeExpr())
|
|
|
|
Writer.AddStmt(TL.getSizeExpr());
|
|
|
|
}
|
|
|
|
void TypeLocWriter::VisitConstantArrayTypeLoc(ConstantArrayTypeLoc TL) {
|
|
|
|
VisitArrayTypeLoc(TL);
|
|
|
|
}
|
|
|
|
void TypeLocWriter::VisitIncompleteArrayTypeLoc(IncompleteArrayTypeLoc TL) {
|
|
|
|
VisitArrayTypeLoc(TL);
|
|
|
|
}
|
|
|
|
void TypeLocWriter::VisitVariableArrayTypeLoc(VariableArrayTypeLoc TL) {
|
|
|
|
VisitArrayTypeLoc(TL);
|
|
|
|
}
|
|
|
|
void TypeLocWriter::VisitDependentSizedArrayTypeLoc(
|
|
|
|
DependentSizedArrayTypeLoc TL) {
|
|
|
|
VisitArrayTypeLoc(TL);
|
|
|
|
}
|
|
|
|
void TypeLocWriter::VisitDependentSizedExtVectorTypeLoc(
|
|
|
|
DependentSizedExtVectorTypeLoc TL) {
|
|
|
|
Writer.AddSourceLocation(TL.getNameLoc(), Record);
|
|
|
|
}
|
|
|
|
void TypeLocWriter::VisitVectorTypeLoc(VectorTypeLoc TL) {
|
|
|
|
Writer.AddSourceLocation(TL.getNameLoc(), Record);
|
|
|
|
}
|
|
|
|
void TypeLocWriter::VisitExtVectorTypeLoc(ExtVectorTypeLoc TL) {
|
|
|
|
Writer.AddSourceLocation(TL.getNameLoc(), Record);
|
|
|
|
}
|
|
|
|
void TypeLocWriter::VisitFunctionTypeLoc(FunctionTypeLoc TL) {
|
|
|
|
Writer.AddSourceLocation(TL.getLParenLoc(), Record);
|
|
|
|
Writer.AddSourceLocation(TL.getRParenLoc(), Record);
|
2010-10-02 02:44:50 +08:00
|
|
|
Record.push_back(TL.getTrailingReturn());
|
2009-10-18 09:05:36 +08:00
|
|
|
for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i)
|
|
|
|
Writer.AddDeclRef(TL.getArg(i), Record);
|
|
|
|
}
|
|
|
|
void TypeLocWriter::VisitFunctionProtoTypeLoc(FunctionProtoTypeLoc TL) {
|
|
|
|
VisitFunctionTypeLoc(TL);
|
|
|
|
}
|
|
|
|
void TypeLocWriter::VisitFunctionNoProtoTypeLoc(FunctionNoProtoTypeLoc TL) {
|
|
|
|
VisitFunctionTypeLoc(TL);
|
|
|
|
}
|
2009-12-05 06:46:56 +08:00
|
|
|
void TypeLocWriter::VisitUnresolvedUsingTypeLoc(UnresolvedUsingTypeLoc TL) {
|
|
|
|
Writer.AddSourceLocation(TL.getNameLoc(), Record);
|
|
|
|
}
|
2009-10-18 09:05:36 +08:00
|
|
|
void TypeLocWriter::VisitTypedefTypeLoc(TypedefTypeLoc TL) {
|
|
|
|
Writer.AddSourceLocation(TL.getNameLoc(), Record);
|
|
|
|
}
|
|
|
|
void TypeLocWriter::VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL) {
|
2010-01-14 04:03:27 +08:00
|
|
|
Writer.AddSourceLocation(TL.getTypeofLoc(), Record);
|
|
|
|
Writer.AddSourceLocation(TL.getLParenLoc(), Record);
|
|
|
|
Writer.AddSourceLocation(TL.getRParenLoc(), Record);
|
2009-10-18 09:05:36 +08:00
|
|
|
}
|
|
|
|
void TypeLocWriter::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) {
|
2010-01-14 04:03:27 +08:00
|
|
|
Writer.AddSourceLocation(TL.getTypeofLoc(), Record);
|
|
|
|
Writer.AddSourceLocation(TL.getLParenLoc(), Record);
|
|
|
|
Writer.AddSourceLocation(TL.getRParenLoc(), Record);
|
|
|
|
Writer.AddTypeSourceInfo(TL.getUnderlyingTInfo(), Record);
|
2009-10-18 09:05:36 +08:00
|
|
|
}
|
|
|
|
void TypeLocWriter::VisitDecltypeTypeLoc(DecltypeTypeLoc TL) {
|
|
|
|
Writer.AddSourceLocation(TL.getNameLoc(), Record);
|
2009-10-17 05:56:05 +08:00
|
|
|
}
|
2009-10-18 09:05:36 +08:00
|
|
|
void TypeLocWriter::VisitRecordTypeLoc(RecordTypeLoc TL) {
|
|
|
|
Writer.AddSourceLocation(TL.getNameLoc(), Record);
|
2009-10-17 05:56:05 +08:00
|
|
|
}
|
2009-10-18 09:05:36 +08:00
|
|
|
void TypeLocWriter::VisitEnumTypeLoc(EnumTypeLoc TL) {
|
|
|
|
Writer.AddSourceLocation(TL.getNameLoc(), Record);
|
2009-10-17 05:56:05 +08:00
|
|
|
}
|
2009-10-18 09:05:36 +08:00
|
|
|
void TypeLocWriter::VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) {
|
|
|
|
Writer.AddSourceLocation(TL.getNameLoc(), Record);
|
2009-10-17 05:56:05 +08:00
|
|
|
}
|
2009-10-18 17:09:24 +08:00
|
|
|
void TypeLocWriter::VisitSubstTemplateTypeParmTypeLoc(
|
|
|
|
SubstTemplateTypeParmTypeLoc TL) {
|
|
|
|
Writer.AddSourceLocation(TL.getNameLoc(), Record);
|
|
|
|
}
|
2009-10-18 09:05:36 +08:00
|
|
|
void TypeLocWriter::VisitTemplateSpecializationTypeLoc(
|
|
|
|
TemplateSpecializationTypeLoc TL) {
|
2009-10-29 16:12:44 +08:00
|
|
|
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)
|
2010-06-22 17:54:59 +08:00
|
|
|
Writer.AddTemplateArgumentLocInfo(TL.getArgLoc(i).getArgument().getKind(),
|
|
|
|
TL.getArgLoc(i).getLocInfo(), Record);
|
2009-10-17 05:56:05 +08:00
|
|
|
}
|
2010-05-12 05:36:43 +08:00
|
|
|
void TypeLocWriter::VisitElaboratedTypeLoc(ElaboratedTypeLoc TL) {
|
2010-05-20 05:37:53 +08:00
|
|
|
Writer.AddSourceLocation(TL.getKeywordLoc(), Record);
|
|
|
|
Writer.AddSourceRange(TL.getQualifierRange(), Record);
|
2009-10-17 05:56:05 +08:00
|
|
|
}
|
2010-03-10 11:28:59 +08:00
|
|
|
void TypeLocWriter::VisitInjectedClassNameTypeLoc(InjectedClassNameTypeLoc TL) {
|
|
|
|
Writer.AddSourceLocation(TL.getNameLoc(), Record);
|
|
|
|
}
|
2010-04-01 01:34:00 +08:00
|
|
|
void TypeLocWriter::VisitDependentNameTypeLoc(DependentNameTypeLoc TL) {
|
2010-05-20 05:37:53 +08:00
|
|
|
Writer.AddSourceLocation(TL.getKeywordLoc(), Record);
|
|
|
|
Writer.AddSourceRange(TL.getQualifierRange(), Record);
|
2009-10-18 09:05:36 +08:00
|
|
|
Writer.AddSourceLocation(TL.getNameLoc(), Record);
|
2009-10-17 05:56:05 +08:00
|
|
|
}
|
2010-06-11 08:33:02 +08:00
|
|
|
void TypeLocWriter::VisitDependentTemplateSpecializationTypeLoc(
|
|
|
|
DependentTemplateSpecializationTypeLoc TL) {
|
|
|
|
Writer.AddSourceLocation(TL.getKeywordLoc(), Record);
|
|
|
|
Writer.AddSourceRange(TL.getQualifierRange(), Record);
|
|
|
|
Writer.AddSourceLocation(TL.getNameLoc(), Record);
|
|
|
|
Writer.AddSourceLocation(TL.getLAngleLoc(), Record);
|
|
|
|
Writer.AddSourceLocation(TL.getRAngleLoc(), Record);
|
|
|
|
for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I)
|
2010-06-22 17:54:59 +08:00
|
|
|
Writer.AddTemplateArgumentLocInfo(TL.getArgLoc(I).getArgument().getKind(),
|
|
|
|
TL.getArgLoc(I).getLocInfo(), Record);
|
2010-06-11 08:33:02 +08:00
|
|
|
}
|
2009-10-18 09:05:36 +08:00
|
|
|
void TypeLocWriter::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) {
|
|
|
|
Writer.AddSourceLocation(TL.getNameLoc(), Record);
|
2010-05-15 19:32:37 +08:00
|
|
|
}
|
|
|
|
void TypeLocWriter::VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) {
|
|
|
|
Record.push_back(TL.hasBaseTypeAsWritten());
|
2009-10-23 06:37:11 +08:00
|
|
|
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);
|
2009-10-17 05:56:05 +08:00
|
|
|
}
|
2009-10-18 09:05:36 +08:00
|
|
|
void TypeLocWriter::VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) {
|
|
|
|
Writer.AddSourceLocation(TL.getStarLoc(), Record);
|
2009-10-17 05:56:05 +08:00
|
|
|
}
|
|
|
|
|
2009-04-10 06:27:44 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
2010-08-19 07:56:21 +08:00
|
|
|
// ASTWriter Implementation
|
2009-04-10 06:27:44 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2009-04-27 06:26:21 +08:00
|
|
|
static void EmitBlockID(unsigned ID, const char *Name,
|
|
|
|
llvm::BitstreamWriter &Stream,
|
2010-08-19 07:56:21 +08:00
|
|
|
ASTWriter::RecordData &Record) {
|
2009-04-27 06:26:21 +08:00
|
|
|
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,
|
2010-08-19 07:56:21 +08:00
|
|
|
ASTWriter::RecordData &Record) {
|
2009-04-27 06:26:21 +08:00
|
|
|
Record.clear();
|
|
|
|
Record.push_back(ID);
|
|
|
|
while (*Name)
|
|
|
|
Record.push_back(*Name++);
|
|
|
|
Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, Record);
|
2009-04-27 08:49:53 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void AddStmtsExprs(llvm::BitstreamWriter &Stream,
|
2010-08-19 07:56:21 +08:00
|
|
|
ASTWriter::RecordData &Record) {
|
2010-08-19 07:57:32 +08:00
|
|
|
#define RECORD(X) EmitRecordID(X, #X, Stream, Record)
|
2009-04-27 08:49:53 +08:00
|
|
|
RECORD(STMT_STOP);
|
|
|
|
RECORD(STMT_NULL_PTR);
|
|
|
|
RECORD(STMT_NULL);
|
|
|
|
RECORD(STMT_COMPOUND);
|
|
|
|
RECORD(STMT_CASE);
|
|
|
|
RECORD(STMT_DEFAULT);
|
|
|
|
RECORD(STMT_LABEL);
|
|
|
|
RECORD(STMT_IF);
|
|
|
|
RECORD(STMT_SWITCH);
|
|
|
|
RECORD(STMT_WHILE);
|
|
|
|
RECORD(STMT_DO);
|
|
|
|
RECORD(STMT_FOR);
|
|
|
|
RECORD(STMT_GOTO);
|
|
|
|
RECORD(STMT_INDIRECT_GOTO);
|
|
|
|
RECORD(STMT_CONTINUE);
|
|
|
|
RECORD(STMT_BREAK);
|
|
|
|
RECORD(STMT_RETURN);
|
|
|
|
RECORD(STMT_DECL);
|
|
|
|
RECORD(STMT_ASM);
|
|
|
|
RECORD(EXPR_PREDEFINED);
|
|
|
|
RECORD(EXPR_DECL_REF);
|
|
|
|
RECORD(EXPR_INTEGER_LITERAL);
|
|
|
|
RECORD(EXPR_FLOATING_LITERAL);
|
|
|
|
RECORD(EXPR_IMAGINARY_LITERAL);
|
|
|
|
RECORD(EXPR_STRING_LITERAL);
|
|
|
|
RECORD(EXPR_CHARACTER_LITERAL);
|
|
|
|
RECORD(EXPR_PAREN);
|
|
|
|
RECORD(EXPR_UNARY_OPERATOR);
|
|
|
|
RECORD(EXPR_SIZEOF_ALIGN_OF);
|
|
|
|
RECORD(EXPR_ARRAY_SUBSCRIPT);
|
|
|
|
RECORD(EXPR_CALL);
|
|
|
|
RECORD(EXPR_MEMBER);
|
|
|
|
RECORD(EXPR_BINARY_OPERATOR);
|
|
|
|
RECORD(EXPR_COMPOUND_ASSIGN_OPERATOR);
|
|
|
|
RECORD(EXPR_CONDITIONAL_OPERATOR);
|
|
|
|
RECORD(EXPR_IMPLICIT_CAST);
|
|
|
|
RECORD(EXPR_CSTYLE_CAST);
|
|
|
|
RECORD(EXPR_COMPOUND_LITERAL);
|
|
|
|
RECORD(EXPR_EXT_VECTOR_ELEMENT);
|
|
|
|
RECORD(EXPR_INIT_LIST);
|
|
|
|
RECORD(EXPR_DESIGNATED_INIT);
|
|
|
|
RECORD(EXPR_IMPLICIT_VALUE_INIT);
|
|
|
|
RECORD(EXPR_VA_ARG);
|
|
|
|
RECORD(EXPR_ADDR_LABEL);
|
|
|
|
RECORD(EXPR_STMT);
|
|
|
|
RECORD(EXPR_TYPES_COMPATIBLE);
|
|
|
|
RECORD(EXPR_CHOOSE);
|
|
|
|
RECORD(EXPR_GNU_NULL);
|
|
|
|
RECORD(EXPR_SHUFFLE_VECTOR);
|
|
|
|
RECORD(EXPR_BLOCK);
|
|
|
|
RECORD(EXPR_BLOCK_DECL_REF);
|
|
|
|
RECORD(EXPR_OBJC_STRING_LITERAL);
|
|
|
|
RECORD(EXPR_OBJC_ENCODE);
|
|
|
|
RECORD(EXPR_OBJC_SELECTOR_EXPR);
|
|
|
|
RECORD(EXPR_OBJC_PROTOCOL_EXPR);
|
|
|
|
RECORD(EXPR_OBJC_IVAR_REF_EXPR);
|
|
|
|
RECORD(EXPR_OBJC_PROPERTY_REF_EXPR);
|
|
|
|
RECORD(EXPR_OBJC_KVC_REF_EXPR);
|
|
|
|
RECORD(EXPR_OBJC_MESSAGE_EXPR);
|
|
|
|
RECORD(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);
|
2010-02-07 14:32:43 +08:00
|
|
|
RECORD(EXPR_CXX_OPERATOR_CALL);
|
|
|
|
RECORD(EXPR_CXX_CONSTRUCT);
|
|
|
|
RECORD(EXPR_CXX_STATIC_CAST);
|
|
|
|
RECORD(EXPR_CXX_DYNAMIC_CAST);
|
|
|
|
RECORD(EXPR_CXX_REINTERPRET_CAST);
|
|
|
|
RECORD(EXPR_CXX_CONST_CAST);
|
|
|
|
RECORD(EXPR_CXX_FUNCTIONAL_CAST);
|
|
|
|
RECORD(EXPR_CXX_BOOL_LITERAL);
|
|
|
|
RECORD(EXPR_CXX_NULL_PTR_LITERAL);
|
2009-04-27 08:49:53 +08:00
|
|
|
#undef RECORD
|
2009-04-27 06:26:21 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-08-19 07:56:21 +08:00
|
|
|
void ASTWriter::WriteBlockInfoBlock() {
|
2009-04-27 06:26:21 +08:00
|
|
|
RecordData Record;
|
|
|
|
Stream.EnterSubblock(llvm::bitc::BLOCKINFO_BLOCK_ID, 3);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-08-19 07:57:32 +08:00
|
|
|
#define BLOCK(X) EmitBlockID(X ## _ID, #X, Stream, Record)
|
|
|
|
#define RECORD(X) EmitRecordID(X, #X, Stream, Record)
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
// AST Top-Level Block.
|
2010-08-19 07:57:22 +08:00
|
|
|
BLOCK(AST_BLOCK);
|
2009-06-03 17:23:28 +08:00
|
|
|
RECORD(ORIGINAL_FILE_NAME);
|
2009-04-27 06:26:21 +08:00
|
|
|
RECORD(TYPE_OFFSET);
|
|
|
|
RECORD(DECL_OFFSET);
|
|
|
|
RECORD(LANGUAGE_OPTIONS);
|
2009-04-28 06:23:34 +08:00
|
|
|
RECORD(METADATA);
|
2009-04-27 06:26:21 +08:00
|
|
|
RECORD(IDENTIFIER_OFFSET);
|
|
|
|
RECORD(IDENTIFIER_TABLE);
|
|
|
|
RECORD(EXTERNAL_DEFINITIONS);
|
|
|
|
RECORD(SPECIAL_TYPES);
|
|
|
|
RECORD(STATISTICS);
|
|
|
|
RECORD(TENTATIVE_DEFINITIONS);
|
2010-08-14 02:42:17 +08:00
|
|
|
RECORD(UNUSED_FILESCOPED_DECLS);
|
2009-04-27 06:26:21 +08:00
|
|
|
RECORD(LOCALLY_SCOPED_EXTERNAL_DECLS);
|
|
|
|
RECORD(SELECTOR_OFFSETS);
|
|
|
|
RECORD(METHOD_POOL);
|
|
|
|
RECORD(PP_COUNTER_VALUE);
|
2009-04-27 14:38:32 +08:00
|
|
|
RECORD(SOURCE_LOCATION_OFFSETS);
|
|
|
|
RECORD(SOURCE_LOCATION_PRELOADS);
|
2009-04-28 02:38:38 +08:00
|
|
|
RECORD(STAT_CACHE);
|
2009-04-28 04:06:05 +08:00
|
|
|
RECORD(EXT_VECTOR_DECLS);
|
2010-01-23 04:59:36 +08:00
|
|
|
RECORD(VERSION_CONTROL_BRANCH_REVISION);
|
Implement serialization and lazy deserialization of the preprocessing
record (which includes all macro instantiations and definitions). As
with all lay deserialization, this introduces a new external source
(here, an external preprocessing record source) that loads all of the
preprocessed entities prior to iterating over the entities.
The preprocessing record is an optional part of the precompiled header
that is disabled by default (enabled with
-detailed-preprocessing-record). When the preprocessor given to the
PCH writer has a preprocessing record, that record is written into the
PCH file. When the PCH reader is given a PCH file that contains a
preprocessing record, it will be lazily loaded (which, effectively,
implicitly adds -detailed-preprocessing-record). This is the first
case where we have sections of the precompiled header that are
added/removed based on a compilation flag, which is
unfortunate. However, this data consumes ~550k in the PCH file for
Cocoa.h (out of ~9.9MB), and there is a non-trivial cost to gathering
this detailed preprocessing information, so it's too expensive to turn
on by default. In the future, we should investigate a better encoding
of this information.
llvm-svn: 99002
2010-03-20 05:51:54 +08:00
|
|
|
RECORD(MACRO_DEFINITION_OFFSETS);
|
2010-07-09 06:01:51 +08:00
|
|
|
RECORD(CHAINED_METADATA);
|
2010-07-24 03:11:11 +08:00
|
|
|
RECORD(REFERENCED_SELECTOR_POOL);
|
Implement serialization and lazy deserialization of the preprocessing
record (which includes all macro instantiations and definitions). As
with all lay deserialization, this introduces a new external source
(here, an external preprocessing record source) that loads all of the
preprocessed entities prior to iterating over the entities.
The preprocessing record is an optional part of the precompiled header
that is disabled by default (enabled with
-detailed-preprocessing-record). When the preprocessor given to the
PCH writer has a preprocessing record, that record is written into the
PCH file. When the PCH reader is given a PCH file that contains a
preprocessing record, it will be lazily loaded (which, effectively,
implicitly adds -detailed-preprocessing-record). This is the first
case where we have sections of the precompiled header that are
added/removed based on a compilation flag, which is
unfortunate. However, this data consumes ~550k in the PCH file for
Cocoa.h (out of ~9.9MB), and there is a non-trivial cost to gathering
this detailed preprocessing information, so it's too expensive to turn
on by default. In the future, we should investigate a better encoding
of this information.
llvm-svn: 99002
2010-03-20 05:51:54 +08:00
|
|
|
|
2009-04-27 06:26:21 +08:00
|
|
|
// SourceManager Block.
|
2009-04-27 08:40:25 +08:00
|
|
|
BLOCK(SOURCE_MANAGER_BLOCK);
|
2009-04-27 06:26:21 +08:00
|
|
|
RECORD(SM_SLOC_FILE_ENTRY);
|
|
|
|
RECORD(SM_SLOC_BUFFER_ENTRY);
|
|
|
|
RECORD(SM_SLOC_BUFFER_BLOB);
|
|
|
|
RECORD(SM_SLOC_INSTANTIATION_ENTRY);
|
|
|
|
RECORD(SM_LINE_TABLE);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-04-27 06:26:21 +08:00
|
|
|
// Preprocessor Block.
|
2009-04-27 08:40:25 +08:00
|
|
|
BLOCK(PREPROCESSOR_BLOCK);
|
2009-04-27 06:26:21 +08:00
|
|
|
RECORD(PP_MACRO_OBJECT_LIKE);
|
|
|
|
RECORD(PP_MACRO_FUNCTION_LIKE);
|
|
|
|
RECORD(PP_TOKEN);
|
Implement serialization and lazy deserialization of the preprocessing
record (which includes all macro instantiations and definitions). As
with all lay deserialization, this introduces a new external source
(here, an external preprocessing record source) that loads all of the
preprocessed entities prior to iterating over the entities.
The preprocessing record is an optional part of the precompiled header
that is disabled by default (enabled with
-detailed-preprocessing-record). When the preprocessor given to the
PCH writer has a preprocessing record, that record is written into the
PCH file. When the PCH reader is given a PCH file that contains a
preprocessing record, it will be lazily loaded (which, effectively,
implicitly adds -detailed-preprocessing-record). This is the first
case where we have sections of the precompiled header that are
added/removed based on a compilation flag, which is
unfortunate. However, this data consumes ~550k in the PCH file for
Cocoa.h (out of ~9.9MB), and there is a non-trivial cost to gathering
this detailed preprocessing information, so it's too expensive to turn
on by default. In the future, we should investigate a better encoding
of this information.
llvm-svn: 99002
2010-03-20 05:51:54 +08:00
|
|
|
RECORD(PP_MACRO_INSTANTIATION);
|
|
|
|
RECORD(PP_MACRO_DEFINITION);
|
|
|
|
|
2009-10-17 08:13:19 +08:00
|
|
|
// Decls and Types block.
|
|
|
|
BLOCK(DECLTYPES_BLOCK);
|
2009-04-27 06:26:21 +08:00
|
|
|
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);
|
2010-05-16 10:12:35 +08:00
|
|
|
RECORD(TYPE_OBJC_OBJECT);
|
2009-06-18 06:40:22 +08:00
|
|
|
RECORD(TYPE_OBJC_OBJECT_POINTER);
|
2009-04-27 06:32:16 +08:00
|
|
|
RECORD(DECL_ATTR);
|
|
|
|
RECORD(DECL_TRANSLATION_UNIT);
|
|
|
|
RECORD(DECL_TYPEDEF);
|
|
|
|
RECORD(DECL_ENUM);
|
|
|
|
RECORD(DECL_RECORD);
|
|
|
|
RECORD(DECL_ENUM_CONSTANT);
|
|
|
|
RECORD(DECL_FUNCTION);
|
|
|
|
RECORD(DECL_OBJC_METHOD);
|
|
|
|
RECORD(DECL_OBJC_INTERFACE);
|
|
|
|
RECORD(DECL_OBJC_PROTOCOL);
|
|
|
|
RECORD(DECL_OBJC_IVAR);
|
|
|
|
RECORD(DECL_OBJC_AT_DEFS_FIELD);
|
|
|
|
RECORD(DECL_OBJC_CLASS);
|
|
|
|
RECORD(DECL_OBJC_FORWARD_PROTOCOL);
|
|
|
|
RECORD(DECL_OBJC_CATEGORY);
|
|
|
|
RECORD(DECL_OBJC_CATEGORY_IMPL);
|
|
|
|
RECORD(DECL_OBJC_IMPLEMENTATION);
|
|
|
|
RECORD(DECL_OBJC_COMPATIBLE_ALIAS);
|
|
|
|
RECORD(DECL_OBJC_PROPERTY);
|
|
|
|
RECORD(DECL_OBJC_PROPERTY_IMPL);
|
2009-04-27 06:26:21 +08:00
|
|
|
RECORD(DECL_FIELD);
|
|
|
|
RECORD(DECL_VAR);
|
2009-04-27 06:32:16 +08:00
|
|
|
RECORD(DECL_IMPLICIT_PARAM);
|
2009-04-27 06:26:21 +08:00
|
|
|
RECORD(DECL_PARM_VAR);
|
2009-04-27 06:32:16 +08:00
|
|
|
RECORD(DECL_FILE_SCOPE_ASM);
|
|
|
|
RECORD(DECL_BLOCK);
|
|
|
|
RECORD(DECL_CONTEXT_LEXICAL);
|
|
|
|
RECORD(DECL_CONTEXT_VISIBLE);
|
2009-10-17 08:13:19 +08:00
|
|
|
// Statements and Exprs can occur in the Decls and Types block.
|
2009-04-27 08:49:53 +08:00
|
|
|
AddStmtsExprs(Stream, Record);
|
2009-04-27 06:26:21 +08:00
|
|
|
#undef RECORD
|
|
|
|
#undef BLOCK
|
|
|
|
Stream.ExitBlock();
|
|
|
|
}
|
|
|
|
|
2009-07-07 08:12:59 +08:00
|
|
|
/// \brief Adjusts the given filename to only write out the portion of the
|
|
|
|
/// filename that is not part of the system root directory.
|
2009-09-09 23:08:12 +08:00
|
|
|
///
|
2009-07-07 08:12:59 +08:00
|
|
|
/// \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).
|
2009-09-09 23:08:12 +08:00
|
|
|
static const char *
|
2009-07-07 08:12:59 +08:00
|
|
|
adjustFilenameForRelocatablePCH(const char *Filename, const char *isysroot) {
|
|
|
|
assert(Filename && "No file name to adjust?");
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-07 08:12:59 +08:00
|
|
|
if (!isysroot)
|
|
|
|
return Filename;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-07 08:12:59 +08:00
|
|
|
// Verify that the filename and the system root have the same prefix.
|
|
|
|
unsigned Pos = 0;
|
|
|
|
for (; Filename[Pos] && isysroot[Pos]; ++Pos)
|
|
|
|
if (Filename[Pos] != isysroot[Pos])
|
|
|
|
return Filename; // Prefixes don't match.
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-07 08:12:59 +08:00
|
|
|
// We hit the end of the filename before we hit the end of the system root.
|
|
|
|
if (!Filename[Pos])
|
|
|
|
return Filename;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-07 08:12:59 +08:00
|
|
|
// 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;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-07 08:12:59 +08:00
|
|
|
return Filename + Pos;
|
|
|
|
}
|
2009-04-27 06:26:21 +08:00
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
/// \brief Write the AST metadata (e.g., i686-apple-darwin9).
|
2010-08-19 07:56:21 +08:00
|
|
|
void ASTWriter::WriteMetadata(ASTContext &Context, const char *isysroot) {
|
2009-04-11 05:16:55 +08:00
|
|
|
using namespace llvm;
|
2009-05-12 09:31:05 +08:00
|
|
|
|
2009-07-07 08:12:59 +08:00
|
|
|
// Metadata
|
|
|
|
const TargetInfo &Target = Context.Target;
|
|
|
|
BitCodeAbbrev *MetaAbbrev = new BitCodeAbbrev();
|
2010-07-10 05:00:24 +08:00
|
|
|
MetaAbbrev->Add(BitCodeAbbrevOp(
|
2010-08-19 07:57:32 +08:00
|
|
|
Chain ? CHAINED_METADATA : METADATA));
|
2010-08-19 07:56:27 +08:00
|
|
|
MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // AST major
|
|
|
|
MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // AST minor
|
2009-07-07 08:12:59 +08:00
|
|
|
MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Clang major
|
|
|
|
MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Clang minor
|
|
|
|
MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Relocatable
|
2010-07-10 05:00:24 +08:00
|
|
|
// Target triple or chained PCH name
|
|
|
|
MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
|
2009-07-07 08:12:59 +08:00
|
|
|
unsigned MetaAbbrevCode = Stream.EmitAbbrev(MetaAbbrev);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-07 08:12:59 +08:00
|
|
|
RecordData Record;
|
2010-08-19 07:57:32 +08:00
|
|
|
Record.push_back(Chain ? CHAINED_METADATA : METADATA);
|
|
|
|
Record.push_back(VERSION_MAJOR);
|
|
|
|
Record.push_back(VERSION_MINOR);
|
2009-07-07 08:12:59 +08:00
|
|
|
Record.push_back(CLANG_VERSION_MAJOR);
|
|
|
|
Record.push_back(CLANG_VERSION_MINOR);
|
|
|
|
Record.push_back(isysroot != 0);
|
2010-07-10 05:00:24 +08:00
|
|
|
// FIXME: This writes the absolute path for chained headers.
|
|
|
|
const std::string &BlobStr = Chain ? Chain->getFileName() : Target.getTriple().getTriple();
|
|
|
|
Stream.EmitRecordWithBlob(MetaAbbrevCode, Record, BlobStr);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-05-12 09:31:05 +08:00
|
|
|
// Original file name
|
|
|
|
SourceManager &SM = Context.getSourceManager();
|
|
|
|
if (const FileEntry *MainFile = SM.getFileEntryForID(SM.getMainFileID())) {
|
|
|
|
BitCodeAbbrev *FileAbbrev = new BitCodeAbbrev();
|
2010-08-19 07:57:32 +08:00
|
|
|
FileAbbrev->Add(BitCodeAbbrevOp(ORIGINAL_FILE_NAME));
|
2009-05-12 09:31:05 +08:00
|
|
|
FileAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name
|
|
|
|
unsigned FileAbbrevCode = Stream.EmitAbbrev(FileAbbrev);
|
|
|
|
|
|
|
|
llvm::sys::Path MainFilePath(MainFile->getName());
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-03-14 15:06:50 +08:00
|
|
|
MainFilePath.makeAbsolute();
|
2009-05-12 09:31:05 +08:00
|
|
|
|
2010-03-14 15:15:57 +08:00
|
|
|
const char *MainFileNameStr = MainFilePath.c_str();
|
2009-09-09 23:08:12 +08:00
|
|
|
MainFileNameStr = adjustFilenameForRelocatablePCH(MainFileNameStr,
|
2009-07-07 08:12:59 +08:00
|
|
|
isysroot);
|
2009-05-12 09:31:05 +08:00
|
|
|
RecordData Record;
|
2010-08-19 07:57:32 +08:00
|
|
|
Record.push_back(ORIGINAL_FILE_NAME);
|
2009-08-24 17:31:37 +08:00
|
|
|
Stream.EmitRecordWithBlob(FileAbbrevCode, Record, MainFileNameStr);
|
2009-05-12 09:31:05 +08:00
|
|
|
}
|
2010-03-14 15:06:50 +08:00
|
|
|
|
2010-01-23 06:12:47 +08:00
|
|
|
// Repository branch/version information.
|
|
|
|
BitCodeAbbrev *RepoAbbrev = new BitCodeAbbrev();
|
2010-08-19 07:57:32 +08:00
|
|
|
RepoAbbrev->Add(BitCodeAbbrevOp(VERSION_CONTROL_BRANCH_REVISION));
|
2010-01-23 06:12:47 +08:00
|
|
|
RepoAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // SVN branch/tag
|
|
|
|
unsigned RepoAbbrevCode = Stream.EmitAbbrev(RepoAbbrev);
|
2009-10-06 05:07:28 +08:00
|
|
|
Record.clear();
|
2010-08-19 07:57:32 +08:00
|
|
|
Record.push_back(VERSION_CONTROL_BRANCH_REVISION);
|
2010-01-23 06:12:47 +08:00
|
|
|
Stream.EmitRecordWithBlob(RepoAbbrevCode, Record,
|
|
|
|
getClangFullRepositoryVersion());
|
2009-04-11 05:16:55 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Write the LangOptions structure.
|
2010-08-19 07:56:21 +08:00
|
|
|
void ASTWriter::WriteLanguageOptions(const LangOptions &LangOpts) {
|
2009-04-11 04:39:37 +08:00
|
|
|
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)
|
2010-04-18 04:17:31 +08:00
|
|
|
Record.push_back(LangOpts.GNUKeywords); // Allow GNU-extension keywords
|
2009-04-11 04:39:37 +08:00
|
|
|
Record.push_back(LangOpts.ImplicitInt); // C89 implicit 'int'.
|
|
|
|
Record.push_back(LangOpts.Digraphs); // C94, C99 and C++
|
|
|
|
Record.push_back(LangOpts.HexFloats); // C99 Hexadecimal float constants.
|
|
|
|
Record.push_back(LangOpts.C99); // C99 Support
|
|
|
|
Record.push_back(LangOpts.Microsoft); // Microsoft extensions.
|
|
|
|
Record.push_back(LangOpts.CPlusPlus); // C++ Support
|
|
|
|
Record.push_back(LangOpts.CPlusPlus0x); // C++0x Support
|
|
|
|
Record.push_back(LangOpts.CXXOperatorNames); // Treat C++ operator names as keywords.
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-04-11 04:39:37 +08:00
|
|
|
Record.push_back(LangOpts.ObjC1); // Objective-C 1 support enabled.
|
|
|
|
Record.push_back(LangOpts.ObjC2); // Objective-C 2 support enabled.
|
2010-03-14 15:06:50 +08:00
|
|
|
Record.push_back(LangOpts.ObjCNonFragileABI); // Objective-C
|
2010-02-10 03:31:38 +08:00
|
|
|
// modern abi enabled.
|
2010-03-14 15:06:50 +08:00
|
|
|
Record.push_back(LangOpts.ObjCNonFragileABI2); // Objective-C enhanced
|
2010-02-10 03:31:38 +08:00
|
|
|
// modern abi enabled.
|
2010-04-23 05:01:59 +08:00
|
|
|
Record.push_back(LangOpts.NoConstantCFStrings); // non cfstring generation enabled..
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-04-11 04:39:37 +08:00
|
|
|
Record.push_back(LangOpts.PascalStrings); // Allow Pascal strings
|
|
|
|
Record.push_back(LangOpts.WritableStrings); // Allow writable strings
|
|
|
|
Record.push_back(LangOpts.LaxVectorConversions);
|
2009-06-26 07:01:11 +08:00
|
|
|
Record.push_back(LangOpts.AltiVec);
|
2009-04-11 04:39:37 +08:00
|
|
|
Record.push_back(LangOpts.Exceptions); // Support exception handling.
|
2010-02-11 02:48:44 +08:00
|
|
|
Record.push_back(LangOpts.SjLjExceptions);
|
2009-04-11 04:39:37 +08:00
|
|
|
|
|
|
|
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)
|
|
|
|
|
2009-04-27 15:35:58 +08:00
|
|
|
// Whether static initializers are protected by locks.
|
|
|
|
Record.push_back(LangOpts.ThreadsafeStatics);
|
2009-09-03 22:36:33 +08:00
|
|
|
Record.push_back(LangOpts.POSIXThreads);
|
2009-04-11 04:39:37 +08:00
|
|
|
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).
|
|
|
|
|
2010-06-27 05:25:03 +08:00
|
|
|
Record.push_back(LangOpts.getSignedOverflowBehavior());
|
|
|
|
Record.push_back(LangOpts.HeinousExtensions);
|
2009-04-11 04:39:37 +08:00
|
|
|
|
|
|
|
Record.push_back(LangOpts.Optimize); // Whether __OPTIMIZE__ should be defined.
|
2009-09-09 23:08:12 +08:00
|
|
|
Record.push_back(LangOpts.OptimizeSize); // Whether __OPTIMIZE_SIZE__ should be
|
2009-04-11 04:39:37 +08:00
|
|
|
// 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.
|
2009-05-14 03:49:53 +08:00
|
|
|
Record.push_back(LangOpts.AccessControl); // Whether C++ access control should
|
|
|
|
// be enabled.
|
2009-06-05 15:05:05 +08:00
|
|
|
Record.push_back(LangOpts.CharIsSigned); // Whether char is a signed or
|
|
|
|
// unsigned type
|
2009-11-06 04:14:16 +08:00
|
|
|
Record.push_back(LangOpts.ShortWChar); // force wchar_t to be unsigned short
|
2009-04-11 04:39:37 +08:00
|
|
|
Record.push_back(LangOpts.getGCMode());
|
|
|
|
Record.push_back(LangOpts.getVisibilityMode());
|
2009-09-21 12:16:19 +08:00
|
|
|
Record.push_back(LangOpts.getStackProtectorMode());
|
2009-04-11 04:39:37 +08:00
|
|
|
Record.push_back(LangOpts.InstantiationDepth);
|
2009-06-26 07:01:11 +08:00
|
|
|
Record.push_back(LangOpts.OpenCL);
|
2009-12-12 09:27:46 +08:00
|
|
|
Record.push_back(LangOpts.CatchUndefined);
|
2009-08-23 06:30:33 +08:00
|
|
|
Record.push_back(LangOpts.ElideConstructors);
|
2010-07-10 01:35:33 +08:00
|
|
|
Record.push_back(LangOpts.SpellChecking);
|
2010-08-19 07:57:32 +08:00
|
|
|
Stream.EmitRecord(LANGUAGE_OPTIONS, Record);
|
2009-04-11 04:39:37 +08:00
|
|
|
}
|
|
|
|
|
2009-04-28 02:38:38 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// stat cache Serialization
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
// Trait used for the on-disk hash table of stat cache results.
|
2010-08-19 07:56:27 +08:00
|
|
|
class ASTStatCacheTrait {
|
2009-04-28 02:38:38 +08:00
|
|
|
public:
|
|
|
|
typedef const char * key_type;
|
|
|
|
typedef key_type key_type_ref;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-04-28 02:38:38 +08:00
|
|
|
typedef std::pair<int, struct stat> data_type;
|
|
|
|
typedef const data_type& data_type_ref;
|
|
|
|
|
|
|
|
static unsigned ComputeHash(const char *path) {
|
2009-10-18 07:52:28 +08:00
|
|
|
return llvm::HashString(path);
|
2009-04-28 02:38:38 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
|
|
|
std::pair<unsigned,unsigned>
|
2009-04-28 02:38:38 +08:00
|
|
|
EmitKeyDataLength(llvm::raw_ostream& Out, const char *path,
|
|
|
|
data_type_ref Data) {
|
|
|
|
unsigned StrLen = strlen(path);
|
|
|
|
clang::io::Emit16(Out, StrLen);
|
|
|
|
unsigned DataLen = 1; // result value
|
|
|
|
if (Data.first == 0)
|
|
|
|
DataLen += 4 + 4 + 2 + 8 + 8;
|
|
|
|
clang::io::Emit8(Out, DataLen);
|
|
|
|
return std::make_pair(StrLen + 1, DataLen);
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-04-28 02:38:38 +08:00
|
|
|
void EmitKey(llvm::raw_ostream& Out, const char *path, unsigned KeyLen) {
|
|
|
|
Out.write(path, KeyLen);
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-04-28 02:38:38 +08:00
|
|
|
void EmitData(llvm::raw_ostream& Out, key_type_ref,
|
|
|
|
data_type_ref Data, unsigned DataLen) {
|
|
|
|
using namespace clang::io;
|
|
|
|
uint64_t Start = Out.tell(); (void)Start;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-04-28 02:38:38 +08:00
|
|
|
// Result of stat()
|
|
|
|
Emit8(Out, Data.first? 1 : 0);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-04-28 02:38:38 +08:00
|
|
|
if (Data.first == 0) {
|
|
|
|
Emit32(Out, (uint32_t) Data.second.st_ino);
|
|
|
|
Emit32(Out, (uint32_t) Data.second.st_dev);
|
|
|
|
Emit16(Out, (uint16_t) Data.second.st_mode);
|
|
|
|
Emit64(Out, (uint64_t) Data.second.st_mtime);
|
|
|
|
Emit64(Out, (uint64_t) Data.second.st_size);
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(Out.tell() - Start == DataLen && "Wrong data length");
|
|
|
|
}
|
|
|
|
};
|
|
|
|
} // end anonymous namespace
|
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
/// \brief Write the stat() system call cache to the AST file.
|
2010-08-19 07:56:21 +08:00
|
|
|
void ASTWriter::WriteStatCache(MemorizeStatCalls &StatCalls) {
|
2009-04-28 02:38:38 +08:00
|
|
|
// Build the on-disk hash table containing information about every
|
|
|
|
// stat() call.
|
2010-08-19 07:56:27 +08:00
|
|
|
OnDiskChainedHashTableGenerator<ASTStatCacheTrait> Generator;
|
2009-04-28 02:38:38 +08:00
|
|
|
unsigned NumStatEntries = 0;
|
2009-09-09 23:08:12 +08:00
|
|
|
for (MemorizeStatCalls::iterator Stat = StatCalls.begin(),
|
2009-04-28 02:38:38 +08:00
|
|
|
StatEnd = StatCalls.end();
|
2009-07-07 08:12:59 +08:00
|
|
|
Stat != StatEnd; ++Stat, ++NumStatEntries) {
|
|
|
|
const char *Filename = Stat->first();
|
|
|
|
Generator.insert(Filename, Stat->second);
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-04-28 02:38:38 +08:00
|
|
|
// Create the on-disk hash table in a buffer.
|
2009-09-09 23:08:12 +08:00
|
|
|
llvm::SmallString<4096> StatCacheData;
|
2009-04-28 02:38:38 +08:00
|
|
|
uint32_t BucketOffset;
|
|
|
|
{
|
|
|
|
llvm::raw_svector_ostream Out(StatCacheData);
|
|
|
|
// Make sure that no bucket is at offset 0
|
|
|
|
clang::io::Emit32(Out, 0);
|
|
|
|
BucketOffset = Generator.Emit(Out);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create a blob abbreviation
|
|
|
|
using namespace llvm;
|
|
|
|
BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
|
2010-08-19 07:57:32 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(STAT_CACHE));
|
2009-04-28 02:38:38 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
|
|
|
|
unsigned StatCacheAbbrev = Stream.EmitAbbrev(Abbrev);
|
|
|
|
|
|
|
|
// Write the stat cache
|
|
|
|
RecordData Record;
|
2010-08-19 07:57:32 +08:00
|
|
|
Record.push_back(STAT_CACHE);
|
2009-04-28 02:38:38 +08:00
|
|
|
Record.push_back(BucketOffset);
|
|
|
|
Record.push_back(NumStatEntries);
|
2009-08-24 17:31:37 +08:00
|
|
|
Stream.EmitRecordWithBlob(StatCacheAbbrev, Record, StatCacheData.str());
|
2009-04-28 02:38:38 +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();
|
2010-08-19 07:57:32 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(SM_SLOC_FILE_ENTRY));
|
2009-04-10 11:52:48 +08:00
|
|
|
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
|
2010-03-22 06:49:54 +08:00
|
|
|
// FileEntry fields.
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 12)); // Size
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 32)); // Modification time
|
2010-03-17 00:35:32 +08:00
|
|
|
// HeaderFileInfo fields.
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isImport
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // DirInfo
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // NumIncludes
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // ControllingMacro
|
2009-04-10 11:52:48 +08:00
|
|
|
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();
|
2010-08-19 07:57:32 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(SM_SLOC_BUFFER_ENTRY));
|
2009-04-10 11:52:48 +08:00
|
|
|
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();
|
2010-08-19 07:57:32 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(SM_SLOC_BUFFER_BLOB));
|
2009-04-10 11:52:48 +08:00
|
|
|
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();
|
2010-08-19 07:57:32 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(SM_SLOC_INSTANTIATION_ENTRY));
|
2009-04-10 11:52:48 +08:00
|
|
|
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.
|
2010-08-19 07:56:21 +08:00
|
|
|
void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
|
2009-07-07 08:12:59 +08:00
|
|
|
const Preprocessor &PP,
|
|
|
|
const char *isysroot) {
|
2009-04-27 14:38:32 +08:00
|
|
|
RecordData Record;
|
|
|
|
|
2009-04-11 01:16:57 +08:00
|
|
|
// Enter the source manager block.
|
2010-08-19 07:57:32 +08:00
|
|
|
Stream.EnterSubblock(SOURCE_MANAGER_BLOCK_ID, 3);
|
2009-04-10 11:52:48 +08:00
|
|
|
|
|
|
|
// Abbreviations for the various kinds of source-location entries.
|
2009-04-28 03:03:22 +08:00
|
|
|
unsigned SLocFileAbbrv = CreateSLocFileAbbrev(Stream);
|
|
|
|
unsigned SLocBufferAbbrv = CreateSLocBufferAbbrev(Stream);
|
|
|
|
unsigned SLocBufferBlobAbbrv = CreateSLocBufferBlobAbbrev(Stream);
|
|
|
|
unsigned SLocInstantiationAbbrv = CreateSLocInstantiationAbbrev(Stream);
|
2009-04-27 14:38:32 +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);
|
2009-07-07 08:12:59 +08:00
|
|
|
Filename = adjustFilenameForRelocatablePCH(Filename, isysroot);
|
2009-04-27 14:38:32 +08:00
|
|
|
unsigned FilenameLen = Filename? strlen(Filename) : 0;
|
|
|
|
Record.push_back(FilenameLen);
|
|
|
|
if (FilenameLen)
|
|
|
|
Record.insert(Record.end(), Filename, Filename + FilenameLen);
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-04-27 14:38:32 +08:00
|
|
|
// 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);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-04-27 14:38:32 +08:00
|
|
|
// Emit the line entries
|
|
|
|
Record.push_back(L->second.size());
|
2009-09-09 23:08:12 +08:00
|
|
|
for (std::vector<LineEntry>::iterator LE = L->second.begin(),
|
2009-04-27 14:38:32 +08:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
2010-08-19 07:57:32 +08:00
|
|
|
Stream.EmitRecord(SM_LINE_TABLE, Record);
|
2009-04-27 14:38:32 +08:00
|
|
|
}
|
|
|
|
|
2009-04-10 11:52:48 +08:00
|
|
|
// Write out the source location entry table. We skip the first
|
|
|
|
// entry, which is always the same dummy entry.
|
2009-04-28 03:01:47 +08:00
|
|
|
std::vector<uint32_t> SLocEntryOffsets;
|
2009-04-27 14:38:32 +08:00
|
|
|
RecordData PreloadSLocs;
|
2010-07-23 01:01:13 +08:00
|
|
|
unsigned BaseSLocID = Chain ? Chain->getTotalNumSLocs() : 0;
|
|
|
|
SLocEntryOffsets.reserve(SourceMgr.sloc_entry_size() - 1 - BaseSLocID);
|
|
|
|
for (unsigned I = BaseSLocID + 1, N = SourceMgr.sloc_entry_size();
|
|
|
|
I != N; ++I) {
|
2009-10-17 06:46:09 +08:00
|
|
|
// Get this source location entry.
|
|
|
|
const SrcMgr::SLocEntry *SLoc = &SourceMgr.getSLocEntry(I);
|
2010-03-14 15:06:50 +08:00
|
|
|
|
2009-04-27 14:38:32 +08:00
|
|
|
// Record the offset of this source-location entry.
|
|
|
|
SLocEntryOffsets.push_back(Stream.GetCurrentBitNo());
|
|
|
|
|
2009-04-10 11:52:48 +08:00
|
|
|
// Figure out which record code to use.
|
|
|
|
unsigned Code;
|
|
|
|
if (SLoc->isFile()) {
|
|
|
|
if (SLoc->getFile().getContentCache()->Entry)
|
2010-08-19 07:57:32 +08:00
|
|
|
Code = SM_SLOC_FILE_ENTRY;
|
2009-04-10 11:52:48 +08:00
|
|
|
else
|
2010-08-19 07:57:32 +08:00
|
|
|
Code = SM_SLOC_BUFFER_ENTRY;
|
2009-04-10 11:52:48 +08:00
|
|
|
} else
|
2010-08-19 07:57:32 +08:00
|
|
|
Code = SM_SLOC_INSTANTIATION_ENTRY;
|
2009-04-27 14:38:32 +08:00
|
|
|
Record.clear();
|
2009-04-10 11:52:48 +08:00
|
|
|
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.
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-03-22 06:49:54 +08:00
|
|
|
// Emit size/modification time for this file.
|
|
|
|
Record.push_back(Content->Entry->getSize());
|
|
|
|
Record.push_back(Content->Entry->getModificationTime());
|
|
|
|
|
2010-03-17 00:35:32 +08:00
|
|
|
// Emit header-search information associated with this file.
|
|
|
|
HeaderFileInfo HFI;
|
|
|
|
HeaderSearch &HS = PP.getHeaderSearchInfo();
|
|
|
|
if (Content->Entry->getUID() < HS.header_file_size())
|
|
|
|
HFI = HS.header_file_begin()[Content->Entry->getUID()];
|
|
|
|
Record.push_back(HFI.isImport);
|
|
|
|
Record.push_back(HFI.DirInfo);
|
|
|
|
Record.push_back(HFI.NumIncludes);
|
|
|
|
AddIdentifierRef(HFI.ControllingMacro, Record);
|
|
|
|
|
2009-07-07 08:12:59 +08:00
|
|
|
// Turn the file name into an absolute path, if it isn't already.
|
|
|
|
const char *Filename = Content->Entry->getName();
|
|
|
|
llvm::sys::Path FilePath(Filename, strlen(Filename));
|
2010-03-14 15:06:50 +08:00
|
|
|
FilePath.makeAbsolute();
|
2010-03-14 15:15:57 +08:00
|
|
|
Filename = FilePath.c_str();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-07 08:12:59 +08:00
|
|
|
Filename = adjustFilenameForRelocatablePCH(Filename, isysroot);
|
2009-08-24 17:31:37 +08:00
|
|
|
Stream.EmitRecordWithBlob(SLocFileAbbrv, Record, Filename);
|
2009-04-27 14:38:32 +08:00
|
|
|
|
|
|
|
// FIXME: For now, preload all file source locations, so that
|
|
|
|
// we get the appropriate File entries in the reader. This is
|
|
|
|
// a temporary measure.
|
2010-07-23 01:01:13 +08:00
|
|
|
PreloadSLocs.push_back(BaseSLocID + SLocEntryOffsets.size());
|
2009-04-10 11:52:48 +08:00
|
|
|
} 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).
|
2010-03-16 08:35:39 +08:00
|
|
|
const llvm::MemoryBuffer *Buffer
|
2010-04-21 04:35:58 +08:00
|
|
|
= Content->getBuffer(PP.getDiagnostics(), PP.getSourceManager());
|
2009-04-10 11:52:48 +08:00
|
|
|
const char *Name = Buffer->getBufferIdentifier();
|
2009-08-24 17:31:37 +08:00
|
|
|
Stream.EmitRecordWithBlob(SLocBufferAbbrv, Record,
|
|
|
|
llvm::StringRef(Name, strlen(Name) + 1));
|
2009-04-10 11:52:48 +08:00
|
|
|
Record.clear();
|
2010-08-19 07:57:32 +08:00
|
|
|
Record.push_back(SM_SLOC_BUFFER_BLOB);
|
2009-04-17 06:23:12 +08:00
|
|
|
Stream.EmitRecordWithBlob(SLocBufferBlobAbbrv, Record,
|
2009-08-24 17:31:37 +08:00
|
|
|
llvm::StringRef(Buffer->getBufferStart(),
|
|
|
|
Buffer->getBufferSize() + 1));
|
2009-04-27 14:38:32 +08:00
|
|
|
|
|
|
|
if (strcmp(Name, "<built-in>") == 0)
|
2010-07-23 01:01:13 +08:00
|
|
|
PreloadSLocs.push_back(BaseSLocID + SLocEntryOffsets.size());
|
2009-04-10 11:52:48 +08:00
|
|
|
}
|
|
|
|
} 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();
|
2009-10-17 06:46:09 +08:00
|
|
|
if (I + 1 != N)
|
|
|
|
NextOffset = SourceMgr.getSLocEntry(I + 1).getOffset();
|
2009-04-16 02:05:10 +08:00
|
|
|
Record.push_back(NextOffset - SLoc->getOffset() - 1);
|
2009-04-17 06:23:12 +08:00
|
|
|
Stream.EmitRecordWithAbbrev(SLocInstantiationAbbrv, Record);
|
2009-04-10 11:52:48 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-04-27 14:38:32 +08:00
|
|
|
Stream.ExitBlock();
|
2009-04-14 00:31:14 +08:00
|
|
|
|
2009-04-27 14:38:32 +08:00
|
|
|
if (SLocEntryOffsets.empty())
|
|
|
|
return;
|
2009-04-26 08:07:37 +08:00
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
// Write the source-location offsets table into the AST block. This
|
2009-04-27 14:38:32 +08:00
|
|
|
// table is used for lazily loading source-location information.
|
|
|
|
using namespace llvm;
|
|
|
|
BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
|
2010-08-19 07:57:32 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(SOURCE_LOCATION_OFFSETS));
|
2009-04-27 14:38:32 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 16)); // # of slocs
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 16)); // next offset
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // offsets
|
|
|
|
unsigned SLocOffsetsAbbrev = Stream.EmitAbbrev(Abbrev);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-04-27 14:38:32 +08:00
|
|
|
Record.clear();
|
2010-08-19 07:57:32 +08:00
|
|
|
Record.push_back(SOURCE_LOCATION_OFFSETS);
|
2009-04-27 14:38:32 +08:00
|
|
|
Record.push_back(SLocEntryOffsets.size());
|
2010-09-23 04:19:08 +08:00
|
|
|
unsigned BaseOffset = Chain ? Chain->getNextSLocOffset() : 0;
|
|
|
|
Record.push_back(SourceMgr.getNextOffset() - BaseOffset);
|
2009-04-27 14:38:32 +08:00
|
|
|
Stream.EmitRecordWithBlob(SLocOffsetsAbbrev, Record,
|
2010-07-31 01:03:48 +08:00
|
|
|
(const char *)data(SLocEntryOffsets),
|
2009-04-28 03:01:47 +08:00
|
|
|
SLocEntryOffsets.size()*sizeof(SLocEntryOffsets[0]));
|
2009-04-27 14:38:32 +08:00
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
// Write the source location entry preloads array, telling the AST
|
2009-04-27 14:38:32 +08:00
|
|
|
// reader which source locations entries it should load eagerly.
|
2010-08-19 07:57:32 +08:00
|
|
|
Stream.EmitRecord(SOURCE_LOCATION_PRELOADS, PreloadSLocs);
|
2009-04-10 11:52:48 +08:00
|
|
|
}
|
|
|
|
|
2009-04-28 02:38:38 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Preprocessor Serialization
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2009-04-11 01:15:23 +08:00
|
|
|
/// \brief Writes the block containing the serialized form of the
|
|
|
|
/// preprocessor.
|
|
|
|
///
|
2010-08-19 07:56:21 +08:00
|
|
|
void ASTWriter::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());
|
2010-08-19 07:57:32 +08:00
|
|
|
Stream.EmitRecord(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.
|
2010-08-19 07:57:32 +08:00
|
|
|
Stream.EnterSubblock(PREPROCESSOR_BLOCK_ID, 2);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
// If the AST file contains __DATE__ or __TIME__ emit a warning about this.
|
2009-04-26 08:07:37 +08:00
|
|
|
// FIXME: use diagnostics subsystem for localization etc.
|
|
|
|
if (PP.SawDateOrTime())
|
|
|
|
fprintf(stderr, "warning: precompiled header used __DATE__ or __TIME__.\n");
|
2009-09-09 23:08:12 +08:00
|
|
|
|
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.
|
Implement serialization and lazy deserialization of the preprocessing
record (which includes all macro instantiations and definitions). As
with all lay deserialization, this introduces a new external source
(here, an external preprocessing record source) that loads all of the
preprocessed entities prior to iterating over the entities.
The preprocessing record is an optional part of the precompiled header
that is disabled by default (enabled with
-detailed-preprocessing-record). When the preprocessor given to the
PCH writer has a preprocessing record, that record is written into the
PCH file. When the PCH reader is given a PCH file that contains a
preprocessing record, it will be lazily loaded (which, effectively,
implicitly adds -detailed-preprocessing-record). This is the first
case where we have sections of the precompiled header that are
added/removed based on a compilation flag, which is
unfortunate. However, this data consumes ~550k in the PCH file for
Cocoa.h (out of ~9.9MB), and there is a non-trivial cost to gathering
this detailed preprocessing information, so it's too expensive to turn
on by default. In the future, we should investigate a better encoding
of this information.
llvm-svn: 99002
2010-03-20 05:51:54 +08:00
|
|
|
PreprocessingRecord *PPRec = PP.getPreprocessingRecord();
|
2009-04-11 02:00:12 +08:00
|
|
|
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;
|
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
// Don't emit builtin macros like __LINE__ to the AST file unless they have
|
2009-04-11 02:00:12 +08:00
|
|
|
// been redefined by the header (in which case they are not isBuiltinMacro).
|
2010-08-19 07:56:27 +08:00
|
|
|
// Also skip macros from a AST file if we're chaining.
|
2010-10-01 09:03:07 +08:00
|
|
|
|
|
|
|
// FIXME: There is a (probably minor) optimization we could do here, if
|
|
|
|
// the macro comes from the original PCH but the identifier comes from a
|
|
|
|
// chained PCH, by storing the offset into the original PCH rather than
|
|
|
|
// writing the macro definition a second time.
|
|
|
|
if (MI->isBuiltinMacro() ||
|
|
|
|
(Chain && I->first->isFromAST() && MI->isFromAST()))
|
2009-04-11 02:00:12 +08:00
|
|
|
continue;
|
|
|
|
|
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());
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-04-11 02:00:12 +08:00
|
|
|
unsigned Code;
|
|
|
|
if (MI->isObjectLike()) {
|
2010-08-19 07:57:32 +08:00
|
|
|
Code = PP_MACRO_OBJECT_LIKE;
|
2009-04-11 02:00:12 +08:00
|
|
|
} else {
|
2010-08-19 07:57:32 +08:00
|
|
|
Code = PP_MACRO_FUNCTION_LIKE;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-04-11 02:00:12 +08:00
|
|
|
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
|
|
|
}
|
Implement serialization and lazy deserialization of the preprocessing
record (which includes all macro instantiations and definitions). As
with all lay deserialization, this introduces a new external source
(here, an external preprocessing record source) that loads all of the
preprocessed entities prior to iterating over the entities.
The preprocessing record is an optional part of the precompiled header
that is disabled by default (enabled with
-detailed-preprocessing-record). When the preprocessor given to the
PCH writer has a preprocessing record, that record is written into the
PCH file. When the PCH reader is given a PCH file that contains a
preprocessing record, it will be lazily loaded (which, effectively,
implicitly adds -detailed-preprocessing-record). This is the first
case where we have sections of the precompiled header that are
added/removed based on a compilation flag, which is
unfortunate. However, this data consumes ~550k in the PCH file for
Cocoa.h (out of ~9.9MB), and there is a non-trivial cost to gathering
this detailed preprocessing information, so it's too expensive to turn
on by default. In the future, we should investigate a better encoding
of this information.
llvm-svn: 99002
2010-03-20 05:51:54 +08:00
|
|
|
|
|
|
|
// If we have a detailed preprocessing record, record the macro definition
|
|
|
|
// ID that corresponds to this macro.
|
|
|
|
if (PPRec)
|
|
|
|
Record.push_back(getMacroDefinitionID(PPRec->findMacroDefinition(MI)));
|
|
|
|
|
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);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-04-11 02:08:30 +08:00
|
|
|
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-09-09 23:08:12 +08:00
|
|
|
|
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-09-09 23:08:12 +08:00
|
|
|
|
2010-08-19 07:57:32 +08:00
|
|
|
Stream.EmitRecord(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
|
|
|
}
|
Implement serialization and lazy deserialization of the preprocessing
record (which includes all macro instantiations and definitions). As
with all lay deserialization, this introduces a new external source
(here, an external preprocessing record source) that loads all of the
preprocessed entities prior to iterating over the entities.
The preprocessing record is an optional part of the precompiled header
that is disabled by default (enabled with
-detailed-preprocessing-record). When the preprocessor given to the
PCH writer has a preprocessing record, that record is written into the
PCH file. When the PCH reader is given a PCH file that contains a
preprocessing record, it will be lazily loaded (which, effectively,
implicitly adds -detailed-preprocessing-record). This is the first
case where we have sections of the precompiled header that are
added/removed based on a compilation flag, which is
unfortunate. However, this data consumes ~550k in the PCH file for
Cocoa.h (out of ~9.9MB), and there is a non-trivial cost to gathering
this detailed preprocessing information, so it's too expensive to turn
on by default. In the future, we should investigate a better encoding
of this information.
llvm-svn: 99002
2010-03-20 05:51:54 +08:00
|
|
|
|
|
|
|
// If the preprocessor has a preprocessing record, emit it.
|
|
|
|
unsigned NumPreprocessingRecords = 0;
|
|
|
|
if (PPRec) {
|
2010-09-28 07:20:01 +08:00
|
|
|
unsigned IndexBase = Chain ? PPRec->getNumPreallocatedEntities() : 0;
|
2010-09-28 06:18:47 +08:00
|
|
|
for (PreprocessingRecord::iterator E = PPRec->begin(Chain),
|
|
|
|
EEnd = PPRec->end(Chain);
|
Implement serialization and lazy deserialization of the preprocessing
record (which includes all macro instantiations and definitions). As
with all lay deserialization, this introduces a new external source
(here, an external preprocessing record source) that loads all of the
preprocessed entities prior to iterating over the entities.
The preprocessing record is an optional part of the precompiled header
that is disabled by default (enabled with
-detailed-preprocessing-record). When the preprocessor given to the
PCH writer has a preprocessing record, that record is written into the
PCH file. When the PCH reader is given a PCH file that contains a
preprocessing record, it will be lazily loaded (which, effectively,
implicitly adds -detailed-preprocessing-record). This is the first
case where we have sections of the precompiled header that are
added/removed based on a compilation flag, which is
unfortunate. However, this data consumes ~550k in the PCH file for
Cocoa.h (out of ~9.9MB), and there is a non-trivial cost to gathering
this detailed preprocessing information, so it's too expensive to turn
on by default. In the future, we should investigate a better encoding
of this information.
llvm-svn: 99002
2010-03-20 05:51:54 +08:00
|
|
|
E != EEnd; ++E) {
|
|
|
|
Record.clear();
|
|
|
|
|
|
|
|
if (MacroInstantiation *MI = dyn_cast<MacroInstantiation>(*E)) {
|
2010-09-28 06:18:47 +08:00
|
|
|
Record.push_back(IndexBase + NumPreprocessingRecords++);
|
Implement serialization and lazy deserialization of the preprocessing
record (which includes all macro instantiations and definitions). As
with all lay deserialization, this introduces a new external source
(here, an external preprocessing record source) that loads all of the
preprocessed entities prior to iterating over the entities.
The preprocessing record is an optional part of the precompiled header
that is disabled by default (enabled with
-detailed-preprocessing-record). When the preprocessor given to the
PCH writer has a preprocessing record, that record is written into the
PCH file. When the PCH reader is given a PCH file that contains a
preprocessing record, it will be lazily loaded (which, effectively,
implicitly adds -detailed-preprocessing-record). This is the first
case where we have sections of the precompiled header that are
added/removed based on a compilation flag, which is
unfortunate. However, this data consumes ~550k in the PCH file for
Cocoa.h (out of ~9.9MB), and there is a non-trivial cost to gathering
this detailed preprocessing information, so it's too expensive to turn
on by default. In the future, we should investigate a better encoding
of this information.
llvm-svn: 99002
2010-03-20 05:51:54 +08:00
|
|
|
AddSourceLocation(MI->getSourceRange().getBegin(), Record);
|
|
|
|
AddSourceLocation(MI->getSourceRange().getEnd(), Record);
|
|
|
|
AddIdentifierRef(MI->getName(), Record);
|
|
|
|
Record.push_back(getMacroDefinitionID(MI->getDefinition()));
|
2010-08-19 07:57:32 +08:00
|
|
|
Stream.EmitRecord(PP_MACRO_INSTANTIATION, Record);
|
Implement serialization and lazy deserialization of the preprocessing
record (which includes all macro instantiations and definitions). As
with all lay deserialization, this introduces a new external source
(here, an external preprocessing record source) that loads all of the
preprocessed entities prior to iterating over the entities.
The preprocessing record is an optional part of the precompiled header
that is disabled by default (enabled with
-detailed-preprocessing-record). When the preprocessor given to the
PCH writer has a preprocessing record, that record is written into the
PCH file. When the PCH reader is given a PCH file that contains a
preprocessing record, it will be lazily loaded (which, effectively,
implicitly adds -detailed-preprocessing-record). This is the first
case where we have sections of the precompiled header that are
added/removed based on a compilation flag, which is
unfortunate. However, this data consumes ~550k in the PCH file for
Cocoa.h (out of ~9.9MB), and there is a non-trivial cost to gathering
this detailed preprocessing information, so it's too expensive to turn
on by default. In the future, we should investigate a better encoding
of this information.
llvm-svn: 99002
2010-03-20 05:51:54 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (MacroDefinition *MD = dyn_cast<MacroDefinition>(*E)) {
|
|
|
|
// Record this macro definition's location.
|
2010-09-16 03:54:06 +08:00
|
|
|
MacroID ID = getMacroDefinitionID(MD);
|
2010-10-03 03:29:26 +08:00
|
|
|
|
|
|
|
// Don't write the macro definition if it is from another AST file.
|
|
|
|
if (ID < FirstMacroID)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
unsigned Position = ID - FirstMacroID;
|
|
|
|
if (Position != MacroDefinitionOffsets.size()) {
|
|
|
|
if (Position > MacroDefinitionOffsets.size())
|
|
|
|
MacroDefinitionOffsets.resize(Position + 1);
|
Implement serialization and lazy deserialization of the preprocessing
record (which includes all macro instantiations and definitions). As
with all lay deserialization, this introduces a new external source
(here, an external preprocessing record source) that loads all of the
preprocessed entities prior to iterating over the entities.
The preprocessing record is an optional part of the precompiled header
that is disabled by default (enabled with
-detailed-preprocessing-record). When the preprocessor given to the
PCH writer has a preprocessing record, that record is written into the
PCH file. When the PCH reader is given a PCH file that contains a
preprocessing record, it will be lazily loaded (which, effectively,
implicitly adds -detailed-preprocessing-record). This is the first
case where we have sections of the precompiled header that are
added/removed based on a compilation flag, which is
unfortunate. However, this data consumes ~550k in the PCH file for
Cocoa.h (out of ~9.9MB), and there is a non-trivial cost to gathering
this detailed preprocessing information, so it's too expensive to turn
on by default. In the future, we should investigate a better encoding
of this information.
llvm-svn: 99002
2010-03-20 05:51:54 +08:00
|
|
|
|
2010-10-03 03:29:26 +08:00
|
|
|
MacroDefinitionOffsets[Position] = Stream.GetCurrentBitNo();
|
Implement serialization and lazy deserialization of the preprocessing
record (which includes all macro instantiations and definitions). As
with all lay deserialization, this introduces a new external source
(here, an external preprocessing record source) that loads all of the
preprocessed entities prior to iterating over the entities.
The preprocessing record is an optional part of the precompiled header
that is disabled by default (enabled with
-detailed-preprocessing-record). When the preprocessor given to the
PCH writer has a preprocessing record, that record is written into the
PCH file. When the PCH reader is given a PCH file that contains a
preprocessing record, it will be lazily loaded (which, effectively,
implicitly adds -detailed-preprocessing-record). This is the first
case where we have sections of the precompiled header that are
added/removed based on a compilation flag, which is
unfortunate. However, this data consumes ~550k in the PCH file for
Cocoa.h (out of ~9.9MB), and there is a non-trivial cost to gathering
this detailed preprocessing information, so it's too expensive to turn
on by default. In the future, we should investigate a better encoding
of this information.
llvm-svn: 99002
2010-03-20 05:51:54 +08:00
|
|
|
} else
|
|
|
|
MacroDefinitionOffsets.push_back(Stream.GetCurrentBitNo());
|
|
|
|
|
2010-09-28 06:18:47 +08:00
|
|
|
Record.push_back(IndexBase + NumPreprocessingRecords++);
|
Implement serialization and lazy deserialization of the preprocessing
record (which includes all macro instantiations and definitions). As
with all lay deserialization, this introduces a new external source
(here, an external preprocessing record source) that loads all of the
preprocessed entities prior to iterating over the entities.
The preprocessing record is an optional part of the precompiled header
that is disabled by default (enabled with
-detailed-preprocessing-record). When the preprocessor given to the
PCH writer has a preprocessing record, that record is written into the
PCH file. When the PCH reader is given a PCH file that contains a
preprocessing record, it will be lazily loaded (which, effectively,
implicitly adds -detailed-preprocessing-record). This is the first
case where we have sections of the precompiled header that are
added/removed based on a compilation flag, which is
unfortunate. However, this data consumes ~550k in the PCH file for
Cocoa.h (out of ~9.9MB), and there is a non-trivial cost to gathering
this detailed preprocessing information, so it's too expensive to turn
on by default. In the future, we should investigate a better encoding
of this information.
llvm-svn: 99002
2010-03-20 05:51:54 +08:00
|
|
|
Record.push_back(ID);
|
|
|
|
AddSourceLocation(MD->getSourceRange().getBegin(), Record);
|
|
|
|
AddSourceLocation(MD->getSourceRange().getEnd(), Record);
|
|
|
|
AddIdentifierRef(MD->getName(), Record);
|
|
|
|
AddSourceLocation(MD->getLocation(), Record);
|
2010-08-19 07:57:32 +08:00
|
|
|
Stream.EmitRecord(PP_MACRO_DEFINITION, Record);
|
Implement serialization and lazy deserialization of the preprocessing
record (which includes all macro instantiations and definitions). As
with all lay deserialization, this introduces a new external source
(here, an external preprocessing record source) that loads all of the
preprocessed entities prior to iterating over the entities.
The preprocessing record is an optional part of the precompiled header
that is disabled by default (enabled with
-detailed-preprocessing-record). When the preprocessor given to the
PCH writer has a preprocessing record, that record is written into the
PCH file. When the PCH reader is given a PCH file that contains a
preprocessing record, it will be lazily loaded (which, effectively,
implicitly adds -detailed-preprocessing-record). This is the first
case where we have sections of the precompiled header that are
added/removed based on a compilation flag, which is
unfortunate. However, this data consumes ~550k in the PCH file for
Cocoa.h (out of ~9.9MB), and there is a non-trivial cost to gathering
this detailed preprocessing information, so it's too expensive to turn
on by default. In the future, we should investigate a better encoding
of this information.
llvm-svn: 99002
2010-03-20 05:51:54 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-04-17 06:23:12 +08:00
|
|
|
Stream.ExitBlock();
|
Implement serialization and lazy deserialization of the preprocessing
record (which includes all macro instantiations and definitions). As
with all lay deserialization, this introduces a new external source
(here, an external preprocessing record source) that loads all of the
preprocessed entities prior to iterating over the entities.
The preprocessing record is an optional part of the precompiled header
that is disabled by default (enabled with
-detailed-preprocessing-record). When the preprocessor given to the
PCH writer has a preprocessing record, that record is written into the
PCH file. When the PCH reader is given a PCH file that contains a
preprocessing record, it will be lazily loaded (which, effectively,
implicitly adds -detailed-preprocessing-record). This is the first
case where we have sections of the precompiled header that are
added/removed based on a compilation flag, which is
unfortunate. However, this data consumes ~550k in the PCH file for
Cocoa.h (out of ~9.9MB), and there is a non-trivial cost to gathering
this detailed preprocessing information, so it's too expensive to turn
on by default. In the future, we should investigate a better encoding
of this information.
llvm-svn: 99002
2010-03-20 05:51:54 +08:00
|
|
|
|
|
|
|
// Write the offsets table for the preprocessing record.
|
|
|
|
if (NumPreprocessingRecords > 0) {
|
|
|
|
// Write the offsets table for identifier IDs.
|
|
|
|
using namespace llvm;
|
|
|
|
BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
|
2010-08-19 07:57:32 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(MACRO_DEFINITION_OFFSETS));
|
Implement serialization and lazy deserialization of the preprocessing
record (which includes all macro instantiations and definitions). As
with all lay deserialization, this introduces a new external source
(here, an external preprocessing record source) that loads all of the
preprocessed entities prior to iterating over the entities.
The preprocessing record is an optional part of the precompiled header
that is disabled by default (enabled with
-detailed-preprocessing-record). When the preprocessor given to the
PCH writer has a preprocessing record, that record is written into the
PCH file. When the PCH reader is given a PCH file that contains a
preprocessing record, it will be lazily loaded (which, effectively,
implicitly adds -detailed-preprocessing-record). This is the first
case where we have sections of the precompiled header that are
added/removed based on a compilation flag, which is
unfortunate. However, this data consumes ~550k in the PCH file for
Cocoa.h (out of ~9.9MB), and there is a non-trivial cost to gathering
this detailed preprocessing information, so it's too expensive to turn
on by default. In the future, we should investigate a better encoding
of this information.
llvm-svn: 99002
2010-03-20 05:51:54 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of records
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of macro defs
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
|
|
|
|
unsigned MacroDefOffsetAbbrev = Stream.EmitAbbrev(Abbrev);
|
|
|
|
|
|
|
|
Record.clear();
|
2010-08-19 07:57:32 +08:00
|
|
|
Record.push_back(MACRO_DEFINITION_OFFSETS);
|
Implement serialization and lazy deserialization of the preprocessing
record (which includes all macro instantiations and definitions). As
with all lay deserialization, this introduces a new external source
(here, an external preprocessing record source) that loads all of the
preprocessed entities prior to iterating over the entities.
The preprocessing record is an optional part of the precompiled header
that is disabled by default (enabled with
-detailed-preprocessing-record). When the preprocessor given to the
PCH writer has a preprocessing record, that record is written into the
PCH file. When the PCH reader is given a PCH file that contains a
preprocessing record, it will be lazily loaded (which, effectively,
implicitly adds -detailed-preprocessing-record). This is the first
case where we have sections of the precompiled header that are
added/removed based on a compilation flag, which is
unfortunate. However, this data consumes ~550k in the PCH file for
Cocoa.h (out of ~9.9MB), and there is a non-trivial cost to gathering
this detailed preprocessing information, so it's too expensive to turn
on by default. In the future, we should investigate a better encoding
of this information.
llvm-svn: 99002
2010-03-20 05:51:54 +08:00
|
|
|
Record.push_back(NumPreprocessingRecords);
|
|
|
|
Record.push_back(MacroDefinitionOffsets.size());
|
|
|
|
Stream.EmitRecordWithBlob(MacroDefOffsetAbbrev, Record,
|
2010-07-31 01:03:48 +08:00
|
|
|
(const char *)data(MacroDefinitionOffsets),
|
Implement serialization and lazy deserialization of the preprocessing
record (which includes all macro instantiations and definitions). As
with all lay deserialization, this introduces a new external source
(here, an external preprocessing record source) that loads all of the
preprocessed entities prior to iterating over the entities.
The preprocessing record is an optional part of the precompiled header
that is disabled by default (enabled with
-detailed-preprocessing-record). When the preprocessor given to the
PCH writer has a preprocessing record, that record is written into the
PCH file. When the PCH reader is given a PCH file that contains a
preprocessing record, it will be lazily loaded (which, effectively,
implicitly adds -detailed-preprocessing-record). This is the first
case where we have sections of the precompiled header that are
added/removed based on a compilation flag, which is
unfortunate. However, this data consumes ~550k in the PCH file for
Cocoa.h (out of ~9.9MB), and there is a non-trivial cost to gathering
this detailed preprocessing information, so it's too expensive to turn
on by default. In the future, we should investigate a better encoding
of this information.
llvm-svn: 99002
2010-03-20 05:51:54 +08:00
|
|
|
MacroDefinitionOffsets.size() * sizeof(uint32_t));
|
|
|
|
}
|
2009-04-11 01:15:23 +08:00
|
|
|
}
|
|
|
|
|
2009-04-28 02:38:38 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Type Serialization
|
|
|
|
//===----------------------------------------------------------------------===//
|
2009-04-11 01:15:23 +08:00
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
/// \brief Write the representation of a type to the AST stream.
|
2010-08-19 07:56:21 +08:00
|
|
|
void ASTWriter::WriteType(QualType T) {
|
2010-08-21 00:04:04 +08:00
|
|
|
TypeIdx &Idx = TypeIdxs[T];
|
2010-08-21 00:03:59 +08:00
|
|
|
if (Idx.getIndex() == 0) // we haven't seen this type before.
|
|
|
|
Idx = TypeIdx(NextTypeID++);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-10-06 02:37:06 +08:00
|
|
|
assert(Idx.getIndex() >= FirstTypeID && "Re-writing a type from a prior AST");
|
2010-10-05 02:21:45 +08:00
|
|
|
|
2009-04-10 06:27:44 +08:00
|
|
|
// Record the offset for this type.
|
2010-08-21 00:03:59 +08:00
|
|
|
unsigned Index = Idx.getIndex() - FirstTypeID;
|
2010-07-27 08:17:23 +08:00
|
|
|
if (TypeOffsets.size() == Index)
|
2009-04-17 06:23:12 +08:00
|
|
|
TypeOffsets.push_back(Stream.GetCurrentBitNo());
|
2010-07-27 08:17:23 +08:00
|
|
|
else if (TypeOffsets.size() < Index) {
|
|
|
|
TypeOffsets.resize(Index + 1);
|
|
|
|
TypeOffsets[Index] = Stream.GetCurrentBitNo();
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
RecordData Record;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-04-10 06:27:44 +08:00
|
|
|
// Emit the type's representation.
|
2010-08-19 07:56:27 +08:00
|
|
|
ASTTypeWriter W(*this, Record);
|
2009-09-25 03:53:00 +08:00
|
|
|
|
First part of changes to eliminate problems with cv-qualifiers and
sugared types. The basic problem is that our qualifier accessors
(getQualifiers, getCVRQualifiers, isConstQualified, etc.) only look at
the current QualType and not at any qualifiers that come from sugared
types, meaning that we won't see these qualifiers through, e.g.,
typedefs:
typedef const int CInt;
typedef CInt Self;
Self.isConstQualified() currently returns false!
Various bugs (e.g., PR5383) have cropped up all over the front end due
to such problems. I'm addressing this problem by splitting each
qualifier accessor into two versions:
- the "local" version only returns qualifiers on this particular
QualType instance
- the "normal" version that will eventually combine qualifiers from this
QualType instance with the qualifiers on the canonical type to
produce the full set of qualifiers.
This commit adds the local versions and switches a few callers from
the "normal" version (e.g., isConstQualified) over to the "local"
version (e.g., isLocalConstQualified) when that is the right thing to
do, e.g., because we're printing or serializing the qualifiers. Also,
switch a bunch of
Context.getCanonicalType(T1).getUnqualifiedType() == Context.getCanonicalType(T2).getQualifiedType()
expressions over to
Context.hasSameUnqualifiedType(T1, T2)
llvm-svn: 88969
2009-11-17 05:35:15 +08:00
|
|
|
if (T.hasLocalNonFastQualifiers()) {
|
|
|
|
Qualifiers Qs = T.getLocalQualifiers();
|
|
|
|
AddTypeRef(T.getLocalUnqualifiedType(), Record);
|
2009-09-25 03:53:00 +08:00
|
|
|
Record.push_back(Qs.getAsOpaqueValue());
|
2010-08-19 07:57:32 +08:00
|
|
|
W.Code = TYPE_EXT_QUAL;
|
2009-09-25 03:53:00 +08:00
|
|
|
} else {
|
|
|
|
switch (T->getTypeClass()) {
|
|
|
|
// For all of the concrete, non-dependent types, call the
|
|
|
|
// appropriate visitor function.
|
2009-04-10 06:27:44 +08:00
|
|
|
#define TYPE(Class, Base) \
|
2010-01-20 10:03:14 +08:00
|
|
|
case Type::Class: W.Visit##Class##Type(cast<Class##Type>(T)); break;
|
2009-04-10 06:27:44 +08:00
|
|
|
#define ABSTRACT_TYPE(Class, Base)
|
|
|
|
#include "clang/AST/TypeNodes.def"
|
2009-09-25 03:53:00 +08:00
|
|
|
}
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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
|
|
|
}
|
|
|
|
|
2009-04-28 02:38:38 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Declaration Serialization
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
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.
|
2010-08-19 07:56:21 +08:00
|
|
|
uint64_t ASTWriter::WriteDeclContextLexicalBlock(ASTContext &Context,
|
2009-04-10 06:27:44 +08:00
|
|
|
DeclContext *DC) {
|
2009-06-30 10:36:12 +08:00
|
|
|
if (DC->decls_empty())
|
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;
|
2010-08-19 07:57:32 +08:00
|
|
|
Record.push_back(DECL_CONTEXT_LEXICAL);
|
2010-10-15 04:14:34 +08:00
|
|
|
llvm::SmallVector<KindDeclIDPair, 64> Decls;
|
2009-06-30 10:36:12 +08:00
|
|
|
for (DeclContext::decl_iterator D = DC->decls_begin(), DEnd = DC->decls_end();
|
|
|
|
D != DEnd; ++D)
|
2010-10-15 04:14:34 +08:00
|
|
|
Decls.push_back(std::make_pair((*D)->getKind(), GetDeclRef(*D)));
|
2009-04-10 06:27:44 +08:00
|
|
|
|
2009-04-23 06:34:57 +08:00
|
|
|
++NumLexicalDeclContexts;
|
2010-07-27 08:17:23 +08:00
|
|
|
Stream.EmitRecordWithBlob(DeclContextLexicalAbbrev, Record,
|
2010-10-15 04:14:34 +08:00
|
|
|
reinterpret_cast<char*>(Decls.data()),
|
|
|
|
Decls.size() * sizeof(KindDeclIDPair));
|
2009-04-10 06:27:44 +08:00
|
|
|
return Offset;
|
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:21 +08:00
|
|
|
void ASTWriter::WriteTypeDeclOffsets() {
|
2010-07-17 00:36:56 +08:00
|
|
|
using namespace llvm;
|
|
|
|
RecordData Record;
|
|
|
|
|
|
|
|
// Write the type offsets array
|
|
|
|
BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
|
2010-08-19 07:57:32 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(TYPE_OFFSET));
|
2010-07-17 00:36:56 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of types
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // types block
|
|
|
|
unsigned TypeOffsetAbbrev = Stream.EmitAbbrev(Abbrev);
|
|
|
|
Record.clear();
|
2010-08-19 07:57:32 +08:00
|
|
|
Record.push_back(TYPE_OFFSET);
|
2010-07-17 00:36:56 +08:00
|
|
|
Record.push_back(TypeOffsets.size());
|
|
|
|
Stream.EmitRecordWithBlob(TypeOffsetAbbrev, Record,
|
2010-07-31 01:03:48 +08:00
|
|
|
(const char *)data(TypeOffsets),
|
2010-07-17 00:36:56 +08:00
|
|
|
TypeOffsets.size() * sizeof(TypeOffsets[0]));
|
|
|
|
|
|
|
|
// Write the declaration offsets array
|
|
|
|
Abbrev = new BitCodeAbbrev();
|
2010-08-19 07:57:32 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(DECL_OFFSET));
|
2010-07-17 00:36:56 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of declarations
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // declarations block
|
|
|
|
unsigned DeclOffsetAbbrev = Stream.EmitAbbrev(Abbrev);
|
|
|
|
Record.clear();
|
2010-08-19 07:57:32 +08:00
|
|
|
Record.push_back(DECL_OFFSET);
|
2010-07-17 00:36:56 +08:00
|
|
|
Record.push_back(DeclOffsets.size());
|
|
|
|
Stream.EmitRecordWithBlob(DeclOffsetAbbrev, Record,
|
2010-07-31 01:03:48 +08:00
|
|
|
(const char *)data(DeclOffsets),
|
2010-07-17 00:36:56 +08:00
|
|
|
DeclOffsets.size() * sizeof(DeclOffsets[0]));
|
|
|
|
}
|
|
|
|
|
2009-04-28 02:38:38 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Global Method Pool and Selector Serialization
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2009-04-25 05:10:55 +08:00
|
|
|
namespace {
|
|
|
|
// Trait used for the on-disk hash table used in the method pool.
|
2010-08-19 07:56:27 +08:00
|
|
|
class ASTMethodPoolTrait {
|
2010-08-19 07:56:21 +08:00
|
|
|
ASTWriter &Writer;
|
2009-04-25 05:10:55 +08:00
|
|
|
|
|
|
|
public:
|
|
|
|
typedef Selector key_type;
|
|
|
|
typedef key_type key_type_ref;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-08-05 01:20:04 +08:00
|
|
|
struct data_type {
|
2010-08-19 07:57:32 +08:00
|
|
|
SelectorID ID;
|
2010-08-05 01:20:04 +08:00
|
|
|
ObjCMethodList Instance, Factory;
|
|
|
|
};
|
2009-04-25 05:10:55 +08:00
|
|
|
typedef const data_type& data_type_ref;
|
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
explicit ASTMethodPoolTrait(ASTWriter &Writer) : Writer(Writer) { }
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-04-25 05:10:55 +08:00
|
|
|
static unsigned ComputeHash(Selector Sel) {
|
2010-08-21 00:03:52 +08:00
|
|
|
return serialization::ComputeHash(Sel);
|
2009-04-25 05:10:55 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
|
|
|
std::pair<unsigned,unsigned>
|
2009-04-25 05:10:55 +08:00
|
|
|
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);
|
2010-08-05 01:20:04 +08:00
|
|
|
unsigned DataLen = 4 + 2 + 2; // 2 bytes for each of the method counts
|
|
|
|
for (const ObjCMethodList *Method = &Methods.Instance; Method;
|
2009-04-25 05:10:55 +08:00
|
|
|
Method = Method->Next)
|
|
|
|
if (Method->Method)
|
|
|
|
DataLen += 4;
|
2010-08-05 01:20:04 +08:00
|
|
|
for (const ObjCMethodList *Method = &Methods.Factory; Method;
|
2009-04-25 05:10:55 +08:00
|
|
|
Method = Method->Next)
|
|
|
|
if (Method->Method)
|
|
|
|
DataLen += 4;
|
|
|
|
clang::io::Emit16(Out, DataLen);
|
|
|
|
return std::make_pair(KeyLen, DataLen);
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-04-26 01:48:32 +08:00
|
|
|
void EmitKey(llvm::raw_ostream& Out, Selector Sel, unsigned) {
|
2009-09-09 23:08:12 +08:00
|
|
|
uint64_t Start = Out.tell();
|
2009-04-26 01:48:32 +08:00
|
|
|
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)
|
2009-09-09 23:08:12 +08:00
|
|
|
clang::io::Emit32(Out,
|
2009-04-25 05:10:55 +08:00
|
|
|
Writer.getIdentifierRef(Sel.getIdentifierInfoForSlot(I)));
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-04-25 05:10:55 +08:00
|
|
|
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;
|
2010-08-05 01:20:04 +08:00
|
|
|
clang::io::Emit32(Out, Methods.ID);
|
2009-04-25 05:10:55 +08:00
|
|
|
unsigned NumInstanceMethods = 0;
|
2010-08-05 01:20:04 +08:00
|
|
|
for (const ObjCMethodList *Method = &Methods.Instance; Method;
|
2009-04-25 05:10:55 +08:00
|
|
|
Method = Method->Next)
|
|
|
|
if (Method->Method)
|
|
|
|
++NumInstanceMethods;
|
|
|
|
|
|
|
|
unsigned NumFactoryMethods = 0;
|
2010-08-05 01:20:04 +08:00
|
|
|
for (const ObjCMethodList *Method = &Methods.Factory; Method;
|
2009-04-25 05:10:55 +08:00
|
|
|
Method = Method->Next)
|
|
|
|
if (Method->Method)
|
|
|
|
++NumFactoryMethods;
|
|
|
|
|
|
|
|
clang::io::Emit16(Out, NumInstanceMethods);
|
|
|
|
clang::io::Emit16(Out, NumFactoryMethods);
|
2010-08-05 01:20:04 +08:00
|
|
|
for (const ObjCMethodList *Method = &Methods.Instance; Method;
|
2009-04-25 05:10:55 +08:00
|
|
|
Method = Method->Next)
|
|
|
|
if (Method->Method)
|
|
|
|
clang::io::Emit32(Out, Writer.getDeclID(Method->Method));
|
2010-08-05 01:20:04 +08:00
|
|
|
for (const ObjCMethodList *Method = &Methods.Factory; Method;
|
2009-04-25 05:10:55 +08:00
|
|
|
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
|
|
|
|
|
2010-08-04 05:58:15 +08:00
|
|
|
/// \brief Write ObjC data: selectors and the method pool.
|
2009-04-25 05:10:55 +08:00
|
|
|
///
|
|
|
|
/// The method pool contains both instance and factory methods, stored
|
2010-08-04 05:58:15 +08:00
|
|
|
/// in an on-disk hash table indexed by the selector. The hash table also
|
|
|
|
/// contains an empty entry for every other selector known to Sema.
|
2010-08-19 07:56:21 +08:00
|
|
|
void ASTWriter::WriteSelectors(Sema &SemaRef) {
|
2009-04-25 05:10:55 +08:00
|
|
|
using namespace llvm;
|
|
|
|
|
2010-08-04 05:58:15 +08:00
|
|
|
// Do we have to do anything at all?
|
2010-08-05 01:20:04 +08:00
|
|
|
if (SemaRef.MethodPool.empty() && SelectorIDs.empty())
|
2010-08-04 05:58:15 +08:00
|
|
|
return;
|
2010-08-05 02:21:41 +08:00
|
|
|
unsigned NumTableEntries = 0;
|
2010-08-04 05:58:15 +08:00
|
|
|
// Create and write out the blob that contains selectors and the method pool.
|
2009-04-25 05:10:55 +08:00
|
|
|
{
|
2010-08-19 07:56:27 +08:00
|
|
|
OnDiskChainedHashTableGenerator<ASTMethodPoolTrait> Generator;
|
2010-08-21 00:04:27 +08:00
|
|
|
ASTMethodPoolTrait Trait(*this);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-08-04 05:58:15 +08:00
|
|
|
// Create the on-disk hash table representation. We walk through every
|
|
|
|
// selector we've seen and look it up in the method pool.
|
2010-08-05 02:21:41 +08:00
|
|
|
SelectorOffsets.resize(NextSelectorID - FirstSelectorID);
|
2010-08-19 07:57:32 +08:00
|
|
|
for (llvm::DenseMap<Selector, SelectorID>::iterator
|
2010-08-05 01:20:04 +08:00
|
|
|
I = SelectorIDs.begin(), E = SelectorIDs.end();
|
|
|
|
I != E; ++I) {
|
|
|
|
Selector S = I->first;
|
2010-08-04 05:58:15 +08:00
|
|
|
Sema::GlobalMethodPool::iterator F = SemaRef.MethodPool.find(S);
|
2010-08-19 07:56:27 +08:00
|
|
|
ASTMethodPoolTrait::data_type Data = {
|
2010-08-05 01:20:04 +08:00
|
|
|
I->second,
|
|
|
|
ObjCMethodList(),
|
|
|
|
ObjCMethodList()
|
|
|
|
};
|
|
|
|
if (F != SemaRef.MethodPool.end()) {
|
|
|
|
Data.Instance = F->second.first;
|
|
|
|
Data.Factory = F->second.second;
|
|
|
|
}
|
2010-08-19 07:56:27 +08:00
|
|
|
// Only write this selector if it's not in an existing AST or something
|
2010-08-05 02:21:41 +08:00
|
|
|
// changed.
|
|
|
|
if (Chain && I->second < FirstSelectorID) {
|
|
|
|
// Selector already exists. Did it change?
|
|
|
|
bool changed = false;
|
|
|
|
for (ObjCMethodList *M = &Data.Instance; !changed && M && M->Method;
|
|
|
|
M = M->Next) {
|
|
|
|
if (M->Method->getPCHLevel() == 0)
|
|
|
|
changed = true;
|
|
|
|
}
|
|
|
|
for (ObjCMethodList *M = &Data.Factory; !changed && M && M->Method;
|
|
|
|
M = M->Next) {
|
|
|
|
if (M->Method->getPCHLevel() == 0)
|
|
|
|
changed = true;
|
|
|
|
}
|
|
|
|
if (!changed)
|
|
|
|
continue;
|
2010-08-05 05:22:45 +08:00
|
|
|
} else if (Data.Instance.Method || Data.Factory.Method) {
|
|
|
|
// A new method pool entry.
|
|
|
|
++NumTableEntries;
|
2010-08-05 02:21:41 +08:00
|
|
|
}
|
2010-08-21 00:04:27 +08:00
|
|
|
Generator.insert(S, Data, Trait);
|
2009-04-25 05:10:55 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Create the on-disk hash table in a buffer.
|
2009-09-09 23:08:12 +08:00
|
|
|
llvm::SmallString<4096> MethodPool;
|
2009-04-25 05:10:55 +08:00
|
|
|
uint32_t BucketOffset;
|
|
|
|
{
|
2010-08-19 07:56:27 +08:00
|
|
|
ASTMethodPoolTrait Trait(*this);
|
2009-04-25 05:10:55 +08:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create a blob abbreviation
|
|
|
|
BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
|
2010-08-19 07:57:32 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(METHOD_POOL));
|
2009-04-25 05:10:55 +08:00
|
|
|
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;
|
2010-08-19 07:57:32 +08:00
|
|
|
Record.push_back(METHOD_POOL);
|
2009-04-25 05:10:55 +08:00
|
|
|
Record.push_back(BucketOffset);
|
2010-08-05 02:21:41 +08:00
|
|
|
Record.push_back(NumTableEntries);
|
2009-08-24 17:31:37 +08:00
|
|
|
Stream.EmitRecordWithBlob(MethodPoolAbbrev, Record, MethodPool.str());
|
2009-04-26 01:48:32 +08:00
|
|
|
|
|
|
|
// Create a blob abbreviation for the selector table offsets.
|
|
|
|
Abbrev = new BitCodeAbbrev();
|
2010-08-19 07:57:32 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(SELECTOR_OFFSETS));
|
2009-04-26 01:48:32 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // index
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
|
|
|
|
unsigned SelectorOffsetAbbrev = Stream.EmitAbbrev(Abbrev);
|
|
|
|
|
|
|
|
// Write the selector offsets table.
|
|
|
|
Record.clear();
|
2010-08-19 07:57:32 +08:00
|
|
|
Record.push_back(SELECTOR_OFFSETS);
|
2009-04-26 01:48:32 +08:00
|
|
|
Record.push_back(SelectorOffsets.size());
|
|
|
|
Stream.EmitRecordWithBlob(SelectorOffsetAbbrev, Record,
|
2010-07-31 01:03:48 +08:00
|
|
|
(const char *)data(SelectorOffsets),
|
2009-04-26 01:48:32 +08:00
|
|
|
SelectorOffsets.size() * 4);
|
2009-04-25 05:10:55 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
/// \brief Write the selectors referenced in @selector expression into AST file.
|
2010-08-19 07:56:21 +08:00
|
|
|
void ASTWriter::WriteReferencedSelectorsPool(Sema &SemaRef) {
|
2010-07-24 03:11:11 +08:00
|
|
|
using namespace llvm;
|
|
|
|
if (SemaRef.ReferencedSelectors.empty())
|
|
|
|
return;
|
2010-08-05 04:40:17 +08:00
|
|
|
|
2010-07-24 03:11:11 +08:00
|
|
|
RecordData Record;
|
2010-08-05 04:40:17 +08:00
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
// Note: this writes out all references even for a dependent AST. But it is
|
2010-08-05 06:21:29 +08:00
|
|
|
// very tricky to fix, and given that @selector shouldn't really appear in
|
|
|
|
// headers, probably not worth it. It's not a correctness issue.
|
2010-07-24 03:11:11 +08:00
|
|
|
for (DenseMap<Selector, SourceLocation>::iterator S =
|
|
|
|
SemaRef.ReferencedSelectors.begin(),
|
|
|
|
E = SemaRef.ReferencedSelectors.end(); S != E; ++S) {
|
|
|
|
Selector Sel = (*S).first;
|
|
|
|
SourceLocation Loc = (*S).second;
|
|
|
|
AddSelectorRef(Sel, Record);
|
|
|
|
AddSourceLocation(Loc, Record);
|
|
|
|
}
|
2010-08-19 07:57:32 +08:00
|
|
|
Stream.EmitRecord(REFERENCED_SELECTOR_POOL, Record);
|
2010-07-24 03:11:11 +08:00
|
|
|
}
|
|
|
|
|
2009-04-28 02:38:38 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Identifier Table Serialization
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2009-04-21 04:36:09 +08:00
|
|
|
namespace {
|
2010-08-19 07:56:27 +08:00
|
|
|
class ASTIdentifierTableTrait {
|
2010-08-19 07:56:21 +08:00
|
|
|
ASTWriter &Writer;
|
2009-04-22 07:56:24 +08:00
|
|
|
Preprocessor &PP;
|
2009-04-21 04:36:09 +08:00
|
|
|
|
2009-04-29 05:18:29 +08:00
|
|
|
/// \brief Determines whether this is an "interesting" identifier
|
|
|
|
/// that needs a full IdentifierInfo structure written into the hash
|
|
|
|
/// table.
|
|
|
|
static bool isInterestingIdentifier(const IdentifierInfo *II) {
|
|
|
|
return II->isPoisoned() ||
|
|
|
|
II->isExtensionToken() ||
|
|
|
|
II->hasMacroDefinition() ||
|
|
|
|
II->getObjCOrBuiltinID() ||
|
|
|
|
II->getFETokenInfo<void>();
|
|
|
|
}
|
|
|
|
|
2009-04-21 04:36:09 +08:00
|
|
|
public:
|
|
|
|
typedef const IdentifierInfo* key_type;
|
|
|
|
typedef key_type key_type_ref;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-08-19 07:57:32 +08:00
|
|
|
typedef IdentID data_type;
|
2009-04-21 04:36:09 +08:00
|
|
|
typedef data_type data_type_ref;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
ASTIdentifierTableTrait(ASTWriter &Writer, Preprocessor &PP)
|
2009-04-22 07:56:24 +08:00
|
|
|
: Writer(Writer), PP(PP) { }
|
2009-04-21 04:36:09 +08:00
|
|
|
|
|
|
|
static unsigned ComputeHash(const IdentifierInfo* II) {
|
2009-10-18 07:52:28 +08:00
|
|
|
return llvm::HashString(II->getName());
|
2009-04-21 04:36:09 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
|
|
|
std::pair<unsigned,unsigned>
|
|
|
|
EmitKeyDataLength(llvm::raw_ostream& Out, const IdentifierInfo* II,
|
2010-08-19 07:57:32 +08:00
|
|
|
IdentID ID) {
|
2009-10-19 04:26:12 +08:00
|
|
|
unsigned KeyLen = II->getLength() + 1;
|
2009-04-29 05:18:29 +08:00
|
|
|
unsigned DataLen = 4; // 4 bytes for the persistent ID << 1
|
|
|
|
if (isInterestingIdentifier(II)) {
|
2009-04-29 05:32:13 +08:00
|
|
|
DataLen += 2; // 2 bytes for builtin ID, flags
|
2009-09-09 23:08:12 +08:00
|
|
|
if (II->hasMacroDefinition() &&
|
2009-04-29 05:18:29 +08:00
|
|
|
!PP.getMacroInfo(const_cast<IdentifierInfo *>(II))->isBuiltinMacro())
|
2009-04-29 05:32:13 +08:00
|
|
|
DataLen += 4;
|
2009-04-29 05:18:29 +08:00
|
|
|
for (IdentifierResolver::iterator D = IdentifierResolver::begin(II),
|
|
|
|
DEnd = IdentifierResolver::end();
|
|
|
|
D != DEnd; ++D)
|
2010-08-19 07:57:32 +08:00
|
|
|
DataLen += sizeof(DeclID);
|
2009-04-29 05:18:29 +08:00
|
|
|
}
|
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-29 04:01:51 +08:00
|
|
|
// We emit the key length after the data length so that every
|
|
|
|
// string is preceded by a 16-bit length. This matches the PTH
|
|
|
|
// format for storing identifiers.
|
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);
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
|
|
|
void EmitKey(llvm::raw_ostream& Out, const IdentifierInfo* II,
|
2009-04-21 04:36:09 +08:00
|
|
|
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());
|
2009-10-19 04:26:12 +08:00
|
|
|
Out.write(II->getNameStart(), KeyLen);
|
2009-04-21 04:36:09 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
|
|
|
void EmitData(llvm::raw_ostream& Out, const IdentifierInfo* II,
|
2010-08-19 07:57:32 +08:00
|
|
|
IdentID ID, unsigned) {
|
2009-04-29 05:18:29 +08:00
|
|
|
if (!isInterestingIdentifier(II)) {
|
|
|
|
clang::io::Emit32(Out, ID << 1);
|
|
|
|
return;
|
|
|
|
}
|
2009-04-29 05:32:13 +08:00
|
|
|
|
2009-04-29 05:18:29 +08:00
|
|
|
clang::io::Emit32(Out, (ID << 1) | 0x01);
|
2009-04-21 04:36:09 +08:00
|
|
|
uint32_t Bits = 0;
|
2009-09-09 23:08:12 +08:00
|
|
|
bool hasMacroDefinition =
|
|
|
|
II->hasMacroDefinition() &&
|
2009-04-22 07:56:24 +08:00
|
|
|
!PP.getMacroInfo(const_cast<IdentifierInfo *>(II))->isBuiltinMacro();
|
2009-04-29 05:32:13 +08:00
|
|
|
Bits = (uint32_t)II->getObjCOrBuiltinID();
|
2009-12-19 04:58:47 +08:00
|
|
|
Bits = (Bits << 1) | unsigned(hasMacroDefinition);
|
|
|
|
Bits = (Bits << 1) | unsigned(II->isExtensionToken());
|
|
|
|
Bits = (Bits << 1) | unsigned(II->isPoisoned());
|
2010-08-12 06:55:12 +08:00
|
|
|
Bits = (Bits << 1) | unsigned(II->hasRevertedTokenIDToIdentifier());
|
2009-12-19 04:58:47 +08:00
|
|
|
Bits = (Bits << 1) | unsigned(II->isCPlusPlusOperatorKeyword());
|
2009-04-29 05:32:13 +08:00
|
|
|
clang::io::Emit16(Out, Bits);
|
2009-04-21 04:36:09 +08:00
|
|
|
|
2009-04-22 07:56:24 +08:00
|
|
|
if (hasMacroDefinition)
|
2009-04-29 05:32:13 +08:00
|
|
|
clang::io::Emit32(Out, Writer.getMacroOffset(II));
|
2009-04-22 07:56:24 +08:00
|
|
|
|
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").
|
2010-07-24 07:49:55 +08:00
|
|
|
// Only emit declarations that aren't from a chained PCH, though.
|
2009-09-09 23:08:12 +08:00
|
|
|
llvm::SmallVector<Decl *, 16> Decls(IdentifierResolver::begin(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
|
|
|
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)
|
2010-08-03 02:30:12 +08:00
|
|
|
clang::io::Emit32(Out, Writer.getDeclID(*D));
|
2009-04-21 04:36:09 +08:00
|
|
|
}
|
|
|
|
};
|
|
|
|
} // end anonymous namespace
|
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
/// \brief Write the identifier table into the AST file.
|
2009-04-11 08:14:32 +08:00
|
|
|
///
|
|
|
|
/// 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.
|
2010-08-19 07:56:21 +08:00
|
|
|
void ASTWriter::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.
|
|
|
|
{
|
2010-08-19 07:56:27 +08:00
|
|
|
OnDiskChainedHashTableGenerator<ASTIdentifierTableTrait> Generator;
|
2010-08-21 00:04:27 +08:00
|
|
|
ASTIdentifierTableTrait Trait(*this, PP);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-04-29 04:33:11 +08:00
|
|
|
// Look for any identifiers that were named while processing the
|
|
|
|
// headers, but are otherwise not needed. We add these to the hash
|
|
|
|
// table to enable checking of the predefines buffer in the case
|
2010-08-19 07:56:27 +08:00
|
|
|
// where the user adds new macro definitions when building the AST
|
2009-04-29 04:33:11 +08:00
|
|
|
// file.
|
|
|
|
for (IdentifierTable::iterator ID = PP.getIdentifierTable().begin(),
|
|
|
|
IDEnd = PP.getIdentifierTable().end();
|
|
|
|
ID != IDEnd; ++ID)
|
|
|
|
getIdentifierRef(ID->second);
|
|
|
|
|
2010-07-24 07:49:55 +08:00
|
|
|
// Create the on-disk hash table representation. We only store offsets
|
|
|
|
// for identifiers that appear here for the first time.
|
|
|
|
IdentifierOffsets.resize(NextIdentID - FirstIdentID);
|
2010-08-19 07:57:32 +08:00
|
|
|
for (llvm::DenseMap<const IdentifierInfo *, IdentID>::iterator
|
2009-04-11 08:14:32 +08:00
|
|
|
ID = IdentifierIDs.begin(), IDEnd = IdentifierIDs.end();
|
|
|
|
ID != IDEnd; ++ID) {
|
|
|
|
assert(ID->first && "NULL identifier in identifier table");
|
2010-08-19 07:57:06 +08:00
|
|
|
if (!Chain || !ID->first->isFromAST())
|
2010-08-21 00:04:27 +08:00
|
|
|
Generator.insert(ID->first, ID->second, Trait);
|
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.
|
2009-09-09 23:08:12 +08:00
|
|
|
llvm::SmallString<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
|
|
|
{
|
2010-08-19 07:56:27 +08:00
|
|
|
ASTIdentifierTableTrait 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-11 08:14:32 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Create a blob abbreviation
|
|
|
|
BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
|
2010-08-19 07:57:32 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(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;
|
2010-08-19 07:57:32 +08:00
|
|
|
Record.push_back(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-08-24 17:31:37 +08:00
|
|
|
Stream.EmitRecordWithBlob(IDTableAbbrev, Record, IdentifierTable.str());
|
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();
|
2010-08-19 07:57:32 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(IDENTIFIER_OFFSET));
|
2009-04-26 03:10:14 +08:00
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of identifiers
|
|
|
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
|
|
|
|
unsigned IdentifierOffsetAbbrev = Stream.EmitAbbrev(Abbrev);
|
|
|
|
|
|
|
|
RecordData Record;
|
2010-08-19 07:57:32 +08:00
|
|
|
Record.push_back(IDENTIFIER_OFFSET);
|
2009-04-26 03:10:14 +08:00
|
|
|
Record.push_back(IdentifierOffsets.size());
|
|
|
|
Stream.EmitRecordWithBlob(IdentifierOffsetAbbrev, Record,
|
2010-07-31 01:03:48 +08:00
|
|
|
(const char *)data(IdentifierOffsets),
|
2009-04-26 03:10:14 +08:00
|
|
|
IdentifierOffsets.size() * sizeof(uint32_t));
|
2009-04-11 08:14:32 +08:00
|
|
|
}
|
|
|
|
|
2010-08-21 00:04:27 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// DeclContext's Name Lookup Table Serialization
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
// Trait used for the on-disk hash table used in the method pool.
|
|
|
|
class ASTDeclContextNameLookupTrait {
|
|
|
|
ASTWriter &Writer;
|
|
|
|
|
|
|
|
public:
|
|
|
|
typedef DeclarationName key_type;
|
|
|
|
typedef key_type key_type_ref;
|
|
|
|
|
|
|
|
typedef DeclContext::lookup_result data_type;
|
|
|
|
typedef const data_type& data_type_ref;
|
|
|
|
|
|
|
|
explicit ASTDeclContextNameLookupTrait(ASTWriter &Writer) : Writer(Writer) { }
|
|
|
|
|
|
|
|
unsigned ComputeHash(DeclarationName Name) {
|
|
|
|
llvm::FoldingSetNodeID ID;
|
|
|
|
ID.AddInteger(Name.getNameKind());
|
|
|
|
|
|
|
|
switch (Name.getNameKind()) {
|
|
|
|
case DeclarationName::Identifier:
|
|
|
|
ID.AddString(Name.getAsIdentifierInfo()->getName());
|
|
|
|
break;
|
|
|
|
case DeclarationName::ObjCZeroArgSelector:
|
|
|
|
case DeclarationName::ObjCOneArgSelector:
|
|
|
|
case DeclarationName::ObjCMultiArgSelector:
|
|
|
|
ID.AddInteger(serialization::ComputeHash(Name.getObjCSelector()));
|
|
|
|
break;
|
|
|
|
case DeclarationName::CXXConstructorName:
|
|
|
|
case DeclarationName::CXXDestructorName:
|
|
|
|
case DeclarationName::CXXConversionFunctionName:
|
|
|
|
ID.AddInteger(Writer.GetOrCreateTypeID(Name.getCXXNameType()));
|
|
|
|
break;
|
|
|
|
case DeclarationName::CXXOperatorName:
|
|
|
|
ID.AddInteger(Name.getCXXOverloadedOperator());
|
|
|
|
break;
|
|
|
|
case DeclarationName::CXXLiteralOperatorName:
|
|
|
|
ID.AddString(Name.getCXXLiteralIdentifier()->getName());
|
|
|
|
case DeclarationName::CXXUsingDirective:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ID.ComputeHash();
|
|
|
|
}
|
|
|
|
|
|
|
|
std::pair<unsigned,unsigned>
|
|
|
|
EmitKeyDataLength(llvm::raw_ostream& Out, DeclarationName Name,
|
|
|
|
data_type_ref Lookup) {
|
|
|
|
unsigned KeyLen = 1;
|
|
|
|
switch (Name.getNameKind()) {
|
|
|
|
case DeclarationName::Identifier:
|
|
|
|
case DeclarationName::ObjCZeroArgSelector:
|
|
|
|
case DeclarationName::ObjCOneArgSelector:
|
|
|
|
case DeclarationName::ObjCMultiArgSelector:
|
|
|
|
case DeclarationName::CXXConstructorName:
|
|
|
|
case DeclarationName::CXXDestructorName:
|
|
|
|
case DeclarationName::CXXConversionFunctionName:
|
|
|
|
case DeclarationName::CXXLiteralOperatorName:
|
|
|
|
KeyLen += 4;
|
|
|
|
break;
|
|
|
|
case DeclarationName::CXXOperatorName:
|
|
|
|
KeyLen += 1;
|
|
|
|
break;
|
|
|
|
case DeclarationName::CXXUsingDirective:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
clang::io::Emit16(Out, KeyLen);
|
|
|
|
|
|
|
|
// 2 bytes for num of decls and 4 for each DeclID.
|
|
|
|
unsigned DataLen = 2 + 4 * (Lookup.second - Lookup.first);
|
|
|
|
clang::io::Emit16(Out, DataLen);
|
|
|
|
|
|
|
|
return std::make_pair(KeyLen, DataLen);
|
|
|
|
}
|
|
|
|
|
|
|
|
void EmitKey(llvm::raw_ostream& Out, DeclarationName Name, unsigned) {
|
|
|
|
using namespace clang::io;
|
|
|
|
|
|
|
|
assert(Name.getNameKind() < 0x100 && "Invalid name kind ?");
|
|
|
|
Emit8(Out, Name.getNameKind());
|
|
|
|
switch (Name.getNameKind()) {
|
|
|
|
case DeclarationName::Identifier:
|
|
|
|
Emit32(Out, Writer.getIdentifierRef(Name.getAsIdentifierInfo()));
|
|
|
|
break;
|
|
|
|
case DeclarationName::ObjCZeroArgSelector:
|
|
|
|
case DeclarationName::ObjCOneArgSelector:
|
|
|
|
case DeclarationName::ObjCMultiArgSelector:
|
|
|
|
Emit32(Out, Writer.getSelectorRef(Name.getObjCSelector()));
|
|
|
|
break;
|
|
|
|
case DeclarationName::CXXConstructorName:
|
|
|
|
case DeclarationName::CXXDestructorName:
|
|
|
|
case DeclarationName::CXXConversionFunctionName:
|
|
|
|
Emit32(Out, Writer.getTypeID(Name.getCXXNameType()));
|
|
|
|
break;
|
|
|
|
case DeclarationName::CXXOperatorName:
|
|
|
|
assert(Name.getCXXOverloadedOperator() < 0x100 && "Invalid operator ?");
|
|
|
|
Emit8(Out, Name.getCXXOverloadedOperator());
|
|
|
|
break;
|
|
|
|
case DeclarationName::CXXLiteralOperatorName:
|
|
|
|
Emit32(Out, Writer.getIdentifierRef(Name.getCXXLiteralIdentifier()));
|
|
|
|
break;
|
|
|
|
case DeclarationName::CXXUsingDirective:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void EmitData(llvm::raw_ostream& Out, key_type_ref,
|
|
|
|
data_type Lookup, unsigned DataLen) {
|
|
|
|
uint64_t Start = Out.tell(); (void)Start;
|
|
|
|
clang::io::Emit16(Out, Lookup.second - Lookup.first);
|
|
|
|
for (; Lookup.first != Lookup.second; ++Lookup.first)
|
|
|
|
clang::io::Emit32(Out, Writer.GetDeclRef(*Lookup.first));
|
|
|
|
|
|
|
|
assert(Out.tell() - Start == DataLen && "Data length is wrong");
|
|
|
|
}
|
|
|
|
};
|
|
|
|
} // end anonymous namespace
|
|
|
|
|
2010-08-21 00:04:35 +08:00
|
|
|
/// \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
|
2010-08-24 08:50:09 +08:00
|
|
|
/// bitstream, or 0 if no block was written.
|
2010-08-21 00:04:35 +08:00
|
|
|
uint64_t ASTWriter::WriteDeclContextVisibleBlock(ASTContext &Context,
|
|
|
|
DeclContext *DC) {
|
|
|
|
if (DC->getPrimaryContext() != DC)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
// Since there is no name lookup into functions or methods, don't bother to
|
|
|
|
// build a visible-declarations table for these entities.
|
|
|
|
if (DC->isFunctionOrMethod())
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
// If not in C++, we perform name lookup for the translation unit via the
|
|
|
|
// IdentifierInfo chains, don't bother to build a visible-declarations table.
|
|
|
|
// FIXME: In C++ we need the visible declarations in order to "see" the
|
|
|
|
// friend declarations, is there a way to do this without writing the table ?
|
|
|
|
if (DC->isTranslationUnit() && !Context.getLangOptions().CPlusPlus)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
// Force the DeclContext to build a its name-lookup table.
|
2010-08-21 07:35:55 +08:00
|
|
|
if (DC->hasExternalVisibleStorage())
|
|
|
|
DC->MaterializeVisibleDeclsFromExternalStorage();
|
|
|
|
else
|
|
|
|
DC->lookup(DeclarationName());
|
2010-08-21 00:04:35 +08:00
|
|
|
|
|
|
|
// Serialize the contents of the mapping used for lookup. Note that,
|
|
|
|
// although we have two very different code paths, the serialized
|
|
|
|
// representation is the same for both cases: a declaration name,
|
|
|
|
// followed by a size, followed by references to the visible
|
|
|
|
// declarations that have that name.
|
|
|
|
uint64_t Offset = Stream.GetCurrentBitNo();
|
|
|
|
StoredDeclsMap *Map = static_cast<StoredDeclsMap*>(DC->getLookupPtr());
|
|
|
|
if (!Map || Map->empty())
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
OnDiskChainedHashTableGenerator<ASTDeclContextNameLookupTrait> Generator;
|
|
|
|
ASTDeclContextNameLookupTrait Trait(*this);
|
|
|
|
|
|
|
|
// Create the on-disk hash table representation.
|
|
|
|
for (StoredDeclsMap::iterator D = Map->begin(), DEnd = Map->end();
|
|
|
|
D != DEnd; ++D) {
|
|
|
|
DeclarationName Name = D->first;
|
|
|
|
DeclContext::lookup_result Result = D->second.getLookupResult();
|
|
|
|
Generator.insert(Name, Result, Trait);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create the on-disk hash table in a buffer.
|
|
|
|
llvm::SmallString<4096> LookupTable;
|
|
|
|
uint32_t BucketOffset;
|
|
|
|
{
|
|
|
|
llvm::raw_svector_ostream Out(LookupTable);
|
|
|
|
// Make sure that no bucket is at offset 0
|
|
|
|
clang::io::Emit32(Out, 0);
|
|
|
|
BucketOffset = Generator.Emit(Out, Trait);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Write the lookup table
|
|
|
|
RecordData Record;
|
|
|
|
Record.push_back(DECL_CONTEXT_VISIBLE);
|
|
|
|
Record.push_back(BucketOffset);
|
|
|
|
Stream.EmitRecordWithBlob(DeclContextVisibleLookupAbbrev, Record,
|
|
|
|
LookupTable.str());
|
|
|
|
|
|
|
|
Stream.EmitRecord(DECL_CONTEXT_VISIBLE, Record);
|
|
|
|
++NumVisibleDeclContexts;
|
|
|
|
return Offset;
|
|
|
|
}
|
|
|
|
|
2010-08-24 08:50:09 +08:00
|
|
|
/// \brief Write an UPDATE_VISIBLE block for the given context.
|
|
|
|
///
|
|
|
|
/// UPDATE_VISIBLE blocks contain the declarations that are added to an existing
|
|
|
|
/// DeclContext in a dependent AST file. As such, they only exist for the TU
|
|
|
|
/// (in C++) and for namespaces.
|
|
|
|
void ASTWriter::WriteDeclContextVisibleUpdate(const DeclContext *DC) {
|
|
|
|
assert((DC->isTranslationUnit() || DC->isNamespace()) &&
|
|
|
|
"Only TU and namespaces should have visible decl updates.");
|
|
|
|
|
|
|
|
// Make the context build its lookup table, but don't make it load external
|
|
|
|
// decls.
|
|
|
|
DC->lookup(DeclarationName());
|
|
|
|
|
|
|
|
StoredDeclsMap *Map = static_cast<StoredDeclsMap*>(DC->getLookupPtr());
|
|
|
|
if (!Map || Map->empty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
OnDiskChainedHashTableGenerator<ASTDeclContextNameLookupTrait> Generator;
|
|
|
|
ASTDeclContextNameLookupTrait Trait(*this);
|
|
|
|
|
|
|
|
// Create the hash table.
|
|
|
|
for (StoredDeclsMap::iterator D = Map->begin(), DEnd = Map->end();
|
|
|
|
D != DEnd; ++D) {
|
|
|
|
DeclarationName Name = D->first;
|
|
|
|
DeclContext::lookup_result Result = D->second.getLookupResult();
|
2010-08-24 08:50:16 +08:00
|
|
|
// For any name that appears in this table, the results are complete, i.e.
|
|
|
|
// they overwrite results from previous PCHs. Merging is always a mess.
|
|
|
|
Generator.insert(Name, Result, Trait);
|
2010-08-24 08:50:09 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Create the on-disk hash table in a buffer.
|
|
|
|
llvm::SmallString<4096> LookupTable;
|
|
|
|
uint32_t BucketOffset;
|
|
|
|
{
|
|
|
|
llvm::raw_svector_ostream Out(LookupTable);
|
|
|
|
// Make sure that no bucket is at offset 0
|
|
|
|
clang::io::Emit32(Out, 0);
|
|
|
|
BucketOffset = Generator.Emit(Out, Trait);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Write the lookup table
|
|
|
|
RecordData Record;
|
|
|
|
Record.push_back(UPDATE_VISIBLE);
|
|
|
|
Record.push_back(getDeclID(cast<Decl>(DC)));
|
|
|
|
Record.push_back(BucketOffset);
|
|
|
|
Stream.EmitRecordWithBlob(UpdateVisibleAbbrev, Record, LookupTable.str());
|
|
|
|
}
|
|
|
|
|
2010-08-25 06:50:24 +08:00
|
|
|
/// \brief Write ADDITIONAL_TEMPLATE_SPECIALIZATIONS blocks for all templates
|
|
|
|
/// that have new specializations in the current AST file.
|
|
|
|
void ASTWriter::WriteAdditionalTemplateSpecializations() {
|
|
|
|
RecordData Record;
|
|
|
|
for (AdditionalTemplateSpecializationsMap::iterator
|
|
|
|
I = AdditionalTemplateSpecializations.begin(),
|
|
|
|
E = AdditionalTemplateSpecializations.end();
|
|
|
|
I != E; ++I) {
|
|
|
|
Record.clear();
|
|
|
|
Record.push_back(I->first);
|
|
|
|
Record.insert(Record.end(), I->second.begin(), I->second.end());
|
|
|
|
Stream.EmitRecord(ADDITIONAL_TEMPLATE_SPECIALIZATIONS, Record);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-04-28 02:38:38 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// General Serialization Routines
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2009-04-16 05:30:51 +08:00
|
|
|
/// \brief Write a record containing the given attributes.
|
2010-08-19 07:56:21 +08:00
|
|
|
void ASTWriter::WriteAttributeRecord(const AttrVec &Attrs) {
|
2009-04-16 05:30:51 +08:00
|
|
|
RecordData Record;
|
2010-08-19 07:23:40 +08:00
|
|
|
for (AttrVec::const_iterator i = Attrs.begin(), e = Attrs.end(); i != e; ++i){
|
|
|
|
const Attr * A = *i;
|
|
|
|
Record.push_back(A->getKind()); // FIXME: stable encoding, target attrs
|
|
|
|
AddSourceLocation(A->getLocation(), Record);
|
|
|
|
Record.push_back(A->isInherited());
|
2009-04-16 05:30:51 +08:00
|
|
|
|
2010-08-19 07:23:40 +08:00
|
|
|
#include "clang/Serialization/AttrPCHWrite.inc"
|
2009-05-21 01:41:43 +08:00
|
|
|
|
2009-04-16 05:30:51 +08:00
|
|
|
}
|
|
|
|
|
2010-08-19 07:57:32 +08:00
|
|
|
Stream.EmitRecord(DECL_ATTR, Record);
|
2009-04-16 05:30:51 +08:00
|
|
|
}
|
|
|
|
|
2010-09-02 23:06:24 +08:00
|
|
|
void ASTWriter::AddString(llvm::StringRef Str, RecordData &Record) {
|
2009-04-16 05:30:51 +08:00
|
|
|
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.
|
2010-08-19 07:56:21 +08:00
|
|
|
void ASTWriter::SetIdentifierOffset(const IdentifierInfo *II, uint32_t Offset) {
|
2010-08-19 07:57:32 +08:00
|
|
|
IdentID ID = IdentifierIDs[II];
|
2010-08-19 07:56:27 +08:00
|
|
|
// Only store offsets new to this AST file. Other identifier names are looked
|
2010-07-24 07:49:55 +08:00
|
|
|
// up earlier in the chain and thus don't need an offset.
|
|
|
|
if (ID >= FirstIdentID)
|
|
|
|
IdentifierOffsets[ID - FirstIdentID] = 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.
|
2010-08-19 07:56:21 +08:00
|
|
|
void ASTWriter::SetSelectorOffset(Selector Sel, uint32_t Offset) {
|
2009-04-26 01:48:32 +08:00
|
|
|
unsigned ID = SelectorIDs[Sel];
|
|
|
|
assert(ID && "Unknown selector");
|
2010-08-05 02:21:41 +08:00
|
|
|
// Don't record offsets for selectors that are also available in a different
|
|
|
|
// file.
|
|
|
|
if (ID < FirstSelectorID)
|
|
|
|
return;
|
|
|
|
SelectorOffsets[ID - FirstSelectorID] = Offset;
|
2009-04-26 01:48:32 +08:00
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:21 +08:00
|
|
|
ASTWriter::ASTWriter(llvm::BitstreamWriter &Stream)
|
2010-08-05 02:21:41 +08:00
|
|
|
: Stream(Stream), Chain(0), FirstDeclID(1), NextDeclID(FirstDeclID),
|
2010-08-19 07:57:32 +08:00
|
|
|
FirstTypeID(NUM_PREDEF_TYPE_IDS), NextTypeID(FirstTypeID),
|
2010-08-05 02:21:41 +08:00
|
|
|
FirstIdentID(1), NextIdentID(FirstIdentID), FirstSelectorID(1),
|
2010-10-03 03:29:26 +08:00
|
|
|
NextSelectorID(FirstSelectorID), FirstMacroID(1), NextMacroID(FirstMacroID),
|
|
|
|
CollectedStmts(&StmtsToEmit),
|
2010-08-05 02:21:41 +08:00
|
|
|
NumStatements(0), NumMacros(0), NumLexicalDeclContexts(0),
|
|
|
|
NumVisibleDeclContexts(0) {
|
2010-07-15 07:45:08 +08:00
|
|
|
}
|
2009-04-10 06:27:44 +08:00
|
|
|
|
2010-08-19 07:56:21 +08:00
|
|
|
void ASTWriter::WriteAST(Sema &SemaRef, MemorizeStatCalls *StatCalls,
|
2010-07-15 07:45:08 +08:00
|
|
|
const char *isysroot) {
|
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-09-09 23:08:12 +08:00
|
|
|
|
2009-04-27 06:26:21 +08:00
|
|
|
WriteBlockInfoBlock();
|
2009-04-10 06:27:44 +08:00
|
|
|
|
2010-07-13 06:02:52 +08:00
|
|
|
if (Chain)
|
2010-08-19 07:56:21 +08:00
|
|
|
WriteASTChain(SemaRef, StatCalls, isysroot);
|
2010-07-13 06:02:52 +08:00
|
|
|
else
|
2010-08-19 07:56:21 +08:00
|
|
|
WriteASTCore(SemaRef, StatCalls, isysroot);
|
2010-07-13 06:02:52 +08:00
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:21 +08:00
|
|
|
void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls,
|
2010-07-13 06:02:52 +08:00
|
|
|
const char *isysroot) {
|
|
|
|
using namespace llvm;
|
|
|
|
|
|
|
|
ASTContext &Context = SemaRef.Context;
|
|
|
|
Preprocessor &PP = SemaRef.PP;
|
|
|
|
|
2009-04-10 06:27:44 +08:00
|
|
|
// The translation unit is the first declaration we'll emit.
|
|
|
|
DeclIDs[Context.getTranslationUnitDecl()] = 1;
|
2010-07-24 07:49:55 +08:00
|
|
|
++NextDeclID;
|
2009-10-17 08:13:19 +08:00
|
|
|
DeclTypesToEmit.push(Context.getTranslationUnitDecl());
|
2009-04-10 06:27:44 +08:00
|
|
|
|
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-09-09 02:19:27 +08:00
|
|
|
// Build a record containing all of the tentative definitions in this file, in
|
2010-02-01 06:27:38 +08:00
|
|
|
// TentativeDefinitions order. Generally, this record will be empty for
|
2009-09-09 02:19:27 +08:00
|
|
|
// headers.
|
2009-04-23 06:02:47 +08:00
|
|
|
RecordData TentativeDefinitions;
|
2010-02-01 06:27:38 +08:00
|
|
|
for (unsigned i = 0, e = SemaRef.TentativeDefinitions.size(); i != e; ++i) {
|
|
|
|
AddDeclRef(SemaRef.TentativeDefinitions[i], TentativeDefinitions);
|
2009-09-09 02:19:27 +08:00
|
|
|
}
|
2009-04-23 06:02:47 +08:00
|
|
|
|
2010-08-14 02:42:17 +08:00
|
|
|
// Build a record containing all of the file scoped decls in this file.
|
|
|
|
RecordData UnusedFileScopedDecls;
|
|
|
|
for (unsigned i=0, e = SemaRef.UnusedFileScopedDecls.size(); i !=e; ++i)
|
|
|
|
AddDeclRef(SemaRef.UnusedFileScopedDecls[i], UnusedFileScopedDecls);
|
2010-08-06 02:21:25 +08:00
|
|
|
|
2010-08-05 17:48:08 +08:00
|
|
|
RecordData WeakUndeclaredIdentifiers;
|
|
|
|
if (!SemaRef.WeakUndeclaredIdentifiers.empty()) {
|
|
|
|
WeakUndeclaredIdentifiers.push_back(
|
|
|
|
SemaRef.WeakUndeclaredIdentifiers.size());
|
|
|
|
for (llvm::DenseMap<IdentifierInfo*,Sema::WeakInfo>::iterator
|
|
|
|
I = SemaRef.WeakUndeclaredIdentifiers.begin(),
|
|
|
|
E = SemaRef.WeakUndeclaredIdentifiers.end(); I != E; ++I) {
|
|
|
|
AddIdentifierRef(I->first, WeakUndeclaredIdentifiers);
|
|
|
|
AddIdentifierRef(I->second.getAlias(), WeakUndeclaredIdentifiers);
|
|
|
|
AddSourceLocation(I->second.getLocation(), WeakUndeclaredIdentifiers);
|
|
|
|
WeakUndeclaredIdentifiers.push_back(I->second.getUsed());
|
|
|
|
}
|
|
|
|
}
|
2010-03-14 15:06:50 +08:00
|
|
|
|
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;
|
2010-08-19 07:56:27 +08:00
|
|
|
// FIXME: This is filling in the AST file in densemap order which is
|
2009-09-09 02:19:27 +08:00
|
|
|
// nondeterminstic!
|
2009-09-09 23:08:12 +08:00
|
|
|
for (llvm::DenseMap<DeclarationName, NamedDecl *>::iterator
|
2009-04-23 06:18:58 +08:00
|
|
|
TD = SemaRef.LocallyScopedExternalDecls.begin(),
|
|
|
|
TDEnd = SemaRef.LocallyScopedExternalDecls.end();
|
|
|
|
TD != TDEnd; ++TD)
|
|
|
|
AddDeclRef(TD->second, LocallyScopedExternalDecls);
|
|
|
|
|
2009-04-28 04:06:05 +08:00
|
|
|
// Build a record containing all of the ext_vector declarations.
|
|
|
|
RecordData ExtVectorDecls;
|
|
|
|
for (unsigned I = 0, N = SemaRef.ExtVectorDecls.size(); I != N; ++I)
|
|
|
|
AddDeclRef(SemaRef.ExtVectorDecls[I], ExtVectorDecls);
|
|
|
|
|
2010-07-06 23:37:04 +08:00
|
|
|
// Build a record containing all of the VTable uses information.
|
|
|
|
RecordData VTableUses;
|
2010-08-04 01:29:52 +08:00
|
|
|
if (!SemaRef.VTableUses.empty()) {
|
|
|
|
VTableUses.push_back(SemaRef.VTableUses.size());
|
|
|
|
for (unsigned I = 0, N = SemaRef.VTableUses.size(); I != N; ++I) {
|
|
|
|
AddDeclRef(SemaRef.VTableUses[I].first, VTableUses);
|
|
|
|
AddSourceLocation(SemaRef.VTableUses[I].second, VTableUses);
|
|
|
|
VTableUses.push_back(SemaRef.VTablesUsed[SemaRef.VTableUses[I].first]);
|
|
|
|
}
|
2010-07-06 23:37:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Build a record containing all of dynamic classes declarations.
|
|
|
|
RecordData DynamicClasses;
|
|
|
|
for (unsigned I = 0, N = SemaRef.DynamicClasses.size(); I != N; ++I)
|
|
|
|
AddDeclRef(SemaRef.DynamicClasses[I], DynamicClasses);
|
|
|
|
|
2010-08-05 17:48:16 +08:00
|
|
|
// Build a record containing all of pending implicit instantiations.
|
2010-08-25 16:44:16 +08:00
|
|
|
RecordData PendingInstantiations;
|
2010-08-05 17:48:16 +08:00
|
|
|
for (std::deque<Sema::PendingImplicitInstantiation>::iterator
|
2010-08-25 16:44:16 +08:00
|
|
|
I = SemaRef.PendingInstantiations.begin(),
|
|
|
|
N = SemaRef.PendingInstantiations.end(); I != N; ++I) {
|
|
|
|
AddDeclRef(I->first, PendingInstantiations);
|
|
|
|
AddSourceLocation(I->second, PendingInstantiations);
|
2010-08-05 17:48:16 +08:00
|
|
|
}
|
|
|
|
assert(SemaRef.PendingLocalImplicitInstantiations.empty() &&
|
|
|
|
"There are local ones at end of translation unit!");
|
|
|
|
|
2010-08-02 15:14:54 +08:00
|
|
|
// Build a record containing some declaration references.
|
|
|
|
RecordData SemaDeclRefs;
|
|
|
|
if (SemaRef.StdNamespace || SemaRef.StdBadAlloc) {
|
|
|
|
AddDeclRef(SemaRef.getStdNamespace(), SemaDeclRefs);
|
|
|
|
AddDeclRef(SemaRef.getStdBadAlloc(), SemaDeclRefs);
|
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:27 +08:00
|
|
|
// Write the remaining AST contents.
|
2009-04-18 13:55:16 +08:00
|
|
|
RecordData Record;
|
2010-08-19 07:57:32 +08:00
|
|
|
Stream.EnterSubblock(AST_BLOCK_ID, 5);
|
2010-07-15 07:45:08 +08:00
|
|
|
WriteMetadata(Context, isysroot);
|
2010-07-13 06:02:52 +08:00
|
|
|
WriteLanguageOptions(Context.getLangOptions());
|
2009-07-07 08:12:59 +08:00
|
|
|
if (StatCalls && !isysroot)
|
2010-07-13 07:48:14 +08:00
|
|
|
WriteStatCache(*StatCalls);
|
2009-07-07 08:12:59 +08:00
|
|
|
WriteSourceManagerBlock(Context.getSourceManager(), PP, isysroot);
|
2009-07-18 23:33:26 +08:00
|
|
|
// Write the record of special types.
|
|
|
|
Record.clear();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-18 23:33:26 +08:00
|
|
|
AddTypeRef(Context.getBuiltinVaListType(), Record);
|
|
|
|
AddTypeRef(Context.getObjCIdType(), Record);
|
|
|
|
AddTypeRef(Context.getObjCSelType(), Record);
|
|
|
|
AddTypeRef(Context.getObjCProtoType(), Record);
|
|
|
|
AddTypeRef(Context.getObjCClassType(), Record);
|
|
|
|
AddTypeRef(Context.getRawCFConstantStringType(), Record);
|
|
|
|
AddTypeRef(Context.getRawObjCFastEnumerationStateType(), Record);
|
|
|
|
AddTypeRef(Context.getFILEType(), Record);
|
2009-07-28 10:25:19 +08:00
|
|
|
AddTypeRef(Context.getjmp_bufType(), Record);
|
|
|
|
AddTypeRef(Context.getsigjmp_bufType(), Record);
|
2009-08-21 08:27:50 +08:00
|
|
|
AddTypeRef(Context.ObjCIdRedefinitionType, Record);
|
|
|
|
AddTypeRef(Context.ObjCClassRedefinitionType, Record);
|
2009-10-20 10:12:22 +08:00
|
|
|
AddTypeRef(Context.getRawBlockdescriptorType(), Record);
|
2009-10-22 08:49:09 +08:00
|
|
|
AddTypeRef(Context.getRawBlockdescriptorExtendedType(), Record);
|
2010-04-24 01:41:07 +08:00
|
|
|
AddTypeRef(Context.ObjCSelRedefinitionType, Record);
|
|
|
|
AddTypeRef(Context.getRawNSConstantStringType(), Record);
|
2010-07-05 05:44:19 +08:00
|
|
|
Record.push_back(Context.isInt128Installed());
|
2010-08-19 07:57:32 +08:00
|
|
|
Stream.EmitRecord(SPECIAL_TYPES, Record);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-04-26 11:49:13 +08:00
|
|
|
// Keep writing types and declarations until all types and
|
|
|
|
// declarations have been written.
|
2010-08-19 07:57:32 +08:00
|
|
|
Stream.EnterSubblock(DECLTYPES_BLOCK_ID, 3);
|
2009-10-17 08:13:19 +08:00
|
|
|
WriteDeclsBlockAbbrevs();
|
|
|
|
while (!DeclTypesToEmit.empty()) {
|
|
|
|
DeclOrType DOT = DeclTypesToEmit.front();
|
|
|
|
DeclTypesToEmit.pop();
|
|
|
|
if (DOT.isType())
|
|
|
|
WriteType(DOT.getType());
|
|
|
|
else
|
|
|
|
WriteDecl(Context, DOT.getDecl());
|
|
|
|
}
|
|
|
|
Stream.ExitBlock();
|
2010-03-14 15:06:50 +08:00
|
|
|
|
2009-10-18 01:25:45 +08:00
|
|
|
WritePreprocessor(PP);
|
2010-08-04 05:58:15 +08:00
|
|
|
WriteSelectors(SemaRef);
|
2010-07-24 03:11:11 +08:00
|
|
|
WriteReferencedSelectorsPool(SemaRef);
|
2009-04-22 07:56:24 +08:00
|
|
|
WriteIdentifierTable(PP);
|
2009-04-26 02:35:21 +08:00
|
|
|
|
2010-07-17 00:36:56 +08:00
|
|
|
WriteTypeDeclOffsets();
|
2009-04-18 13:55:16 +08:00
|
|
|
|
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())
|
2010-08-19 07:57:32 +08:00
|
|
|
Stream.EmitRecord(EXTERNAL_DEFINITIONS, ExternalDefinitions);
|
2009-04-23 06:02:47 +08:00
|
|
|
|
|
|
|
// Write the record containing tentative definitions.
|
|
|
|
if (!TentativeDefinitions.empty())
|
2010-08-19 07:57:32 +08:00
|
|
|
Stream.EmitRecord(TENTATIVE_DEFINITIONS, TentativeDefinitions);
|
2009-04-23 06:18:58 +08:00
|
|
|
|
2010-08-14 02:42:17 +08:00
|
|
|
// Write the record containing unused file scoped decls.
|
|
|
|
if (!UnusedFileScopedDecls.empty())
|
2010-08-19 07:57:32 +08:00
|
|
|
Stream.EmitRecord(UNUSED_FILESCOPED_DECLS, UnusedFileScopedDecls);
|
2010-03-14 15:06:50 +08:00
|
|
|
|
2010-08-05 17:48:08 +08:00
|
|
|
// Write the record containing weak undeclared identifiers.
|
|
|
|
if (!WeakUndeclaredIdentifiers.empty())
|
2010-08-19 07:57:32 +08:00
|
|
|
Stream.EmitRecord(WEAK_UNDECLARED_IDENTIFIERS,
|
2010-08-05 17:48:08 +08:00
|
|
|
WeakUndeclaredIdentifiers);
|
|
|
|
|
2009-04-23 06:18:58 +08:00
|
|
|
// Write the record containing locally-scoped external definitions.
|
|
|
|
if (!LocallyScopedExternalDecls.empty())
|
2010-08-19 07:57:32 +08:00
|
|
|
Stream.EmitRecord(LOCALLY_SCOPED_EXTERNAL_DECLS,
|
2009-04-23 06:18:58 +08:00
|
|
|
LocallyScopedExternalDecls);
|
2009-04-28 04:06:05 +08:00
|
|
|
|
|
|
|
// Write the record containing ext_vector type names.
|
|
|
|
if (!ExtVectorDecls.empty())
|
2010-08-19 07:57:32 +08:00
|
|
|
Stream.EmitRecord(EXT_VECTOR_DECLS, ExtVectorDecls);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-07-06 23:37:04 +08:00
|
|
|
// Write the record containing VTable uses information.
|
|
|
|
if (!VTableUses.empty())
|
2010-08-19 07:57:32 +08:00
|
|
|
Stream.EmitRecord(VTABLE_USES, VTableUses);
|
2010-07-06 23:37:04 +08:00
|
|
|
|
|
|
|
// Write the record containing dynamic classes declarations.
|
|
|
|
if (!DynamicClasses.empty())
|
2010-08-19 07:57:32 +08:00
|
|
|
Stream.EmitRecord(DYNAMIC_CLASSES, DynamicClasses);
|
2010-07-06 23:37:04 +08:00
|
|
|
|
2010-08-05 17:48:16 +08:00
|
|
|
// Write the record containing pending implicit instantiations.
|
2010-08-25 16:44:16 +08:00
|
|
|
if (!PendingInstantiations.empty())
|
|
|
|
Stream.EmitRecord(PENDING_IMPLICIT_INSTANTIATIONS, PendingInstantiations);
|
2010-08-05 17:48:16 +08:00
|
|
|
|
2010-08-02 15:14:54 +08:00
|
|
|
// Write the record containing declaration references of Sema.
|
|
|
|
if (!SemaDeclRefs.empty())
|
2010-08-19 07:57:32 +08:00
|
|
|
Stream.EmitRecord(SEMA_DECL_REFS, SemaDeclRefs);
|
2010-08-02 15:14:54 +08:00
|
|
|
|
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);
|
2010-08-19 07:57:32 +08:00
|
|
|
Stream.EmitRecord(STATISTICS, Record);
|
2009-04-17 06:23:12 +08:00
|
|
|
Stream.ExitBlock();
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:21 +08:00
|
|
|
void ASTWriter::WriteASTChain(Sema &SemaRef, MemorizeStatCalls *StatCalls,
|
2010-07-15 07:45:08 +08:00
|
|
|
const char *isysroot) {
|
2010-07-13 06:02:52 +08:00
|
|
|
using namespace llvm;
|
|
|
|
|
2010-07-30 08:29:29 +08:00
|
|
|
FirstDeclID += Chain->getTotalNumDecls();
|
|
|
|
FirstTypeID += Chain->getTotalNumTypes();
|
|
|
|
FirstIdentID += Chain->getTotalNumIdentifiers();
|
2010-08-05 02:21:41 +08:00
|
|
|
FirstSelectorID += Chain->getTotalNumSelectors();
|
2010-10-03 03:29:26 +08:00
|
|
|
FirstMacroID += Chain->getTotalNumMacroDefinitions();
|
2010-07-30 08:29:29 +08:00
|
|
|
NextDeclID = FirstDeclID;
|
|
|
|
NextTypeID = FirstTypeID;
|
|
|
|
NextIdentID = FirstIdentID;
|
2010-08-05 02:21:41 +08:00
|
|
|
NextSelectorID = FirstSelectorID;
|
2010-10-03 03:29:26 +08:00
|
|
|
NextMacroID = FirstMacroID;
|
2010-07-30 08:29:29 +08:00
|
|
|
|
2010-07-13 06:02:52 +08:00
|
|
|
ASTContext &Context = SemaRef.Context;
|
|
|
|
Preprocessor &PP = SemaRef.PP;
|
2010-07-17 00:36:56 +08:00
|
|
|
|
2010-07-13 06:02:52 +08:00
|
|
|
RecordData Record;
|
2010-08-19 07:57:32 +08:00
|
|
|
Stream.EnterSubblock(AST_BLOCK_ID, 5);
|
2010-07-15 07:45:08 +08:00
|
|
|
WriteMetadata(Context, isysroot);
|
2010-07-17 00:36:56 +08:00
|
|
|
if (StatCalls && !isysroot)
|
|
|
|
WriteStatCache(*StatCalls);
|
|
|
|
// FIXME: Source manager block should only write new stuff, which could be
|
|
|
|
// done by tracking the largest ID in the chain
|
|
|
|
WriteSourceManagerBlock(Context.getSourceManager(), PP, isysroot);
|
2010-07-13 06:02:52 +08:00
|
|
|
|
|
|
|
// The special types are in the chained PCH.
|
|
|
|
|
|
|
|
// We don't start with the translation unit, but with its decls that
|
2010-08-19 07:57:06 +08:00
|
|
|
// don't come from the chained PCH.
|
2010-07-13 06:02:52 +08:00
|
|
|
const TranslationUnitDecl *TU = Context.getTranslationUnitDecl();
|
2010-10-15 04:14:34 +08:00
|
|
|
llvm::SmallVector<KindDeclIDPair, 64> NewGlobalDecls;
|
2010-07-27 08:17:23 +08:00
|
|
|
for (DeclContext::decl_iterator I = TU->noload_decls_begin(),
|
|
|
|
E = TU->noload_decls_end();
|
2010-07-13 06:02:52 +08:00
|
|
|
I != E; ++I) {
|
2010-07-28 02:24:41 +08:00
|
|
|
if ((*I)->getPCHLevel() == 0)
|
2010-10-15 04:14:34 +08:00
|
|
|
NewGlobalDecls.push_back(std::make_pair((*I)->getKind(), GetDeclRef(*I)));
|
2010-08-13 08:28:03 +08:00
|
|
|
else if ((*I)->isChangedSinceDeserialization())
|
|
|
|
(void)GetDeclRef(*I); // Make sure it's written, but don't record it.
|
2010-07-13 06:02:52 +08:00
|
|
|
}
|
2010-07-27 08:17:23 +08:00
|
|
|
// We also need to write a lexical updates block for the TU.
|
2010-07-28 02:24:41 +08:00
|
|
|
llvm::BitCodeAbbrev *Abv = new llvm::BitCodeAbbrev();
|
2010-08-19 07:57:32 +08:00
|
|
|
Abv->Add(llvm::BitCodeAbbrevOp(TU_UPDATE_LEXICAL));
|
2010-07-28 02:24:41 +08:00
|
|
|
Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob));
|
|
|
|
unsigned TuUpdateLexicalAbbrev = Stream.EmitAbbrev(Abv);
|
|
|
|
Record.clear();
|
2010-08-19 07:57:32 +08:00
|
|
|
Record.push_back(TU_UPDATE_LEXICAL);
|
2010-07-28 02:24:41 +08:00
|
|
|
Stream.EmitRecordWithBlob(TuUpdateLexicalAbbrev, Record,
|
|
|
|
reinterpret_cast<const char*>(NewGlobalDecls.data()),
|
2010-10-15 04:14:34 +08:00
|
|
|
NewGlobalDecls.size() * sizeof(KindDeclIDPair));
|
2010-08-24 08:50:09 +08:00
|
|
|
// And in C++, a visible updates block for the TU.
|
|
|
|
if (Context.getLangOptions().CPlusPlus) {
|
|
|
|
Abv = new llvm::BitCodeAbbrev();
|
|
|
|
Abv->Add(llvm::BitCodeAbbrevOp(UPDATE_VISIBLE));
|
|
|
|
Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::VBR, 6));
|
|
|
|
Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed, 32));
|
|
|
|
Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob));
|
|
|
|
UpdateVisibleAbbrev = Stream.EmitAbbrev(Abv);
|
|
|
|
WriteDeclContextVisibleUpdate(TU);
|
|
|
|
}
|
2010-07-13 06:02:52 +08:00
|
|
|
|
2010-07-28 07:01:28 +08:00
|
|
|
// Build a record containing all of the new tentative definitions in this
|
|
|
|
// file, in TentativeDefinitions order.
|
|
|
|
RecordData TentativeDefinitions;
|
|
|
|
for (unsigned i = 0, e = SemaRef.TentativeDefinitions.size(); i != e; ++i) {
|
|
|
|
if (SemaRef.TentativeDefinitions[i]->getPCHLevel() == 0)
|
|
|
|
AddDeclRef(SemaRef.TentativeDefinitions[i], TentativeDefinitions);
|
|
|
|
}
|
|
|
|
|
2010-08-14 02:42:17 +08:00
|
|
|
// Build a record containing all of the file scoped decls in this file.
|
|
|
|
RecordData UnusedFileScopedDecls;
|
|
|
|
for (unsigned i=0, e = SemaRef.UnusedFileScopedDecls.size(); i !=e; ++i) {
|
|
|
|
if (SemaRef.UnusedFileScopedDecls[i]->getPCHLevel() == 0)
|
|
|
|
AddDeclRef(SemaRef.UnusedFileScopedDecls[i], UnusedFileScopedDecls);
|
2010-07-28 07:01:28 +08:00
|
|
|
}
|
|
|
|
|
2010-08-06 02:21:25 +08:00
|
|
|
// We write the entire table, overwriting the tables from the chain.
|
|
|
|
RecordData WeakUndeclaredIdentifiers;
|
|
|
|
if (!SemaRef.WeakUndeclaredIdentifiers.empty()) {
|
|
|
|
WeakUndeclaredIdentifiers.push_back(
|
|
|
|
SemaRef.WeakUndeclaredIdentifiers.size());
|
|
|
|
for (llvm::DenseMap<IdentifierInfo*,Sema::WeakInfo>::iterator
|
|
|
|
I = SemaRef.WeakUndeclaredIdentifiers.begin(),
|
|
|
|
E = SemaRef.WeakUndeclaredIdentifiers.end(); I != E; ++I) {
|
|
|
|
AddIdentifierRef(I->first, WeakUndeclaredIdentifiers);
|
|
|
|
AddIdentifierRef(I->second.getAlias(), WeakUndeclaredIdentifiers);
|
|
|
|
AddSourceLocation(I->second.getLocation(), WeakUndeclaredIdentifiers);
|
|
|
|
WeakUndeclaredIdentifiers.push_back(I->second.getUsed());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-07-28 07:01:28 +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;
|
2010-08-19 07:56:27 +08:00
|
|
|
// FIXME: This is filling in the AST file in densemap order which is
|
2010-07-28 07:01:28 +08:00
|
|
|
// nondeterminstic!
|
|
|
|
for (llvm::DenseMap<DeclarationName, NamedDecl *>::iterator
|
|
|
|
TD = SemaRef.LocallyScopedExternalDecls.begin(),
|
|
|
|
TDEnd = SemaRef.LocallyScopedExternalDecls.end();
|
|
|
|
TD != TDEnd; ++TD) {
|
|
|
|
if (TD->second->getPCHLevel() == 0)
|
|
|
|
AddDeclRef(TD->second, LocallyScopedExternalDecls);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Build a record containing all of the ext_vector declarations.
|
|
|
|
RecordData ExtVectorDecls;
|
|
|
|
for (unsigned I = 0, N = SemaRef.ExtVectorDecls.size(); I != N; ++I) {
|
|
|
|
if (SemaRef.ExtVectorDecls[I]->getPCHLevel() == 0)
|
|
|
|
AddDeclRef(SemaRef.ExtVectorDecls[I], ExtVectorDecls);
|
|
|
|
}
|
|
|
|
|
2010-08-06 02:21:25 +08:00
|
|
|
// Build a record containing all of the VTable uses information.
|
|
|
|
// We write everything here, because it's too hard to determine whether
|
|
|
|
// a use is new to this part.
|
|
|
|
RecordData VTableUses;
|
|
|
|
if (!SemaRef.VTableUses.empty()) {
|
|
|
|
VTableUses.push_back(SemaRef.VTableUses.size());
|
|
|
|
for (unsigned I = 0, N = SemaRef.VTableUses.size(); I != N; ++I) {
|
|
|
|
AddDeclRef(SemaRef.VTableUses[I].first, VTableUses);
|
|
|
|
AddSourceLocation(SemaRef.VTableUses[I].second, VTableUses);
|
|
|
|
VTableUses.push_back(SemaRef.VTablesUsed[SemaRef.VTableUses[I].first]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Build a record containing all of dynamic classes declarations.
|
|
|
|
RecordData DynamicClasses;
|
|
|
|
for (unsigned I = 0, N = SemaRef.DynamicClasses.size(); I != N; ++I)
|
|
|
|
if (SemaRef.DynamicClasses[I]->getPCHLevel() == 0)
|
|
|
|
AddDeclRef(SemaRef.DynamicClasses[I], DynamicClasses);
|
|
|
|
|
|
|
|
// Build a record containing all of pending implicit instantiations.
|
2010-08-25 16:44:16 +08:00
|
|
|
RecordData PendingInstantiations;
|
2010-08-06 02:21:25 +08:00
|
|
|
for (std::deque<Sema::PendingImplicitInstantiation>::iterator
|
2010-08-25 16:44:16 +08:00
|
|
|
I = SemaRef.PendingInstantiations.begin(),
|
|
|
|
N = SemaRef.PendingInstantiations.end(); I != N; ++I) {
|
2010-08-06 02:21:25 +08:00
|
|
|
if (I->first->getPCHLevel() == 0) {
|
2010-08-25 16:44:16 +08:00
|
|
|
AddDeclRef(I->first, PendingInstantiations);
|
|
|
|
AddSourceLocation(I->second, PendingInstantiations);
|
2010-08-06 02:21:25 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
assert(SemaRef.PendingLocalImplicitInstantiations.empty() &&
|
|
|
|
"There are local ones at end of translation unit!");
|
|
|
|
|
|
|
|
// Build a record containing some declaration references.
|
|
|
|
// It's not worth the effort to avoid duplication here.
|
|
|
|
RecordData SemaDeclRefs;
|
|
|
|
if (SemaRef.StdNamespace || SemaRef.StdBadAlloc) {
|
|
|
|
AddDeclRef(SemaRef.getStdNamespace(), SemaDeclRefs);
|
|
|
|
AddDeclRef(SemaRef.getStdBadAlloc(), SemaDeclRefs);
|
|
|
|
}
|
|
|
|
|
2010-08-19 07:57:32 +08:00
|
|
|
Stream.EnterSubblock(DECLTYPES_BLOCK_ID, 3);
|
2010-07-13 06:02:52 +08:00
|
|
|
WriteDeclsBlockAbbrevs();
|
|
|
|
while (!DeclTypesToEmit.empty()) {
|
|
|
|
DeclOrType DOT = DeclTypesToEmit.front();
|
|
|
|
DeclTypesToEmit.pop();
|
|
|
|
if (DOT.isType())
|
|
|
|
WriteType(DOT.getType());
|
|
|
|
else
|
|
|
|
WriteDecl(Context, DOT.getDecl());
|
|
|
|
}
|
|
|
|
Stream.ExitBlock();
|
|
|
|
|
2010-07-28 07:01:28 +08:00
|
|
|
WritePreprocessor(PP);
|
2010-08-05 06:21:29 +08:00
|
|
|
WriteSelectors(SemaRef);
|
|
|
|
WriteReferencedSelectorsPool(SemaRef);
|
2010-07-24 07:49:55 +08:00
|
|
|
WriteIdentifierTable(PP);
|
2010-07-17 00:36:56 +08:00
|
|
|
WriteTypeDeclOffsets();
|
2010-07-28 07:01:28 +08:00
|
|
|
|
2010-08-04 01:30:10 +08:00
|
|
|
/// Build a record containing first declarations from a chained PCH and the
|
2010-08-19 07:56:27 +08:00
|
|
|
/// most recent declarations in this AST that they point to.
|
2010-08-04 01:30:10 +08:00
|
|
|
RecordData FirstLatestDeclIDs;
|
|
|
|
for (FirstLatestDeclMap::iterator
|
|
|
|
I = FirstLatestDecls.begin(), E = FirstLatestDecls.end(); I != E; ++I) {
|
|
|
|
assert(I->first->getPCHLevel() > I->second->getPCHLevel() &&
|
|
|
|
"Expected first & second to be in different PCHs");
|
|
|
|
AddDeclRef(I->first, FirstLatestDeclIDs);
|
|
|
|
AddDeclRef(I->second, FirstLatestDeclIDs);
|
|
|
|
}
|
|
|
|
if (!FirstLatestDeclIDs.empty())
|
2010-08-19 07:57:32 +08:00
|
|
|
Stream.EmitRecord(REDECLS_UPDATE_LATEST, FirstLatestDeclIDs);
|
2010-08-04 01:30:10 +08:00
|
|
|
|
2010-07-28 07:01:28 +08:00
|
|
|
// Write the record containing external, unnamed definitions.
|
|
|
|
if (!ExternalDefinitions.empty())
|
2010-08-19 07:57:32 +08:00
|
|
|
Stream.EmitRecord(EXTERNAL_DEFINITIONS, ExternalDefinitions);
|
2010-07-28 07:01:28 +08:00
|
|
|
|
|
|
|
// Write the record containing tentative definitions.
|
|
|
|
if (!TentativeDefinitions.empty())
|
2010-08-19 07:57:32 +08:00
|
|
|
Stream.EmitRecord(TENTATIVE_DEFINITIONS, TentativeDefinitions);
|
2010-07-28 07:01:28 +08:00
|
|
|
|
2010-08-14 02:42:17 +08:00
|
|
|
// Write the record containing unused file scoped decls.
|
|
|
|
if (!UnusedFileScopedDecls.empty())
|
2010-08-19 07:57:32 +08:00
|
|
|
Stream.EmitRecord(UNUSED_FILESCOPED_DECLS, UnusedFileScopedDecls);
|
2010-07-28 07:01:28 +08:00
|
|
|
|
2010-08-06 02:21:25 +08:00
|
|
|
// Write the record containing weak undeclared identifiers.
|
|
|
|
if (!WeakUndeclaredIdentifiers.empty())
|
2010-08-19 07:57:32 +08:00
|
|
|
Stream.EmitRecord(WEAK_UNDECLARED_IDENTIFIERS,
|
2010-08-06 02:21:25 +08:00
|
|
|
WeakUndeclaredIdentifiers);
|
|
|
|
|
2010-07-28 07:01:28 +08:00
|
|
|
// Write the record containing locally-scoped external definitions.
|
|
|
|
if (!LocallyScopedExternalDecls.empty())
|
2010-08-19 07:57:32 +08:00
|
|
|
Stream.EmitRecord(LOCALLY_SCOPED_EXTERNAL_DECLS,
|
2010-07-28 07:01:28 +08:00
|
|
|
LocallyScopedExternalDecls);
|
|
|
|
|
|
|
|
// Write the record containing ext_vector type names.
|
|
|
|
if (!ExtVectorDecls.empty())
|
2010-08-19 07:57:32 +08:00
|
|
|
Stream.EmitRecord(EXT_VECTOR_DECLS, ExtVectorDecls);
|
2010-07-28 07:01:28 +08:00
|
|
|
|
2010-08-06 02:21:25 +08:00
|
|
|
// Write the record containing VTable uses information.
|
|
|
|
if (!VTableUses.empty())
|
2010-08-19 07:57:32 +08:00
|
|
|
Stream.EmitRecord(VTABLE_USES, VTableUses);
|
2010-08-06 02:21:25 +08:00
|
|
|
|
|
|
|
// Write the record containing dynamic classes declarations.
|
|
|
|
if (!DynamicClasses.empty())
|
2010-08-19 07:57:32 +08:00
|
|
|
Stream.EmitRecord(DYNAMIC_CLASSES, DynamicClasses);
|
2010-08-06 02:21:25 +08:00
|
|
|
|
|
|
|
// Write the record containing pending implicit instantiations.
|
2010-08-25 16:44:16 +08:00
|
|
|
if (!PendingInstantiations.empty())
|
|
|
|
Stream.EmitRecord(PENDING_IMPLICIT_INSTANTIATIONS, PendingInstantiations);
|
2010-08-06 02:21:25 +08:00
|
|
|
|
|
|
|
// Write the record containing declaration references of Sema.
|
|
|
|
if (!SemaDeclRefs.empty())
|
2010-08-19 07:57:32 +08:00
|
|
|
Stream.EmitRecord(SEMA_DECL_REFS, SemaDeclRefs);
|
2010-07-28 07:01:28 +08:00
|
|
|
|
2010-08-24 08:50:09 +08:00
|
|
|
// Write the updates to C++ namespaces.
|
|
|
|
for (llvm::SmallPtrSet<const NamespaceDecl *, 16>::iterator
|
|
|
|
I = UpdatedNamespaces.begin(),
|
|
|
|
E = UpdatedNamespaces.end();
|
|
|
|
I != E; ++I)
|
|
|
|
WriteDeclContextVisibleUpdate(*I);
|
|
|
|
|
2010-08-25 06:50:24 +08:00
|
|
|
// Write the updates to C++ template specialization lists.
|
|
|
|
if (!AdditionalTemplateSpecializations.empty())
|
|
|
|
WriteAdditionalTemplateSpecializations();
|
|
|
|
|
2010-07-28 07:01:28 +08:00
|
|
|
Record.clear();
|
|
|
|
Record.push_back(NumStatements);
|
|
|
|
Record.push_back(NumMacros);
|
|
|
|
Record.push_back(NumLexicalDeclContexts);
|
|
|
|
Record.push_back(NumVisibleDeclContexts);
|
2010-08-13 08:28:03 +08:00
|
|
|
WriteDeclUpdateBlock();
|
2010-08-19 07:57:32 +08:00
|
|
|
Stream.EmitRecord(STATISTICS, Record);
|
2010-07-13 06:02:52 +08:00
|
|
|
Stream.ExitBlock();
|
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:21 +08:00
|
|
|
void ASTWriter::WriteDeclUpdateBlock() {
|
2010-08-13 08:28:03 +08:00
|
|
|
if (ReplacedDecls.empty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
RecordData Record;
|
2010-08-19 07:57:32 +08:00
|
|
|
for (llvm::SmallVector<std::pair<DeclID, uint64_t>, 16>::iterator
|
2010-08-13 08:28:03 +08:00
|
|
|
I = ReplacedDecls.begin(), E = ReplacedDecls.end(); I != E; ++I) {
|
|
|
|
Record.push_back(I->first);
|
|
|
|
Record.push_back(I->second);
|
|
|
|
}
|
2010-08-19 07:57:32 +08:00
|
|
|
Stream.EmitRecord(DECL_REPLACEMENTS, Record);
|
2010-08-13 08:28:03 +08:00
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:21 +08:00
|
|
|
void ASTWriter::AddSourceLocation(SourceLocation Loc, RecordData &Record) {
|
2009-04-10 06:27:44 +08:00
|
|
|
Record.push_back(Loc.getRawEncoding());
|
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:21 +08:00
|
|
|
void ASTWriter::AddSourceRange(SourceRange Range, RecordData &Record) {
|
2010-05-08 05:43:38 +08:00
|
|
|
AddSourceLocation(Range.getBegin(), Record);
|
|
|
|
AddSourceLocation(Range.getEnd(), Record);
|
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:21 +08:00
|
|
|
void ASTWriter::AddAPInt(const llvm::APInt &Value, RecordData &Record) {
|
2009-04-10 06:27:44 +08:00
|
|
|
Record.push_back(Value.getBitWidth());
|
2010-09-07 07:43:28 +08:00
|
|
|
const uint64_t *Words = Value.getRawData();
|
|
|
|
Record.append(Words, Words + Value.getNumWords());
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:21 +08:00
|
|
|
void ASTWriter::AddAPSInt(const llvm::APSInt &Value, RecordData &Record) {
|
2009-04-14 02:14:40 +08:00
|
|
|
Record.push_back(Value.isUnsigned());
|
|
|
|
AddAPInt(Value, Record);
|
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:21 +08:00
|
|
|
void ASTWriter::AddAPFloat(const llvm::APFloat &Value, RecordData &Record) {
|
2009-04-15 05:55:33 +08:00
|
|
|
AddAPInt(Value.bitcastToAPInt(), Record);
|
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:21 +08:00
|
|
|
void ASTWriter::AddIdentifierRef(const IdentifierInfo *II, RecordData &Record) {
|
2009-04-23 02:49:13 +08:00
|
|
|
Record.push_back(getIdentifierRef(II));
|
|
|
|
}
|
|
|
|
|
2010-08-19 07:57:32 +08:00
|
|
|
IdentID ASTWriter::getIdentifierRef(const IdentifierInfo *II) {
|
2009-04-23 02:49:13 +08:00
|
|
|
if (II == 0)
|
|
|
|
return 0;
|
2009-04-11 08:14:32 +08:00
|
|
|
|
2010-08-19 07:57:32 +08:00
|
|
|
IdentID &ID = IdentifierIDs[II];
|
2009-04-11 08:14:32 +08:00
|
|
|
if (ID == 0)
|
2010-07-24 07:49:55 +08:00
|
|
|
ID = NextIdentID++;
|
2009-04-23 02:49:13 +08:00
|
|
|
return ID;
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
|
|
|
|
2010-09-16 03:54:06 +08:00
|
|
|
MacroID ASTWriter::getMacroDefinitionID(MacroDefinition *MD) {
|
Implement serialization and lazy deserialization of the preprocessing
record (which includes all macro instantiations and definitions). As
with all lay deserialization, this introduces a new external source
(here, an external preprocessing record source) that loads all of the
preprocessed entities prior to iterating over the entities.
The preprocessing record is an optional part of the precompiled header
that is disabled by default (enabled with
-detailed-preprocessing-record). When the preprocessor given to the
PCH writer has a preprocessing record, that record is written into the
PCH file. When the PCH reader is given a PCH file that contains a
preprocessing record, it will be lazily loaded (which, effectively,
implicitly adds -detailed-preprocessing-record). This is the first
case where we have sections of the precompiled header that are
added/removed based on a compilation flag, which is
unfortunate. However, this data consumes ~550k in the PCH file for
Cocoa.h (out of ~9.9MB), and there is a non-trivial cost to gathering
this detailed preprocessing information, so it's too expensive to turn
on by default. In the future, we should investigate a better encoding
of this information.
llvm-svn: 99002
2010-03-20 05:51:54 +08:00
|
|
|
if (MD == 0)
|
|
|
|
return 0;
|
2010-09-16 03:54:06 +08:00
|
|
|
|
|
|
|
MacroID &ID = MacroDefinitions[MD];
|
Implement serialization and lazy deserialization of the preprocessing
record (which includes all macro instantiations and definitions). As
with all lay deserialization, this introduces a new external source
(here, an external preprocessing record source) that loads all of the
preprocessed entities prior to iterating over the entities.
The preprocessing record is an optional part of the precompiled header
that is disabled by default (enabled with
-detailed-preprocessing-record). When the preprocessor given to the
PCH writer has a preprocessing record, that record is written into the
PCH file. When the PCH reader is given a PCH file that contains a
preprocessing record, it will be lazily loaded (which, effectively,
implicitly adds -detailed-preprocessing-record). This is the first
case where we have sections of the precompiled header that are
added/removed based on a compilation flag, which is
unfortunate. However, this data consumes ~550k in the PCH file for
Cocoa.h (out of ~9.9MB), and there is a non-trivial cost to gathering
this detailed preprocessing information, so it's too expensive to turn
on by default. In the future, we should investigate a better encoding
of this information.
llvm-svn: 99002
2010-03-20 05:51:54 +08:00
|
|
|
if (ID == 0)
|
2010-10-03 03:29:26 +08:00
|
|
|
ID = NextMacroID++;
|
Implement serialization and lazy deserialization of the preprocessing
record (which includes all macro instantiations and definitions). As
with all lay deserialization, this introduces a new external source
(here, an external preprocessing record source) that loads all of the
preprocessed entities prior to iterating over the entities.
The preprocessing record is an optional part of the precompiled header
that is disabled by default (enabled with
-detailed-preprocessing-record). When the preprocessor given to the
PCH writer has a preprocessing record, that record is written into the
PCH file. When the PCH reader is given a PCH file that contains a
preprocessing record, it will be lazily loaded (which, effectively,
implicitly adds -detailed-preprocessing-record). This is the first
case where we have sections of the precompiled header that are
added/removed based on a compilation flag, which is
unfortunate. However, this data consumes ~550k in the PCH file for
Cocoa.h (out of ~9.9MB), and there is a non-trivial cost to gathering
this detailed preprocessing information, so it's too expensive to turn
on by default. In the future, we should investigate a better encoding
of this information.
llvm-svn: 99002
2010-03-20 05:51:54 +08:00
|
|
|
return ID;
|
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:21 +08:00
|
|
|
void ASTWriter::AddSelectorRef(const Selector SelRef, RecordData &Record) {
|
2010-08-05 01:20:04 +08:00
|
|
|
Record.push_back(getSelectorRef(SelRef));
|
|
|
|
}
|
|
|
|
|
2010-08-19 07:57:32 +08:00
|
|
|
SelectorID ASTWriter::getSelectorRef(Selector Sel) {
|
2010-08-05 01:20:04 +08:00
|
|
|
if (Sel.getAsOpaquePtr() == 0) {
|
|
|
|
return 0;
|
2009-04-23 18:39:46 +08:00
|
|
|
}
|
|
|
|
|
2010-08-19 07:57:32 +08:00
|
|
|
SelectorID &SID = SelectorIDs[Sel];
|
2010-08-05 02:21:41 +08:00
|
|
|
if (SID == 0 && Chain) {
|
|
|
|
// This might trigger a ReadSelector callback, which will set the ID for
|
|
|
|
// this selector.
|
|
|
|
Chain->LoadSelector(Sel);
|
|
|
|
}
|
2009-04-23 18:39:46 +08:00
|
|
|
if (SID == 0) {
|
2010-08-05 02:21:41 +08:00
|
|
|
SID = NextSelectorID++;
|
2009-04-23 18:39:46 +08:00
|
|
|
}
|
2010-08-05 01:20:04 +08:00
|
|
|
return SID;
|
2009-04-23 18:39:46 +08:00
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:21 +08:00
|
|
|
void ASTWriter::AddCXXTemporary(const CXXTemporary *Temp, RecordData &Record) {
|
2010-05-10 08:25:06 +08:00
|
|
|
AddDeclRef(Temp->getDestructor(), Record);
|
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:21 +08:00
|
|
|
void ASTWriter::AddTemplateArgumentLocInfo(TemplateArgument::ArgKind Kind,
|
2010-06-22 17:54:59 +08:00
|
|
|
const TemplateArgumentLocInfo &Arg,
|
|
|
|
RecordData &Record) {
|
|
|
|
switch (Kind) {
|
2009-10-29 16:12:44 +08:00
|
|
|
case TemplateArgument::Expression:
|
2010-06-22 17:54:59 +08:00
|
|
|
AddStmt(Arg.getAsExpr());
|
2009-10-29 16:12:44 +08:00
|
|
|
break;
|
|
|
|
case TemplateArgument::Type:
|
2010-06-22 17:54:59 +08:00
|
|
|
AddTypeSourceInfo(Arg.getAsTypeSourceInfo(), Record);
|
2009-10-29 16:12:44 +08:00
|
|
|
break;
|
2009-11-11 09:00:40 +08:00
|
|
|
case TemplateArgument::Template:
|
2010-06-28 17:31:42 +08:00
|
|
|
AddSourceRange(Arg.getTemplateQualifierRange(), Record);
|
|
|
|
AddSourceLocation(Arg.getTemplateNameLoc(), Record);
|
2009-11-11 09:00:40 +08:00
|
|
|
break;
|
2009-10-29 16:12:44 +08:00
|
|
|
case TemplateArgument::Null:
|
|
|
|
case TemplateArgument::Integral:
|
|
|
|
case TemplateArgument::Declaration:
|
|
|
|
case TemplateArgument::Pack:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:21 +08:00
|
|
|
void ASTWriter::AddTemplateArgumentLoc(const TemplateArgumentLoc &Arg,
|
2010-06-22 17:54:59 +08:00
|
|
|
RecordData &Record) {
|
|
|
|
AddTemplateArgument(Arg.getArgument(), Record);
|
2010-06-28 17:31:42 +08:00
|
|
|
|
|
|
|
if (Arg.getArgument().getKind() == TemplateArgument::Expression) {
|
|
|
|
bool InfoHasSameExpr
|
|
|
|
= Arg.getArgument().getAsExpr() == Arg.getLocInfo().getAsExpr();
|
|
|
|
Record.push_back(InfoHasSameExpr);
|
|
|
|
if (InfoHasSameExpr)
|
|
|
|
return; // Avoid storing the same expr twice.
|
|
|
|
}
|
2010-06-22 17:54:59 +08:00
|
|
|
AddTemplateArgumentLocInfo(Arg.getArgument().getKind(), Arg.getLocInfo(),
|
|
|
|
Record);
|
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:21 +08:00
|
|
|
void ASTWriter::AddTypeSourceInfo(TypeSourceInfo *TInfo, RecordData &Record) {
|
2009-12-07 10:54:59 +08:00
|
|
|
if (TInfo == 0) {
|
2009-10-17 05:56:05 +08:00
|
|
|
AddTypeRef(QualType(), Record);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-12-07 10:54:59 +08:00
|
|
|
AddTypeRef(TInfo->getType(), Record);
|
2009-10-17 05:56:05 +08:00
|
|
|
TypeLocWriter TLW(*this, Record);
|
2009-12-07 10:54:59 +08:00
|
|
|
for (TypeLoc TL = TInfo->getTypeLoc(); !TL.isNull(); TL = TL.getNextTypeLoc())
|
2010-03-14 15:06:50 +08:00
|
|
|
TLW.Visit(TL);
|
2009-10-17 05:56:05 +08:00
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:21 +08:00
|
|
|
void ASTWriter::AddTypeRef(QualType T, RecordData &Record) {
|
2010-08-21 00:04:14 +08:00
|
|
|
Record.push_back(GetOrCreateTypeID(T));
|
|
|
|
}
|
|
|
|
|
|
|
|
TypeID ASTWriter::GetOrCreateTypeID(QualType T) {
|
2010-08-21 00:04:20 +08:00
|
|
|
return MakeTypeID(T,
|
|
|
|
std::bind1st(std::mem_fun(&ASTWriter::GetOrCreateTypeIdx), this));
|
|
|
|
}
|
2009-04-10 06:27:44 +08:00
|
|
|
|
2010-08-21 00:04:27 +08:00
|
|
|
TypeID ASTWriter::getTypeID(QualType T) const {
|
2010-08-21 00:04:20 +08:00
|
|
|
return MakeTypeID(T,
|
|
|
|
std::bind1st(std::mem_fun(&ASTWriter::getTypeIdx), this));
|
2010-08-21 00:04:09 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
TypeIdx ASTWriter::GetOrCreateTypeIdx(QualType T) {
|
|
|
|
if (T.isNull())
|
|
|
|
return TypeIdx();
|
|
|
|
assert(!T.getLocalFastQualifiers());
|
|
|
|
|
2010-08-21 00:04:04 +08:00
|
|
|
TypeIdx &Idx = TypeIdxs[T];
|
2010-08-21 00:03:59 +08:00
|
|
|
if (Idx.getIndex() == 0) {
|
2009-04-26 11:49:13 +08:00
|
|
|
// We haven't seen this type before. Assign it a new ID and put it
|
2009-09-25 03:53:00 +08:00
|
|
|
// into the queue of types to emit.
|
2010-08-21 00:03:59 +08:00
|
|
|
Idx = TypeIdx(NextTypeID++);
|
2009-10-17 08:13:19 +08:00
|
|
|
DeclTypesToEmit.push(T);
|
2009-04-26 11:49:13 +08:00
|
|
|
}
|
2010-08-21 00:04:09 +08:00
|
|
|
return Idx;
|
|
|
|
}
|
2009-04-10 06:27:44 +08:00
|
|
|
|
2010-08-21 00:04:27 +08:00
|
|
|
TypeIdx ASTWriter::getTypeIdx(QualType T) const {
|
2010-08-21 00:04:09 +08:00
|
|
|
if (T.isNull())
|
|
|
|
return TypeIdx();
|
|
|
|
assert(!T.getLocalFastQualifiers());
|
|
|
|
|
2010-08-21 00:04:27 +08:00
|
|
|
TypeIdxMap::const_iterator I = TypeIdxs.find(T);
|
|
|
|
assert(I != TypeIdxs.end() && "Type not emitted!");
|
|
|
|
return I->second;
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:21 +08:00
|
|
|
void ASTWriter::AddDeclRef(const Decl *D, RecordData &Record) {
|
2010-07-27 08:17:23 +08:00
|
|
|
Record.push_back(GetDeclRef(D));
|
|
|
|
}
|
|
|
|
|
2010-08-19 07:57:32 +08:00
|
|
|
DeclID ASTWriter::GetDeclRef(const Decl *D) {
|
2009-04-10 06:27:44 +08:00
|
|
|
if (D == 0) {
|
2010-07-27 08:17:23 +08:00
|
|
|
return 0;
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
2010-10-06 02:37:06 +08:00
|
|
|
assert(!(reinterpret_cast<uintptr_t>(D) & 0x01) && "Invalid decl pointer");
|
2010-08-19 07:57:32 +08:00
|
|
|
DeclID &ID = DeclIDs[D];
|
2009-09-09 23:08:12 +08:00
|
|
|
if (ID == 0) {
|
2009-04-10 06:27:44 +08:00
|
|
|
// We haven't seen this declaration before. Give it a new ID and
|
|
|
|
// enqueue it in the list of declarations to emit.
|
2010-07-24 07:49:55 +08:00
|
|
|
ID = NextDeclID++;
|
2009-10-17 08:13:19 +08:00
|
|
|
DeclTypesToEmit.push(const_cast<Decl *>(D));
|
2010-08-13 08:28:03 +08:00
|
|
|
} else if (ID < FirstDeclID && D->isChangedSinceDeserialization()) {
|
|
|
|
// We don't add it to the replacement collection here, because we don't
|
|
|
|
// have the offset yet.
|
|
|
|
DeclTypesToEmit.push(const_cast<Decl *>(D));
|
|
|
|
// Reset the flag, so that we don't add this decl multiple times.
|
|
|
|
const_cast<Decl *>(D)->setChangedSinceDeserialization(false);
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
|
|
|
|
2010-07-27 08:17:23 +08:00
|
|
|
return ID;
|
2009-04-10 06:27:44 +08:00
|
|
|
}
|
|
|
|
|
2010-08-19 07:57:32 +08:00
|
|
|
DeclID ASTWriter::getDeclID(const Decl *D) {
|
2009-04-21 04:36:09 +08:00
|
|
|
if (D == 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
assert(DeclIDs.find(D) != DeclIDs.end() && "Declaration not emitted!");
|
|
|
|
return DeclIDs[D];
|
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:21 +08:00
|
|
|
void ASTWriter::AddDeclarationName(DeclarationName Name, RecordData &Record) {
|
2009-04-27 15:35:58 +08:00
|
|
|
// FIXME: Emit a stable enum for NameKind. 0 = Identifier etc.
|
2009-04-10 06:27:44 +08:00
|
|
|
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;
|
|
|
|
|
2009-11-29 15:34:05 +08:00
|
|
|
case DeclarationName::CXXLiteralOperatorName:
|
|
|
|
AddIdentifierRef(Name.getCXXLiteralIdentifier(), Record);
|
|
|
|
break;
|
|
|
|
|
2009-04-10 06:27:44 +08:00
|
|
|
case DeclarationName::CXXUsingDirective:
|
|
|
|
// No extra data to emit
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2010-05-08 05:43:38 +08:00
|
|
|
|
2010-10-16 02:21:24 +08:00
|
|
|
void ASTWriter::AddDeclarationNameLoc(const DeclarationNameLoc &DNLoc,
|
|
|
|
DeclarationName Name, RecordData &Record) {
|
|
|
|
switch (Name.getNameKind()) {
|
|
|
|
case DeclarationName::CXXConstructorName:
|
|
|
|
case DeclarationName::CXXDestructorName:
|
|
|
|
case DeclarationName::CXXConversionFunctionName:
|
|
|
|
AddTypeSourceInfo(DNLoc.NamedType.TInfo, Record);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DeclarationName::CXXOperatorName:
|
|
|
|
AddSourceLocation(
|
|
|
|
SourceLocation::getFromRawEncoding(DNLoc.CXXOperatorName.BeginOpNameLoc),
|
|
|
|
Record);
|
|
|
|
AddSourceLocation(
|
|
|
|
SourceLocation::getFromRawEncoding(DNLoc.CXXOperatorName.EndOpNameLoc),
|
|
|
|
Record);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DeclarationName::CXXLiteralOperatorName:
|
|
|
|
AddSourceLocation(
|
|
|
|
SourceLocation::getFromRawEncoding(DNLoc.CXXLiteralOperatorName.OpNameLoc),
|
|
|
|
Record);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DeclarationName::Identifier:
|
|
|
|
case DeclarationName::ObjCZeroArgSelector:
|
|
|
|
case DeclarationName::ObjCOneArgSelector:
|
|
|
|
case DeclarationName::ObjCMultiArgSelector:
|
|
|
|
case DeclarationName::CXXUsingDirective:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ASTWriter::AddDeclarationNameInfo(const DeclarationNameInfo &NameInfo,
|
|
|
|
RecordData &Record) {
|
|
|
|
AddDeclarationName(NameInfo.getName(), Record);
|
|
|
|
AddSourceLocation(NameInfo.getLoc(), Record);
|
|
|
|
AddDeclarationNameLoc(NameInfo.getInfo(), NameInfo.getName(), Record);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ASTWriter::AddQualifierInfo(const QualifierInfo &Info,
|
|
|
|
RecordData &Record) {
|
|
|
|
AddNestedNameSpecifier(Info.NNS, Record);
|
|
|
|
AddSourceRange(Info.NNSRange, Record);
|
|
|
|
Record.push_back(Info.NumTemplParamLists);
|
|
|
|
for (unsigned i=0, e=Info.NumTemplParamLists; i != e; ++i)
|
|
|
|
AddTemplateParameterList(Info.TemplParamLists[i], Record);
|
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:21 +08:00
|
|
|
void ASTWriter::AddNestedNameSpecifier(NestedNameSpecifier *NNS,
|
2010-05-08 05:43:38 +08:00
|
|
|
RecordData &Record) {
|
|
|
|
// Nested name specifiers usually aren't too long. I think that 8 would
|
|
|
|
// typically accomodate the vast majority.
|
|
|
|
llvm::SmallVector<NestedNameSpecifier *, 8> NestedNames;
|
|
|
|
|
|
|
|
// Push each of the NNS's onto a stack for serialization in reverse order.
|
|
|
|
while (NNS) {
|
|
|
|
NestedNames.push_back(NNS);
|
|
|
|
NNS = NNS->getPrefix();
|
|
|
|
}
|
|
|
|
|
|
|
|
Record.push_back(NestedNames.size());
|
|
|
|
while(!NestedNames.empty()) {
|
|
|
|
NNS = NestedNames.pop_back_val();
|
|
|
|
NestedNameSpecifier::SpecifierKind Kind = NNS->getKind();
|
|
|
|
Record.push_back(Kind);
|
|
|
|
switch (Kind) {
|
|
|
|
case NestedNameSpecifier::Identifier:
|
|
|
|
AddIdentifierRef(NNS->getAsIdentifier(), Record);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NestedNameSpecifier::Namespace:
|
|
|
|
AddDeclRef(NNS->getAsNamespace(), Record);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NestedNameSpecifier::TypeSpec:
|
|
|
|
case NestedNameSpecifier::TypeSpecWithTemplate:
|
|
|
|
AddTypeRef(QualType(NNS->getAsType(), 0), Record);
|
|
|
|
Record.push_back(Kind == NestedNameSpecifier::TypeSpecWithTemplate);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NestedNameSpecifier::Global:
|
|
|
|
// Don't need to write an associated value.
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2010-06-20 03:28:53 +08:00
|
|
|
|
2010-08-19 07:56:21 +08:00
|
|
|
void ASTWriter::AddTemplateName(TemplateName Name, RecordData &Record) {
|
2010-06-20 03:28:53 +08:00
|
|
|
TemplateName::NameKind Kind = Name.getKind();
|
|
|
|
Record.push_back(Kind);
|
|
|
|
switch (Kind) {
|
|
|
|
case TemplateName::Template:
|
|
|
|
AddDeclRef(Name.getAsTemplateDecl(), Record);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case TemplateName::OverloadedTemplate: {
|
|
|
|
OverloadedTemplateStorage *OvT = Name.getAsOverloadedTemplate();
|
|
|
|
Record.push_back(OvT->size());
|
|
|
|
for (OverloadedTemplateStorage::iterator I = OvT->begin(), E = OvT->end();
|
|
|
|
I != E; ++I)
|
|
|
|
AddDeclRef(*I, Record);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case TemplateName::QualifiedTemplate: {
|
|
|
|
QualifiedTemplateName *QualT = Name.getAsQualifiedTemplateName();
|
|
|
|
AddNestedNameSpecifier(QualT->getQualifier(), Record);
|
|
|
|
Record.push_back(QualT->hasTemplateKeyword());
|
|
|
|
AddDeclRef(QualT->getTemplateDecl(), Record);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case TemplateName::DependentTemplate: {
|
|
|
|
DependentTemplateName *DepT = Name.getAsDependentTemplateName();
|
|
|
|
AddNestedNameSpecifier(DepT->getQualifier(), Record);
|
|
|
|
Record.push_back(DepT->isIdentifier());
|
|
|
|
if (DepT->isIdentifier())
|
|
|
|
AddIdentifierRef(DepT->getIdentifier(), Record);
|
|
|
|
else
|
|
|
|
Record.push_back(DepT->getOperator());
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:21 +08:00
|
|
|
void ASTWriter::AddTemplateArgument(const TemplateArgument &Arg,
|
2010-06-20 03:28:53 +08:00
|
|
|
RecordData &Record) {
|
|
|
|
Record.push_back(Arg.getKind());
|
|
|
|
switch (Arg.getKind()) {
|
|
|
|
case TemplateArgument::Null:
|
|
|
|
break;
|
|
|
|
case TemplateArgument::Type:
|
|
|
|
AddTypeRef(Arg.getAsType(), Record);
|
|
|
|
break;
|
|
|
|
case TemplateArgument::Declaration:
|
|
|
|
AddDeclRef(Arg.getAsDecl(), Record);
|
|
|
|
break;
|
|
|
|
case TemplateArgument::Integral:
|
|
|
|
AddAPSInt(*Arg.getAsIntegral(), Record);
|
|
|
|
AddTypeRef(Arg.getIntegralType(), Record);
|
|
|
|
break;
|
|
|
|
case TemplateArgument::Template:
|
|
|
|
AddTemplateName(Arg.getAsTemplate(), Record);
|
|
|
|
break;
|
|
|
|
case TemplateArgument::Expression:
|
|
|
|
AddStmt(Arg.getAsExpr());
|
|
|
|
break;
|
|
|
|
case TemplateArgument::Pack:
|
|
|
|
Record.push_back(Arg.pack_size());
|
|
|
|
for (TemplateArgument::pack_iterator I=Arg.pack_begin(), E=Arg.pack_end();
|
|
|
|
I != E; ++I)
|
|
|
|
AddTemplateArgument(*I, Record);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2010-06-23 21:48:30 +08:00
|
|
|
|
|
|
|
void
|
2010-08-19 07:56:21 +08:00
|
|
|
ASTWriter::AddTemplateParameterList(const TemplateParameterList *TemplateParams,
|
2010-06-23 21:48:30 +08:00
|
|
|
RecordData &Record) {
|
|
|
|
assert(TemplateParams && "No TemplateParams!");
|
|
|
|
AddSourceLocation(TemplateParams->getTemplateLoc(), Record);
|
|
|
|
AddSourceLocation(TemplateParams->getLAngleLoc(), Record);
|
|
|
|
AddSourceLocation(TemplateParams->getRAngleLoc(), Record);
|
|
|
|
Record.push_back(TemplateParams->size());
|
|
|
|
for (TemplateParameterList::const_iterator
|
|
|
|
P = TemplateParams->begin(), PEnd = TemplateParams->end();
|
|
|
|
P != PEnd; ++P)
|
|
|
|
AddDeclRef(*P, Record);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Emit a template argument list.
|
|
|
|
void
|
2010-08-19 07:56:21 +08:00
|
|
|
ASTWriter::AddTemplateArgumentList(const TemplateArgumentList *TemplateArgs,
|
2010-06-23 21:48:30 +08:00
|
|
|
RecordData &Record) {
|
|
|
|
assert(TemplateArgs && "No TemplateArgs!");
|
|
|
|
Record.push_back(TemplateArgs->flat_size());
|
|
|
|
for (int i=0, e = TemplateArgs->flat_size(); i != e; ++i)
|
|
|
|
AddTemplateArgument(TemplateArgs->get(i), Record);
|
|
|
|
}
|
2010-07-02 19:55:32 +08:00
|
|
|
|
|
|
|
|
|
|
|
void
|
2010-08-19 07:56:21 +08:00
|
|
|
ASTWriter::AddUnresolvedSet(const UnresolvedSetImpl &Set, RecordData &Record) {
|
2010-07-02 19:55:32 +08:00
|
|
|
Record.push_back(Set.size());
|
|
|
|
for (UnresolvedSetImpl::const_iterator
|
|
|
|
I = Set.begin(), E = Set.end(); I != E; ++I) {
|
|
|
|
AddDeclRef(I.getDecl(), Record);
|
|
|
|
Record.push_back(I.getAccess());
|
|
|
|
}
|
|
|
|
}
|
2010-07-03 07:30:27 +08:00
|
|
|
|
2010-08-19 07:56:21 +08:00
|
|
|
void ASTWriter::AddCXXBaseSpecifier(const CXXBaseSpecifier &Base,
|
2010-07-03 07:30:27 +08:00
|
|
|
RecordData &Record) {
|
|
|
|
Record.push_back(Base.isVirtual());
|
|
|
|
Record.push_back(Base.isBaseOfClass());
|
|
|
|
Record.push_back(Base.getAccessSpecifierAsWritten());
|
2010-07-27 00:56:01 +08:00
|
|
|
AddTypeSourceInfo(Base.getTypeSourceInfo(), Record);
|
2010-07-03 07:30:27 +08:00
|
|
|
AddSourceRange(Base.getSourceRange(), Record);
|
|
|
|
}
|
2010-07-15 07:45:08 +08:00
|
|
|
|
2010-08-19 07:56:21 +08:00
|
|
|
void ASTWriter::AddCXXBaseOrMemberInitializers(
|
2010-08-09 18:54:12 +08:00
|
|
|
const CXXBaseOrMemberInitializer * const *BaseOrMembers,
|
|
|
|
unsigned NumBaseOrMembers, RecordData &Record) {
|
|
|
|
Record.push_back(NumBaseOrMembers);
|
|
|
|
for (unsigned i=0; i != NumBaseOrMembers; ++i) {
|
|
|
|
const CXXBaseOrMemberInitializer *Init = BaseOrMembers[i];
|
|
|
|
|
|
|
|
Record.push_back(Init->isBaseInitializer());
|
|
|
|
if (Init->isBaseInitializer()) {
|
|
|
|
AddTypeSourceInfo(Init->getBaseClassInfo(), Record);
|
|
|
|
Record.push_back(Init->isBaseVirtual());
|
|
|
|
} else {
|
|
|
|
AddDeclRef(Init->getMember(), Record);
|
|
|
|
}
|
|
|
|
AddSourceLocation(Init->getMemberLocation(), Record);
|
|
|
|
AddStmt(Init->getInit());
|
|
|
|
AddDeclRef(Init->getAnonUnionMember(), Record);
|
|
|
|
AddSourceLocation(Init->getLParenLoc(), Record);
|
|
|
|
AddSourceLocation(Init->getRParenLoc(), Record);
|
|
|
|
Record.push_back(Init->isWritten());
|
|
|
|
if (Init->isWritten()) {
|
|
|
|
Record.push_back(Init->getSourceOrder());
|
|
|
|
} else {
|
|
|
|
Record.push_back(Init->getNumArrayIndices());
|
|
|
|
for (unsigned i=0, e=Init->getNumArrayIndices(); i != e; ++i)
|
|
|
|
AddDeclRef(Init->getArrayIndex(i), Record);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-08-19 07:56:43 +08:00
|
|
|
void ASTWriter::SetReader(ASTReader *Reader) {
|
2010-07-30 08:29:29 +08:00
|
|
|
assert(Reader && "Cannot remove chain");
|
|
|
|
assert(FirstDeclID == NextDeclID &&
|
|
|
|
FirstTypeID == NextTypeID &&
|
|
|
|
FirstIdentID == NextIdentID &&
|
2010-08-05 02:21:41 +08:00
|
|
|
FirstSelectorID == NextSelectorID &&
|
2010-10-03 03:29:26 +08:00
|
|
|
FirstMacroID == NextMacroID &&
|
2010-07-30 08:29:29 +08:00
|
|
|
"Setting chain after writing has started.");
|
|
|
|
Chain = Reader;
|
|
|
|
}
|
|
|
|
|
2010-08-19 07:57:32 +08:00
|
|
|
void ASTWriter::IdentifierRead(IdentID ID, IdentifierInfo *II) {
|
2010-07-24 07:49:55 +08:00
|
|
|
IdentifierIDs[II] = ID;
|
|
|
|
}
|
|
|
|
|
2010-08-21 00:03:59 +08:00
|
|
|
void ASTWriter::TypeRead(TypeIdx Idx, QualType T) {
|
2010-10-06 02:37:06 +08:00
|
|
|
// Always take the highest-numbered type index. This copes with an interesting
|
|
|
|
// case for chained AST writing where we schedule writing the type and then,
|
|
|
|
// later, deserialize the type from another AST. In this case, we want to
|
|
|
|
// keep the higher-numbered entry so that we can properly write it out to
|
|
|
|
// the AST file.
|
|
|
|
TypeIdx &StoredIdx = TypeIdxs[T];
|
|
|
|
if (Idx.getIndex() >= StoredIdx.getIndex())
|
|
|
|
StoredIdx = Idx;
|
2010-07-15 07:45:08 +08:00
|
|
|
}
|
|
|
|
|
2010-08-19 07:57:32 +08:00
|
|
|
void ASTWriter::DeclRead(DeclID ID, const Decl *D) {
|
2010-07-17 00:36:56 +08:00
|
|
|
DeclIDs[D] = ID;
|
2010-07-15 07:45:08 +08:00
|
|
|
}
|
2010-08-05 01:20:04 +08:00
|
|
|
|
2010-08-19 07:57:32 +08:00
|
|
|
void ASTWriter::SelectorRead(SelectorID ID, Selector S) {
|
2010-08-05 01:20:04 +08:00
|
|
|
SelectorIDs[S] = ID;
|
|
|
|
}
|
2010-10-03 03:29:26 +08:00
|
|
|
|
|
|
|
void ASTWriter::MacroDefinitionRead(serialization::MacroID ID,
|
|
|
|
MacroDefinition *MD) {
|
|
|
|
MacroDefinitions[MD] = ID;
|
|
|
|
}
|