summaryrefslogtreecommitdiffstats
path: root/contrib/llvm/tools/clang/lib/Frontend
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Frontend')
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/ASTConsumers.cpp451
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/ASTMerge.cpp105
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/ASTUnit.cpp461
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/BoostConAction.cpp39
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/CMakeLists.txt53
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/CacheTokens.cpp649
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/CompilerInstance.cpp535
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/CompilerInvocation.cpp1473
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/DeclXML.cpp189
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/DependencyFile.cpp174
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/DiagChecker.cpp301
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/DocumentXML.cpp367
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/FrontendAction.cpp261
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/FrontendActions.cpp194
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/FrontendOptions.cpp31
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/GeneratePCH.cpp83
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/InitHeaderSearch.cpp916
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/InitPreprocessor.cpp606
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/LangStandards.cpp44
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/Makefile15
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/PCHReader.cpp3469
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/PCHReaderDecl.cpp1484
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/PCHReaderStmt.cpp1727
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/PCHWriter.cpp2748
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/PCHWriterDecl.cpp1172
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/PCHWriterStmt.cpp1345
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/PrintParserCallbacks.cpp852
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/PrintPreprocessedOutput.cpp543
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/StmtXML.cpp453
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/TextDiagnosticBuffer.cpp48
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/TextDiagnosticPrinter.cpp957
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/TypeXML.cpp119
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/VerifyDiagnosticsClient.cpp521
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/Warnings.cpp133
34 files changed, 22518 insertions, 0 deletions
diff --git a/contrib/llvm/tools/clang/lib/Frontend/ASTConsumers.cpp b/contrib/llvm/tools/clang/lib/Frontend/ASTConsumers.cpp
new file mode 100644
index 0000000..87b01d4
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Frontend/ASTConsumers.cpp
@@ -0,0 +1,451 @@
+//===--- ASTConsumers.cpp - ASTConsumer implementations -------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// AST Consumer Implementations.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/ASTConsumers.h"
+#include "clang/Frontend/DocumentXML.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/AST/AST.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/RecordLayout.h"
+#include "clang/AST/PrettyPrinter.h"
+#include "llvm/Module.h"
+#include "llvm/Support/Timer.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/System/Path.h"
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+/// ASTPrinter - Pretty-printer and dumper of ASTs
+
+namespace {
+ class ASTPrinter : public ASTConsumer {
+ llvm::raw_ostream &Out;
+ bool Dump;
+
+ public:
+ ASTPrinter(llvm::raw_ostream* o = NULL, bool Dump = false)
+ : Out(o? *o : llvm::errs()), Dump(Dump) { }
+
+ virtual void HandleTranslationUnit(ASTContext &Context) {
+ PrintingPolicy Policy = Context.PrintingPolicy;
+ Policy.Dump = Dump;
+ Context.getTranslationUnitDecl()->print(Out, Policy);
+ }
+ };
+} // end anonymous namespace
+
+ASTConsumer *clang::CreateASTPrinter(llvm::raw_ostream* out) {
+ return new ASTPrinter(out);
+}
+
+//===----------------------------------------------------------------------===//
+/// ASTPrinterXML - XML-printer of ASTs
+
+namespace {
+ class ASTPrinterXML : public ASTConsumer {
+ DocumentXML Doc;
+
+ public:
+ ASTPrinterXML(llvm::raw_ostream& o) : Doc("CLANG_XML", o) {}
+
+ void Initialize(ASTContext &Context) {
+ Doc.initialize(Context);
+ }
+
+ virtual void HandleTranslationUnit(ASTContext &Ctx) {
+ Doc.addSubNode("TranslationUnit");
+ for (DeclContext::decl_iterator
+ D = Ctx.getTranslationUnitDecl()->decls_begin(),
+ DEnd = Ctx.getTranslationUnitDecl()->decls_end();
+ D != DEnd;
+ ++D)
+ Doc.PrintDecl(*D);
+ Doc.toParent();
+ Doc.finalize();
+ }
+ };
+} // end anonymous namespace
+
+
+ASTConsumer *clang::CreateASTPrinterXML(llvm::raw_ostream* out) {
+ return new ASTPrinterXML(out ? *out : llvm::outs());
+}
+
+ASTConsumer *clang::CreateASTDumper() {
+ return new ASTPrinter(0, true);
+}
+
+//===----------------------------------------------------------------------===//
+/// ASTViewer - AST Visualization
+
+namespace {
+ class ASTViewer : public ASTConsumer {
+ ASTContext *Context;
+ public:
+ void Initialize(ASTContext &Context) {
+ this->Context = &Context;
+ }
+
+ virtual void HandleTopLevelDecl(DeclGroupRef D) {
+ for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I)
+ HandleTopLevelSingleDecl(*I);
+ }
+
+ void HandleTopLevelSingleDecl(Decl *D);
+ };
+}
+
+void ASTViewer::HandleTopLevelSingleDecl(Decl *D) {
+ if (isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D)) {
+ D->print(llvm::errs());
+
+ if (Stmt *Body = D->getBody()) {
+ llvm::errs() << '\n';
+ Body->viewAST();
+ llvm::errs() << '\n';
+ }
+ }
+}
+
+
+ASTConsumer *clang::CreateASTViewer() { return new ASTViewer(); }
+
+//===----------------------------------------------------------------------===//
+/// DeclContextPrinter - Decl and DeclContext Visualization
+
+namespace {
+
+class DeclContextPrinter : public ASTConsumer {
+ llvm::raw_ostream& Out;
+public:
+ DeclContextPrinter() : Out(llvm::errs()) {}
+
+ void HandleTranslationUnit(ASTContext &C) {
+ PrintDeclContext(C.getTranslationUnitDecl(), 4);
+ }
+
+ void PrintDeclContext(const DeclContext* DC, unsigned Indentation);
+};
+} // end anonymous namespace
+
+void DeclContextPrinter::PrintDeclContext(const DeclContext* DC,
+ unsigned Indentation) {
+ // Print DeclContext name.
+ switch (DC->getDeclKind()) {
+ case Decl::TranslationUnit:
+ Out << "[translation unit] " << DC;
+ break;
+ case Decl::Namespace: {
+ Out << "[namespace] ";
+ const NamespaceDecl* ND = cast<NamespaceDecl>(DC);
+ Out << ND;
+ break;
+ }
+ case Decl::Enum: {
+ const EnumDecl* ED = cast<EnumDecl>(DC);
+ if (ED->isDefinition())
+ Out << "[enum] ";
+ else
+ Out << "<enum> ";
+ Out << ED;
+ break;
+ }
+ case Decl::Record: {
+ const RecordDecl* RD = cast<RecordDecl>(DC);
+ if (RD->isDefinition())
+ Out << "[struct] ";
+ else
+ Out << "<struct> ";
+ Out << RD;
+ break;
+ }
+ case Decl::CXXRecord: {
+ const CXXRecordDecl* RD = cast<CXXRecordDecl>(DC);
+ if (RD->isDefinition())
+ Out << "[class] ";
+ else
+ Out << "<class> ";
+ Out << RD << ' ' << DC;
+ break;
+ }
+ case Decl::ObjCMethod:
+ Out << "[objc method]";
+ break;
+ case Decl::ObjCInterface:
+ Out << "[objc interface]";
+ break;
+ case Decl::ObjCCategory:
+ Out << "[objc category]";
+ break;
+ case Decl::ObjCProtocol:
+ Out << "[objc protocol]";
+ break;
+ case Decl::ObjCImplementation:
+ Out << "[objc implementation]";
+ break;
+ case Decl::ObjCCategoryImpl:
+ Out << "[objc categoryimpl]";
+ break;
+ case Decl::LinkageSpec:
+ Out << "[linkage spec]";
+ break;
+ case Decl::Block:
+ Out << "[block]";
+ break;
+ case Decl::Function: {
+ const FunctionDecl* FD = cast<FunctionDecl>(DC);
+ if (FD->isThisDeclarationADefinition())
+ Out << "[function] ";
+ else
+ Out << "<function> ";
+ Out << FD;
+ // Print the parameters.
+ Out << "(";
+ bool PrintComma = false;
+ for (FunctionDecl::param_const_iterator I = FD->param_begin(),
+ E = FD->param_end(); I != E; ++I) {
+ if (PrintComma)
+ Out << ", ";
+ else
+ PrintComma = true;
+ Out << *I;
+ }
+ Out << ")";
+ break;
+ }
+ case Decl::CXXMethod: {
+ const CXXMethodDecl* D = cast<CXXMethodDecl>(DC);
+ if (D->isOutOfLine())
+ Out << "[c++ method] ";
+ else if (D->isImplicit())
+ Out << "(c++ method) ";
+ else
+ Out << "<c++ method> ";
+ Out << D;
+ // Print the parameters.
+ Out << "(";
+ bool PrintComma = false;
+ for (FunctionDecl::param_const_iterator I = D->param_begin(),
+ E = D->param_end(); I != E; ++I) {
+ if (PrintComma)
+ Out << ", ";
+ else
+ PrintComma = true;
+ Out << *I;
+ }
+ Out << ")";
+
+ // Check the semantic DeclContext.
+ const DeclContext* SemaDC = D->getDeclContext();
+ const DeclContext* LexicalDC = D->getLexicalDeclContext();
+ if (SemaDC != LexicalDC)
+ Out << " [[" << SemaDC << "]]";
+
+ break;
+ }
+ case Decl::CXXConstructor: {
+ const CXXConstructorDecl* D = cast<CXXConstructorDecl>(DC);
+ if (D->isOutOfLine())
+ Out << "[c++ ctor] ";
+ else if (D->isImplicit())
+ Out << "(c++ ctor) ";
+ else
+ Out << "<c++ ctor> ";
+ Out << D;
+ // Print the parameters.
+ Out << "(";
+ bool PrintComma = false;
+ for (FunctionDecl::param_const_iterator I = D->param_begin(),
+ E = D->param_end(); I != E; ++I) {
+ if (PrintComma)
+ Out << ", ";
+ else
+ PrintComma = true;
+ Out << *I;
+ }
+ Out << ")";
+
+ // Check the semantic DC.
+ const DeclContext* SemaDC = D->getDeclContext();
+ const DeclContext* LexicalDC = D->getLexicalDeclContext();
+ if (SemaDC != LexicalDC)
+ Out << " [[" << SemaDC << "]]";
+ break;
+ }
+ case Decl::CXXDestructor: {
+ const CXXDestructorDecl* D = cast<CXXDestructorDecl>(DC);
+ if (D->isOutOfLine())
+ Out << "[c++ dtor] ";
+ else if (D->isImplicit())
+ Out << "(c++ dtor) ";
+ else
+ Out << "<c++ dtor> ";
+ Out << D;
+ // Check the semantic DC.
+ const DeclContext* SemaDC = D->getDeclContext();
+ const DeclContext* LexicalDC = D->getLexicalDeclContext();
+ if (SemaDC != LexicalDC)
+ Out << " [[" << SemaDC << "]]";
+ break;
+ }
+ case Decl::CXXConversion: {
+ const CXXConversionDecl* D = cast<CXXConversionDecl>(DC);
+ if (D->isOutOfLine())
+ Out << "[c++ conversion] ";
+ else if (D->isImplicit())
+ Out << "(c++ conversion) ";
+ else
+ Out << "<c++ conversion> ";
+ Out << D;
+ // Check the semantic DC.
+ const DeclContext* SemaDC = D->getDeclContext();
+ const DeclContext* LexicalDC = D->getLexicalDeclContext();
+ if (SemaDC != LexicalDC)
+ Out << " [[" << SemaDC << "]]";
+ break;
+ }
+
+ default:
+ assert(0 && "a decl that inherits DeclContext isn't handled");
+ }
+
+ Out << "\n";
+
+ // Print decls in the DeclContext.
+ for (DeclContext::decl_iterator I = DC->decls_begin(), E = DC->decls_end();
+ I != E; ++I) {
+ for (unsigned i = 0; i < Indentation; ++i)
+ Out << " ";
+
+ Decl::Kind DK = I->getKind();
+ switch (DK) {
+ case Decl::Namespace:
+ case Decl::Enum:
+ case Decl::Record:
+ case Decl::CXXRecord:
+ case Decl::ObjCMethod:
+ case Decl::ObjCInterface:
+ case Decl::ObjCCategory:
+ case Decl::ObjCProtocol:
+ case Decl::ObjCImplementation:
+ case Decl::ObjCCategoryImpl:
+ case Decl::LinkageSpec:
+ case Decl::Block:
+ case Decl::Function:
+ case Decl::CXXMethod:
+ case Decl::CXXConstructor:
+ case Decl::CXXDestructor:
+ case Decl::CXXConversion:
+ {
+ DeclContext* DC = cast<DeclContext>(*I);
+ PrintDeclContext(DC, Indentation+2);
+ break;
+ }
+ case Decl::Field: {
+ FieldDecl* FD = cast<FieldDecl>(*I);
+ Out << "<field> " << FD << '\n';
+ break;
+ }
+ case Decl::Typedef: {
+ TypedefDecl* TD = cast<TypedefDecl>(*I);
+ Out << "<typedef> " << TD << '\n';
+ break;
+ }
+ case Decl::EnumConstant: {
+ EnumConstantDecl* ECD = cast<EnumConstantDecl>(*I);
+ Out << "<enum constant> " << ECD << '\n';
+ break;
+ }
+ case Decl::Var: {
+ VarDecl* VD = cast<VarDecl>(*I);
+ Out << "<var> " << VD << '\n';
+ break;
+ }
+ case Decl::ImplicitParam: {
+ ImplicitParamDecl* IPD = cast<ImplicitParamDecl>(*I);
+ Out << "<implicit parameter> " << IPD << '\n';
+ break;
+ }
+ case Decl::ParmVar: {
+ ParmVarDecl* PVD = cast<ParmVarDecl>(*I);
+ Out << "<parameter> " << PVD << '\n';
+ break;
+ }
+ case Decl::ObjCProperty: {
+ ObjCPropertyDecl* OPD = cast<ObjCPropertyDecl>(*I);
+ Out << "<objc property> " << OPD << '\n';
+ break;
+ }
+ case Decl::FunctionTemplate: {
+ FunctionTemplateDecl* FTD = cast<FunctionTemplateDecl>(*I);
+ Out << "<function template> " << FTD << '\n';
+ break;
+ }
+ case Decl::FileScopeAsm: {
+ Out << "<file-scope asm>\n";
+ break;
+ }
+ case Decl::UsingDirective: {
+ Out << "<using directive>\n";
+ break;
+ }
+ case Decl::NamespaceAlias: {
+ NamespaceAliasDecl* NAD = cast<NamespaceAliasDecl>(*I);
+ Out << "<namespace alias> " << NAD << '\n';
+ break;
+ }
+ case Decl::ClassTemplate: {
+ ClassTemplateDecl *CTD = cast<ClassTemplateDecl>(*I);
+ Out << "<class template> " << CTD << '\n';
+ break;
+ }
+ default:
+ Out << "DeclKind: " << DK << '"' << *I << "\"\n";
+ assert(0 && "decl unhandled");
+ }
+ }
+}
+ASTConsumer *clang::CreateDeclContextPrinter() {
+ return new DeclContextPrinter();
+}
+
+//===----------------------------------------------------------------------===//
+/// InheritanceViewer - C++ Inheritance Visualization
+
+namespace {
+class InheritanceViewer : public ASTConsumer {
+ const std::string clsname;
+public:
+ InheritanceViewer(const std::string& cname) : clsname(cname) {}
+
+ void HandleTranslationUnit(ASTContext &C) {
+ for (ASTContext::type_iterator I=C.types_begin(),E=C.types_end(); I!=E; ++I)
+ if (RecordType *T = dyn_cast<RecordType>(*I)) {
+ if (CXXRecordDecl *D = dyn_cast<CXXRecordDecl>(T->getDecl())) {
+ // FIXME: This lookup needs to be generalized to handle namespaces and
+ // (when we support them) templates.
+ if (D->getNameAsString() == clsname) {
+ D->viewInheritance(C);
+ }
+ }
+ }
+ }
+};
+}
+
+ASTConsumer *clang::CreateInheritanceViewer(const std::string& clsname) {
+ return new InheritanceViewer(clsname);
+}
diff --git a/contrib/llvm/tools/clang/lib/Frontend/ASTMerge.cpp b/contrib/llvm/tools/clang/lib/Frontend/ASTMerge.cpp
new file mode 100644
index 0000000..e916e20
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Frontend/ASTMerge.cpp
@@ -0,0 +1,105 @@
+//===-- ASTMerge.cpp - AST Merging Frontent Action --------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "clang/Frontend/ASTUnit.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTDiagnostic.h"
+#include "clang/AST/ASTImporter.h"
+#include "clang/Basic/Diagnostic.h"
+
+using namespace clang;
+
+ASTConsumer *ASTMergeAction::CreateASTConsumer(CompilerInstance &CI,
+ llvm::StringRef InFile) {
+ return AdaptedAction->CreateASTConsumer(CI, InFile);
+}
+
+bool ASTMergeAction::BeginSourceFileAction(CompilerInstance &CI,
+ llvm::StringRef Filename) {
+ // FIXME: This is a hack. We need a better way to communicate the
+ // AST file, compiler instance, and file name than member variables
+ // of FrontendAction.
+ AdaptedAction->setCurrentFile(getCurrentFile(), getCurrentFileKind(),
+ takeCurrentASTUnit());
+ AdaptedAction->setCompilerInstance(&CI);
+ return AdaptedAction->BeginSourceFileAction(CI, Filename);
+}
+
+void ASTMergeAction::ExecuteAction() {
+ CompilerInstance &CI = getCompilerInstance();
+ CI.getDiagnostics().getClient()->BeginSourceFile(
+ CI.getASTContext().getLangOptions());
+ CI.getDiagnostics().SetArgToStringFn(&FormatASTNodeDiagnosticArgument,
+ &CI.getASTContext());
+ llvm::IntrusiveRefCntPtr<Diagnostic> Diags(&CI.getDiagnostics());
+ for (unsigned I = 0, N = ASTFiles.size(); I != N; ++I) {
+ ASTUnit *Unit = ASTUnit::LoadFromPCHFile(ASTFiles[I], Diags, false);
+ if (!Unit)
+ continue;
+
+ ASTImporter Importer(CI.getDiagnostics(),
+ CI.getASTContext(),
+ CI.getFileManager(),
+ Unit->getASTContext(),
+ Unit->getFileManager());
+
+ TranslationUnitDecl *TU = Unit->getASTContext().getTranslationUnitDecl();
+ for (DeclContext::decl_iterator D = TU->decls_begin(),
+ DEnd = TU->decls_end();
+ D != DEnd; ++D) {
+ // Don't re-import __va_list_tag, __builtin_va_list.
+ if (NamedDecl *ND = dyn_cast<NamedDecl>(*D))
+ if (IdentifierInfo *II = ND->getIdentifier())
+ if (II->isStr("__va_list_tag") || II->isStr("__builtin_va_list"))
+ continue;
+
+ Importer.Import(*D);
+ }
+
+ delete Unit;
+ }
+
+ AdaptedAction->ExecuteAction();
+ CI.getDiagnostics().getClient()->EndSourceFile();
+}
+
+void ASTMergeAction::EndSourceFileAction() {
+ return AdaptedAction->EndSourceFileAction();
+}
+
+ASTMergeAction::ASTMergeAction(FrontendAction *AdaptedAction,
+ std::string *ASTFiles, unsigned NumASTFiles)
+ : AdaptedAction(AdaptedAction), ASTFiles(ASTFiles, ASTFiles + NumASTFiles) {
+ assert(AdaptedAction && "ASTMergeAction needs an action to adapt");
+}
+
+ASTMergeAction::~ASTMergeAction() {
+ delete AdaptedAction;
+}
+
+bool ASTMergeAction::usesPreprocessorOnly() const {
+ return AdaptedAction->usesPreprocessorOnly();
+}
+
+bool ASTMergeAction::usesCompleteTranslationUnit() {
+ return AdaptedAction->usesCompleteTranslationUnit();
+}
+
+bool ASTMergeAction::hasPCHSupport() const {
+ return AdaptedAction->hasPCHSupport();
+}
+
+bool ASTMergeAction::hasASTFileSupport() const {
+ return AdaptedAction->hasASTFileSupport();
+}
+
+bool ASTMergeAction::hasCodeCompletionSupport() const {
+ return AdaptedAction->hasCodeCompletionSupport();
+}
diff --git a/contrib/llvm/tools/clang/lib/Frontend/ASTUnit.cpp b/contrib/llvm/tools/clang/lib/Frontend/ASTUnit.cpp
new file mode 100644
index 0000000..88f0037
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Frontend/ASTUnit.cpp
@@ -0,0 +1,461 @@
+//===--- ASTUnit.cpp - ASTUnit utility ------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// ASTUnit Implementation.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/ASTUnit.h"
+#include "clang/Frontend/PCHReader.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/DeclVisitor.h"
+#include "clang/AST/StmtVisitor.h"
+#include "clang/Driver/Compilation.h"
+#include "clang/Driver/Driver.h"
+#include "clang/Driver/Job.h"
+#include "clang/Driver/Tool.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
+#include "clang/Frontend/FrontendOptions.h"
+#include "clang/Lex/HeaderSearch.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Basic/TargetOptions.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/Diagnostic.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/System/Host.h"
+#include "llvm/System/Path.h"
+using namespace clang;
+
+ASTUnit::ASTUnit(bool _MainFileIsAST)
+ : MainFileIsAST(_MainFileIsAST), ConcurrencyCheckValue(CheckUnlocked) { }
+
+ASTUnit::~ASTUnit() {
+ ConcurrencyCheckValue = CheckLocked;
+ for (unsigned I = 0, N = TemporaryFiles.size(); I != N; ++I)
+ TemporaryFiles[I].eraseFromDisk();
+}
+
+namespace {
+
+/// \brief Gathers information from PCHReader that will be used to initialize
+/// a Preprocessor.
+class PCHInfoCollector : public PCHReaderListener {
+ LangOptions &LangOpt;
+ HeaderSearch &HSI;
+ std::string &TargetTriple;
+ std::string &Predefines;
+ unsigned &Counter;
+
+ unsigned NumHeaderInfos;
+
+public:
+ PCHInfoCollector(LangOptions &LangOpt, HeaderSearch &HSI,
+ std::string &TargetTriple, std::string &Predefines,
+ unsigned &Counter)
+ : LangOpt(LangOpt), HSI(HSI), TargetTriple(TargetTriple),
+ Predefines(Predefines), Counter(Counter), NumHeaderInfos(0) {}
+
+ virtual bool ReadLanguageOptions(const LangOptions &LangOpts) {
+ LangOpt = LangOpts;
+ return false;
+ }
+
+ virtual bool ReadTargetTriple(llvm::StringRef Triple) {
+ TargetTriple = Triple;
+ return false;
+ }
+
+ virtual bool ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers,
+ llvm::StringRef OriginalFileName,
+ std::string &SuggestedPredefines) {
+ Predefines = Buffers[0].Data;
+ for (unsigned I = 1, N = Buffers.size(); I != N; ++I) {
+ Predefines += Buffers[I].Data;
+ }
+ return false;
+ }
+
+ virtual void ReadHeaderFileInfo(const HeaderFileInfo &HFI, unsigned ID) {
+ HSI.setHeaderFileInfoForUID(HFI, NumHeaderInfos++);
+ }
+
+ virtual void ReadCounter(unsigned Value) {
+ Counter = Value;
+ }
+};
+
+class StoredDiagnosticClient : public DiagnosticClient {
+ llvm::SmallVectorImpl<StoredDiagnostic> &StoredDiags;
+
+public:
+ explicit StoredDiagnosticClient(
+ llvm::SmallVectorImpl<StoredDiagnostic> &StoredDiags)
+ : StoredDiags(StoredDiags) { }
+
+ virtual void HandleDiagnostic(Diagnostic::Level Level,
+ const DiagnosticInfo &Info);
+};
+
+/// \brief RAII object that optionally captures diagnostics, if
+/// there is no diagnostic client to capture them already.
+class CaptureDroppedDiagnostics {
+ Diagnostic &Diags;
+ StoredDiagnosticClient Client;
+ DiagnosticClient *PreviousClient;
+
+public:
+ CaptureDroppedDiagnostics(bool RequestCapture, Diagnostic &Diags,
+ llvm::SmallVectorImpl<StoredDiagnostic> &StoredDiags)
+ : Diags(Diags), Client(StoredDiags), PreviousClient(Diags.getClient())
+ {
+ if (RequestCapture || Diags.getClient() == 0)
+ Diags.setClient(&Client);
+ }
+
+ ~CaptureDroppedDiagnostics() {
+ Diags.setClient(PreviousClient);
+ }
+};
+
+} // anonymous namespace
+
+void StoredDiagnosticClient::HandleDiagnostic(Diagnostic::Level Level,
+ const DiagnosticInfo &Info) {
+ StoredDiags.push_back(StoredDiagnostic(Level, Info));
+}
+
+const std::string &ASTUnit::getOriginalSourceFileName() {
+ return OriginalSourceFile;
+}
+
+const std::string &ASTUnit::getPCHFileName() {
+ assert(isMainFileAST() && "Not an ASTUnit from a PCH file!");
+ return static_cast<PCHReader *>(Ctx->getExternalSource())->getFileName();
+}
+
+ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename,
+ llvm::IntrusiveRefCntPtr<Diagnostic> Diags,
+ bool OnlyLocalDecls,
+ RemappedFile *RemappedFiles,
+ unsigned NumRemappedFiles,
+ bool CaptureDiagnostics) {
+ llvm::OwningPtr<ASTUnit> AST(new ASTUnit(true));
+
+ if (!Diags.getPtr()) {
+ // No diagnostics engine was provided, so create our own diagnostics object
+ // with the default options.
+ DiagnosticOptions DiagOpts;
+ Diags = CompilerInstance::createDiagnostics(DiagOpts, 0, 0);
+ }
+
+ AST->OnlyLocalDecls = OnlyLocalDecls;
+ AST->Diagnostics = Diags;
+ AST->FileMgr.reset(new FileManager);
+ AST->SourceMgr.reset(new SourceManager(AST->getDiagnostics()));
+ AST->HeaderInfo.reset(new HeaderSearch(AST->getFileManager()));
+
+ // If requested, capture diagnostics in the ASTUnit.
+ CaptureDroppedDiagnostics Capture(CaptureDiagnostics, AST->getDiagnostics(),
+ AST->StoredDiagnostics);
+
+ for (unsigned I = 0; I != NumRemappedFiles; ++I) {
+ // Create the file entry for the file that we're mapping from.
+ const FileEntry *FromFile
+ = AST->getFileManager().getVirtualFile(RemappedFiles[I].first,
+ RemappedFiles[I].second->getBufferSize(),
+ 0);
+ if (!FromFile) {
+ AST->getDiagnostics().Report(diag::err_fe_remap_missing_from_file)
+ << RemappedFiles[I].first;
+ delete RemappedFiles[I].second;
+ continue;
+ }
+
+ // Override the contents of the "from" file with the contents of
+ // the "to" file.
+ AST->getSourceManager().overrideFileContents(FromFile,
+ RemappedFiles[I].second);
+ }
+
+ // Gather Info for preprocessor construction later on.
+
+ LangOptions LangInfo;
+ HeaderSearch &HeaderInfo = *AST->HeaderInfo.get();
+ std::string TargetTriple;
+ std::string Predefines;
+ unsigned Counter;
+
+ llvm::OwningPtr<PCHReader> Reader;
+ llvm::OwningPtr<ExternalASTSource> Source;
+
+ Reader.reset(new PCHReader(AST->getSourceManager(), AST->getFileManager(),
+ AST->getDiagnostics()));
+ Reader->setListener(new PCHInfoCollector(LangInfo, HeaderInfo, TargetTriple,
+ Predefines, Counter));
+
+ switch (Reader->ReadPCH(Filename)) {
+ case PCHReader::Success:
+ break;
+
+ case PCHReader::Failure:
+ case PCHReader::IgnorePCH:
+ AST->getDiagnostics().Report(diag::err_fe_unable_to_load_pch);
+ return NULL;
+ }
+
+ AST->OriginalSourceFile = Reader->getOriginalSourceFile();
+
+ // PCH loaded successfully. Now create the preprocessor.
+
+ // Get information about the target being compiled for.
+ //
+ // FIXME: This is broken, we should store the TargetOptions in the PCH.
+ TargetOptions TargetOpts;
+ TargetOpts.ABI = "";
+ TargetOpts.CXXABI = "itanium";
+ TargetOpts.CPU = "";
+ TargetOpts.Features.clear();
+ TargetOpts.Triple = TargetTriple;
+ AST->Target.reset(TargetInfo::CreateTargetInfo(AST->getDiagnostics(),
+ TargetOpts));
+ AST->PP.reset(new Preprocessor(AST->getDiagnostics(), LangInfo,
+ *AST->Target.get(),
+ AST->getSourceManager(), HeaderInfo));
+ Preprocessor &PP = *AST->PP.get();
+
+ PP.setPredefines(Reader->getSuggestedPredefines());
+ PP.setCounterValue(Counter);
+ Reader->setPreprocessor(PP);
+
+ // Create and initialize the ASTContext.
+
+ AST->Ctx.reset(new ASTContext(LangInfo,
+ AST->getSourceManager(),
+ *AST->Target.get(),
+ PP.getIdentifierTable(),
+ PP.getSelectorTable(),
+ PP.getBuiltinInfo(),
+ /* FreeMemory = */ false,
+ /* size_reserve = */0));
+ ASTContext &Context = *AST->Ctx.get();
+
+ Reader->InitializeContext(Context);
+
+ // Attach the PCH reader to the AST context as an external AST
+ // source, so that declarations will be deserialized from the
+ // PCH file as needed.
+ Source.reset(Reader.take());
+ Context.setExternalSource(Source);
+
+ return AST.take();
+}
+
+namespace {
+
+class TopLevelDeclTrackerConsumer : public ASTConsumer {
+ ASTUnit &Unit;
+
+public:
+ TopLevelDeclTrackerConsumer(ASTUnit &_Unit) : Unit(_Unit) {}
+
+ void HandleTopLevelDecl(DeclGroupRef D) {
+ for (DeclGroupRef::iterator it = D.begin(), ie = D.end(); it != ie; ++it) {
+ Decl *D = *it;
+ // FIXME: Currently ObjC method declarations are incorrectly being
+ // reported as top-level declarations, even though their DeclContext
+ // is the containing ObjC @interface/@implementation. This is a
+ // fundamental problem in the parser right now.
+ if (isa<ObjCMethodDecl>(D))
+ continue;
+ Unit.getTopLevelDecls().push_back(D);
+ }
+ }
+};
+
+class TopLevelDeclTrackerAction : public ASTFrontendAction {
+public:
+ ASTUnit &Unit;
+
+ virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
+ llvm::StringRef InFile) {
+ return new TopLevelDeclTrackerConsumer(Unit);
+ }
+
+public:
+ TopLevelDeclTrackerAction(ASTUnit &_Unit) : Unit(_Unit) {}
+
+ virtual bool hasCodeCompletionSupport() const { return false; }
+};
+
+}
+
+ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI,
+ llvm::IntrusiveRefCntPtr<Diagnostic> Diags,
+ bool OnlyLocalDecls,
+ bool CaptureDiagnostics) {
+ // Create the compiler instance to use for building the AST.
+ CompilerInstance Clang;
+ llvm::OwningPtr<ASTUnit> AST;
+ llvm::OwningPtr<TopLevelDeclTrackerAction> Act;
+
+ if (!Diags.getPtr()) {
+ // No diagnostics engine was provided, so create our own diagnostics object
+ // with the default options.
+ DiagnosticOptions DiagOpts;
+ Diags = CompilerInstance::createDiagnostics(DiagOpts, 0, 0);
+ }
+
+ Clang.setInvocation(CI);
+
+ Clang.setDiagnostics(Diags.getPtr());
+ Clang.setDiagnosticClient(Diags->getClient());
+
+ // Create the target instance.
+ Clang.setTarget(TargetInfo::CreateTargetInfo(Clang.getDiagnostics(),
+ Clang.getTargetOpts()));
+ if (!Clang.hasTarget()) {
+ Clang.takeDiagnosticClient();
+ return 0;
+ }
+
+ // Inform the target of the language options.
+ //
+ // FIXME: We shouldn't need to do this, the target should be immutable once
+ // created. This complexity should be lifted elsewhere.
+ Clang.getTarget().setForcedLangOptions(Clang.getLangOpts());
+
+ assert(Clang.getFrontendOpts().Inputs.size() == 1 &&
+ "Invocation must have exactly one source file!");
+ assert(Clang.getFrontendOpts().Inputs[0].first != IK_AST &&
+ "FIXME: AST inputs not yet supported here!");
+ assert(Clang.getFrontendOpts().Inputs[0].first != IK_LLVM_IR &&
+ "IR inputs not support here!");
+
+ // Create the AST unit.
+ AST.reset(new ASTUnit(false));
+ AST->Diagnostics = Diags;
+ AST->FileMgr.reset(new FileManager);
+ AST->SourceMgr.reset(new SourceManager(AST->getDiagnostics()));
+ AST->OnlyLocalDecls = OnlyLocalDecls;
+ AST->OriginalSourceFile = Clang.getFrontendOpts().Inputs[0].second;
+
+ // Capture any diagnostics that would otherwise be dropped.
+ CaptureDroppedDiagnostics Capture(CaptureDiagnostics,
+ Clang.getDiagnostics(),
+ AST->StoredDiagnostics);
+
+ // Create a file manager object to provide access to and cache the filesystem.
+ Clang.setFileManager(&AST->getFileManager());
+
+ // Create the source manager.
+ Clang.setSourceManager(&AST->getSourceManager());
+
+ Act.reset(new TopLevelDeclTrackerAction(*AST));
+ if (!Act->BeginSourceFile(Clang, Clang.getFrontendOpts().Inputs[0].second,
+ Clang.getFrontendOpts().Inputs[0].first))
+ goto error;
+
+ Act->Execute();
+
+ // Steal the created target, context, and preprocessor, and take back the
+ // source and file managers.
+ AST->Ctx.reset(Clang.takeASTContext());
+ AST->PP.reset(Clang.takePreprocessor());
+ Clang.takeSourceManager();
+ Clang.takeFileManager();
+ AST->Target.reset(Clang.takeTarget());
+
+ Act->EndSourceFile();
+
+ Clang.takeDiagnosticClient();
+ Clang.takeInvocation();
+
+ AST->Invocation.reset(Clang.takeInvocation());
+ return AST.take();
+
+error:
+ Clang.takeSourceManager();
+ Clang.takeFileManager();
+ Clang.takeDiagnosticClient();
+ return 0;
+}
+
+ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
+ const char **ArgEnd,
+ llvm::IntrusiveRefCntPtr<Diagnostic> Diags,
+ llvm::StringRef ResourceFilesPath,
+ bool OnlyLocalDecls,
+ RemappedFile *RemappedFiles,
+ unsigned NumRemappedFiles,
+ bool CaptureDiagnostics) {
+ if (!Diags.getPtr()) {
+ // No diagnostics engine was provided, so create our own diagnostics object
+ // with the default options.
+ DiagnosticOptions DiagOpts;
+ Diags = CompilerInstance::createDiagnostics(DiagOpts, 0, 0);
+ }
+
+ llvm::SmallVector<const char *, 16> Args;
+ Args.push_back("<clang>"); // FIXME: Remove dummy argument.
+ Args.insert(Args.end(), ArgBegin, ArgEnd);
+
+ // FIXME: Find a cleaner way to force the driver into restricted modes. We
+ // also want to force it to use clang.
+ Args.push_back("-fsyntax-only");
+
+ // FIXME: We shouldn't have to pass in the path info.
+ driver::Driver TheDriver("clang", "/", llvm::sys::getHostTriple(),
+ "a.out", false, false, *Diags);
+
+ // Don't check that inputs exist, they have been remapped.
+ TheDriver.setCheckInputsExist(false);
+
+ llvm::OwningPtr<driver::Compilation> C(
+ TheDriver.BuildCompilation(Args.size(), Args.data()));
+
+ // We expect to get back exactly one command job, if we didn't something
+ // failed.
+ const driver::JobList &Jobs = C->getJobs();
+ if (Jobs.size() != 1 || !isa<driver::Command>(Jobs.begin())) {
+ llvm::SmallString<256> Msg;
+ llvm::raw_svector_ostream OS(Msg);
+ C->PrintJob(OS, C->getJobs(), "; ", true);
+ Diags->Report(diag::err_fe_expected_compiler_job) << OS.str();
+ return 0;
+ }
+
+ const driver::Command *Cmd = cast<driver::Command>(*Jobs.begin());
+ if (llvm::StringRef(Cmd->getCreator().getName()) != "clang") {
+ Diags->Report(diag::err_fe_expected_clang_command);
+ return 0;
+ }
+
+ const driver::ArgStringList &CCArgs = Cmd->getArguments();
+ llvm::OwningPtr<CompilerInvocation> CI(new CompilerInvocation);
+ CompilerInvocation::CreateFromArgs(*CI,
+ const_cast<const char **>(CCArgs.data()),
+ const_cast<const char **>(CCArgs.data()) +
+ CCArgs.size(),
+ *Diags);
+
+ // Override any files that need remapping
+ for (unsigned I = 0; I != NumRemappedFiles; ++I)
+ CI->getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first,
+ RemappedFiles[I].second);
+
+ // Override the resources path.
+ CI->getHeaderSearchOpts().ResourceDir = ResourceFilesPath;
+
+ CI->getFrontendOpts().DisableFree = true;
+ return LoadFromCompilerInvocation(CI.take(), Diags, OnlyLocalDecls,
+ CaptureDiagnostics);
+}
diff --git a/contrib/llvm/tools/clang/lib/Frontend/BoostConAction.cpp b/contrib/llvm/tools/clang/lib/Frontend/BoostConAction.cpp
new file mode 100644
index 0000000..4a12ff2
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Frontend/BoostConAction.cpp
@@ -0,0 +1,39 @@
+//===-- BoostConAction.cpp - BoostCon Workshop Action -----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include <cstdio>
+#include <iostream>
+using namespace clang;
+
+namespace {
+ class BoostConASTConsumer : public ASTConsumer,
+ public RecursiveASTVisitor<BoostConASTConsumer> {
+ public:
+ /// HandleTranslationUnit - This method is called when the ASTs for entire
+ /// translation unit have been parsed.
+ virtual void HandleTranslationUnit(ASTContext &Ctx);
+
+ bool VisitCXXRecordDecl(CXXRecordDecl *D) {
+ std::cout << D->getNameAsString() << std::endl;
+ return true;
+ }
+ };
+}
+
+ASTConsumer *BoostConAction::CreateASTConsumer(CompilerInstance &CI,
+ llvm::StringRef InFile) {
+ return new BoostConASTConsumer();
+}
+
+void BoostConASTConsumer::HandleTranslationUnit(ASTContext &Ctx) {
+ fprintf(stderr, "Welcome to BoostCon!\n");
+ TraverseDecl(Ctx.getTranslationUnitDecl());
+}
diff --git a/contrib/llvm/tools/clang/lib/Frontend/CMakeLists.txt b/contrib/llvm/tools/clang/lib/Frontend/CMakeLists.txt
new file mode 100644
index 0000000..8757e2c
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Frontend/CMakeLists.txt
@@ -0,0 +1,53 @@
+set(LLVM_NO_RTTI 1)
+
+add_clang_library(clangFrontend
+ ASTConsumers.cpp
+ ASTMerge.cpp
+ ASTUnit.cpp
+ BoostConAction.cpp
+ CacheTokens.cpp
+ CompilerInstance.cpp
+ CompilerInvocation.cpp
+ DeclXML.cpp
+ DependencyFile.cpp
+ DiagChecker.cpp
+ DocumentXML.cpp
+ FrontendAction.cpp
+ FrontendActions.cpp
+ FrontendOptions.cpp
+ GeneratePCH.cpp
+ InitHeaderSearch.cpp
+ InitPreprocessor.cpp
+ LangStandards.cpp
+ PCHReader.cpp
+ PCHReaderDecl.cpp
+ PCHReaderStmt.cpp
+ PCHWriter.cpp
+ PCHWriterDecl.cpp
+ PCHWriterStmt.cpp
+ PrintParserCallbacks.cpp
+ PrintPreprocessedOutput.cpp
+ StmtXML.cpp
+ TextDiagnosticBuffer.cpp
+ TextDiagnosticPrinter.cpp
+ TypeXML.cpp
+ VerifyDiagnosticsClient.cpp
+ Warnings.cpp
+ )
+
+IF(MSVC)
+ get_target_property(NON_ANSI_COMPILE_FLAGS clangFrontend COMPILE_FLAGS)
+ string(REPLACE /Za
+ "" NON_ANSI_COMPILE_FLAGS
+ ${NON_ANSI_COMPILE_FLAGS})
+ set_target_properties(clangFrontend PROPERTIES COMPILE_FLAGS ${NON_ANSI_COMPILE_FLAGS})
+ENDIF(MSVC)
+
+add_dependencies(clangFrontend
+ ClangAttrClasses
+ ClangAttrList
+ ClangDiagnosticFrontend
+ ClangDiagnosticLex
+ ClangDiagnosticSema
+ ClangDeclNodes
+ ClangStmtNodes)
diff --git a/contrib/llvm/tools/clang/lib/Frontend/CacheTokens.cpp b/contrib/llvm/tools/clang/lib/Frontend/CacheTokens.cpp
new file mode 100644
index 0000000..a5fcebe
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Frontend/CacheTokens.cpp
@@ -0,0 +1,649 @@
+//===--- CacheTokens.cpp - Caching of lexer tokens for PTH support --------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This provides a possible implementation of PTH support for Clang that is
+// based on caching lexed tokens and identifiers.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/Utils.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/IdentifierTable.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/OnDiskHashTable.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Lex/Preprocessor.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/System/Path.h"
+
+// FIXME: put this somewhere else?
+#ifndef S_ISDIR
+#define S_ISDIR(x) (((x)&_S_IFDIR)!=0)
+#endif
+
+using namespace clang;
+using namespace clang::io;
+
+//===----------------------------------------------------------------------===//
+// PTH-specific stuff.
+//===----------------------------------------------------------------------===//
+
+namespace {
+class PTHEntry {
+ Offset TokenData, PPCondData;
+
+public:
+ PTHEntry() {}
+
+ PTHEntry(Offset td, Offset ppcd)
+ : TokenData(td), PPCondData(ppcd) {}
+
+ Offset getTokenOffset() const { return TokenData; }
+ Offset getPPCondTableOffset() const { return PPCondData; }
+};
+
+
+class PTHEntryKeyVariant {
+ union { const FileEntry* FE; const char* Path; };
+ enum { IsFE = 0x1, IsDE = 0x2, IsNoExist = 0x0 } Kind;
+ struct stat *StatBuf;
+public:
+ PTHEntryKeyVariant(const FileEntry *fe)
+ : FE(fe), Kind(IsFE), StatBuf(0) {}
+
+ PTHEntryKeyVariant(struct stat* statbuf, const char* path)
+ : Path(path), Kind(IsDE), StatBuf(new struct stat(*statbuf)) {}
+
+ explicit PTHEntryKeyVariant(const char* path)
+ : Path(path), Kind(IsNoExist), StatBuf(0) {}
+
+ bool isFile() const { return Kind == IsFE; }
+
+ llvm::StringRef getString() const {
+ return Kind == IsFE ? FE->getName() : Path;
+ }
+
+ unsigned getKind() const { return (unsigned) Kind; }
+
+ void EmitData(llvm::raw_ostream& Out) {
+ switch (Kind) {
+ case IsFE:
+ // Emit stat information.
+ ::Emit32(Out, FE->getInode());
+ ::Emit32(Out, FE->getDevice());
+ ::Emit16(Out, FE->getFileMode());
+ ::Emit64(Out, FE->getModificationTime());
+ ::Emit64(Out, FE->getSize());
+ break;
+ case IsDE:
+ // Emit stat information.
+ ::Emit32(Out, (uint32_t) StatBuf->st_ino);
+ ::Emit32(Out, (uint32_t) StatBuf->st_dev);
+ ::Emit16(Out, (uint16_t) StatBuf->st_mode);
+ ::Emit64(Out, (uint64_t) StatBuf->st_mtime);
+ ::Emit64(Out, (uint64_t) StatBuf->st_size);
+ delete StatBuf;
+ break;
+ default:
+ break;
+ }
+ }
+
+ unsigned getRepresentationLength() const {
+ return Kind == IsNoExist ? 0 : 4 + 4 + 2 + 8 + 8;
+ }
+};
+
+class FileEntryPTHEntryInfo {
+public:
+ typedef PTHEntryKeyVariant key_type;
+ typedef key_type key_type_ref;
+
+ typedef PTHEntry data_type;
+ typedef const PTHEntry& data_type_ref;
+
+ static unsigned ComputeHash(PTHEntryKeyVariant V) {
+ return llvm::HashString(V.getString());
+ }
+
+ static std::pair<unsigned,unsigned>
+ EmitKeyDataLength(llvm::raw_ostream& Out, PTHEntryKeyVariant V,
+ const PTHEntry& E) {
+
+ unsigned n = V.getString().size() + 1 + 1;
+ ::Emit16(Out, n);
+
+ unsigned m = V.getRepresentationLength() + (V.isFile() ? 4 + 4 : 0);
+ ::Emit8(Out, m);
+
+ return std::make_pair(n, m);
+ }
+
+ static void EmitKey(llvm::raw_ostream& Out, PTHEntryKeyVariant V, unsigned n){
+ // Emit the entry kind.
+ ::Emit8(Out, (unsigned) V.getKind());
+ // Emit the string.
+ Out.write(V.getString().data(), n - 1);
+ }
+
+ static void EmitData(llvm::raw_ostream& Out, PTHEntryKeyVariant V,
+ const PTHEntry& E, unsigned) {
+
+
+ // For file entries emit the offsets into the PTH file for token data
+ // and the preprocessor blocks table.
+ if (V.isFile()) {
+ ::Emit32(Out, E.getTokenOffset());
+ ::Emit32(Out, E.getPPCondTableOffset());
+ }
+
+ // Emit any other data associated with the key (i.e., stat information).
+ V.EmitData(Out);
+ }
+};
+
+class OffsetOpt {
+ bool valid;
+ Offset off;
+public:
+ OffsetOpt() : valid(false) {}
+ bool hasOffset() const { return valid; }
+ Offset getOffset() const { assert(valid); return off; }
+ void setOffset(Offset o) { off = o; valid = true; }
+};
+} // end anonymous namespace
+
+typedef OnDiskChainedHashTableGenerator<FileEntryPTHEntryInfo> PTHMap;
+
+namespace {
+class PTHWriter {
+ typedef llvm::DenseMap<const IdentifierInfo*,uint32_t> IDMap;
+ typedef llvm::StringMap<OffsetOpt, llvm::BumpPtrAllocator> CachedStrsTy;
+
+ IDMap IM;
+ llvm::raw_fd_ostream& Out;
+ Preprocessor& PP;
+ uint32_t idcount;
+ PTHMap PM;
+ CachedStrsTy CachedStrs;
+ Offset CurStrOffset;
+ std::vector<llvm::StringMapEntry<OffsetOpt>*> StrEntries;
+
+ //// Get the persistent id for the given IdentifierInfo*.
+ uint32_t ResolveID(const IdentifierInfo* II);
+
+ /// Emit a token to the PTH file.
+ void EmitToken(const Token& T);
+
+ void Emit8(uint32_t V) { ::Emit8(Out, V); }
+
+ void Emit16(uint32_t V) { ::Emit16(Out, V); }
+
+ void Emit24(uint32_t V) { ::Emit24(Out, V); }
+
+ void Emit32(uint32_t V) { ::Emit32(Out, V); }
+
+ void EmitBuf(const char *Ptr, unsigned NumBytes) {
+ Out.write(Ptr, NumBytes);
+ }
+
+ void EmitString(llvm::StringRef V) {
+ ::Emit16(Out, V.size());
+ EmitBuf(V.data(), V.size());
+ }
+
+ /// EmitIdentifierTable - Emits two tables to the PTH file. The first is
+ /// a hashtable mapping from identifier strings to persistent IDs.
+ /// The second is a straight table mapping from persistent IDs to string data
+ /// (the keys of the first table).
+ std::pair<Offset, Offset> EmitIdentifierTable();
+
+ /// EmitFileTable - Emit a table mapping from file name strings to PTH
+ /// token data.
+ Offset EmitFileTable() { return PM.Emit(Out); }
+
+ PTHEntry LexTokens(Lexer& L);
+ Offset EmitCachedSpellings();
+
+public:
+ PTHWriter(llvm::raw_fd_ostream& out, Preprocessor& pp)
+ : Out(out), PP(pp), idcount(0), CurStrOffset(0) {}
+
+ PTHMap &getPM() { return PM; }
+ void GeneratePTH(const std::string &MainFile);
+};
+} // end anonymous namespace
+
+uint32_t PTHWriter::ResolveID(const IdentifierInfo* II) {
+ // Null IdentifierInfo's map to the persistent ID 0.
+ if (!II)
+ return 0;
+
+ IDMap::iterator I = IM.find(II);
+ if (I != IM.end())
+ return I->second; // We've already added 1.
+
+ IM[II] = ++idcount; // Pre-increment since '0' is reserved for NULL.
+ return idcount;
+}
+
+void PTHWriter::EmitToken(const Token& T) {
+ // Emit the token kind, flags, and length.
+ Emit32(((uint32_t) T.getKind()) | ((((uint32_t) T.getFlags())) << 8)|
+ (((uint32_t) T.getLength()) << 16));
+
+ if (!T.isLiteral()) {
+ Emit32(ResolveID(T.getIdentifierInfo()));
+ } else {
+ // We cache *un-cleaned* spellings. This gives us 100% fidelity with the
+ // source code.
+ const char* s = T.getLiteralData();
+ unsigned len = T.getLength();
+
+ // Get the string entry.
+ llvm::StringMapEntry<OffsetOpt> *E = &CachedStrs.GetOrCreateValue(s, s+len);
+
+ // If this is a new string entry, bump the PTH offset.
+ if (!E->getValue().hasOffset()) {
+ E->getValue().setOffset(CurStrOffset);
+ StrEntries.push_back(E);
+ CurStrOffset += len + 1;
+ }
+
+ // Emit the relative offset into the PTH file for the spelling string.
+ Emit32(E->getValue().getOffset());
+ }
+
+ // Emit the offset into the original source file of this token so that we
+ // can reconstruct its SourceLocation.
+ Emit32(PP.getSourceManager().getFileOffset(T.getLocation()));
+}
+
+PTHEntry PTHWriter::LexTokens(Lexer& L) {
+ // Pad 0's so that we emit tokens to a 4-byte alignment.
+ // This speed up reading them back in.
+ Pad(Out, 4);
+ Offset TokenOff = (Offset) Out.tell();
+
+ // Keep track of matching '#if' ... '#endif'.
+ typedef std::vector<std::pair<Offset, unsigned> > PPCondTable;
+ PPCondTable PPCond;
+ std::vector<unsigned> PPStartCond;
+ bool ParsingPreprocessorDirective = false;
+ Token Tok;
+
+ do {
+ L.LexFromRawLexer(Tok);
+ NextToken:
+
+ if ((Tok.isAtStartOfLine() || Tok.is(tok::eof)) &&
+ ParsingPreprocessorDirective) {
+ // Insert an eom token into the token cache. It has the same
+ // position as the next token that is not on the same line as the
+ // preprocessor directive. Observe that we continue processing
+ // 'Tok' when we exit this branch.
+ Token Tmp = Tok;
+ Tmp.setKind(tok::eom);
+ Tmp.clearFlag(Token::StartOfLine);
+ Tmp.setIdentifierInfo(0);
+ EmitToken(Tmp);
+ ParsingPreprocessorDirective = false;
+ }
+
+ if (Tok.is(tok::identifier)) {
+ PP.LookUpIdentifierInfo(Tok);
+ EmitToken(Tok);
+ continue;
+ }
+
+ if (Tok.is(tok::hash) && Tok.isAtStartOfLine()) {
+ // Special processing for #include. Store the '#' token and lex
+ // the next token.
+ assert(!ParsingPreprocessorDirective);
+ Offset HashOff = (Offset) Out.tell();
+ EmitToken(Tok);
+
+ // Get the next token.
+ L.LexFromRawLexer(Tok);
+
+ // If we see the start of line, then we had a null directive "#".
+ if (Tok.isAtStartOfLine())
+ goto NextToken;
+
+ // Did we see 'include'/'import'/'include_next'?
+ if (Tok.isNot(tok::identifier)) {
+ EmitToken(Tok);
+ continue;
+ }
+
+ IdentifierInfo* II = PP.LookUpIdentifierInfo(Tok);
+ tok::PPKeywordKind K = II->getPPKeywordID();
+
+ ParsingPreprocessorDirective = true;
+
+ switch (K) {
+ case tok::pp_not_keyword:
+ // Invalid directives "#foo" can occur in #if 0 blocks etc, just pass
+ // them through.
+ default:
+ break;
+
+ case tok::pp_include:
+ case tok::pp_import:
+ case tok::pp_include_next: {
+ // Save the 'include' token.
+ EmitToken(Tok);
+ // Lex the next token as an include string.
+ L.setParsingPreprocessorDirective(true);
+ L.LexIncludeFilename(Tok);
+ L.setParsingPreprocessorDirective(false);
+ assert(!Tok.isAtStartOfLine());
+ if (Tok.is(tok::identifier))
+ PP.LookUpIdentifierInfo(Tok);
+
+ break;
+ }
+ case tok::pp_if:
+ case tok::pp_ifdef:
+ case tok::pp_ifndef: {
+ // Add an entry for '#if' and friends. We initially set the target
+ // index to 0. This will get backpatched when we hit #endif.
+ PPStartCond.push_back(PPCond.size());
+ PPCond.push_back(std::make_pair(HashOff, 0U));
+ break;
+ }
+ case tok::pp_endif: {
+ // Add an entry for '#endif'. We set the target table index to itself.
+ // This will later be set to zero when emitting to the PTH file. We
+ // use 0 for uninitialized indices because that is easier to debug.
+ unsigned index = PPCond.size();
+ // Backpatch the opening '#if' entry.
+ assert(!PPStartCond.empty());
+ assert(PPCond.size() > PPStartCond.back());
+ assert(PPCond[PPStartCond.back()].second == 0);
+ PPCond[PPStartCond.back()].second = index;
+ PPStartCond.pop_back();
+ // Add the new entry to PPCond.
+ PPCond.push_back(std::make_pair(HashOff, index));
+ EmitToken(Tok);
+
+ // Some files have gibberish on the same line as '#endif'.
+ // Discard these tokens.
+ do
+ L.LexFromRawLexer(Tok);
+ while (Tok.isNot(tok::eof) && !Tok.isAtStartOfLine());
+ // We have the next token in hand.
+ // Don't immediately lex the next one.
+ goto NextToken;
+ }
+ case tok::pp_elif:
+ case tok::pp_else: {
+ // Add an entry for #elif or #else.
+ // This serves as both a closing and opening of a conditional block.
+ // This means that its entry will get backpatched later.
+ unsigned index = PPCond.size();
+ // Backpatch the previous '#if' entry.
+ assert(!PPStartCond.empty());
+ assert(PPCond.size() > PPStartCond.back());
+ assert(PPCond[PPStartCond.back()].second == 0);
+ PPCond[PPStartCond.back()].second = index;
+ PPStartCond.pop_back();
+ // Now add '#elif' as a new block opening.
+ PPCond.push_back(std::make_pair(HashOff, 0U));
+ PPStartCond.push_back(index);
+ break;
+ }
+ }
+ }
+
+ EmitToken(Tok);
+ }
+ while (Tok.isNot(tok::eof));
+
+ assert(PPStartCond.empty() && "Error: imblanced preprocessor conditionals.");
+
+ // Next write out PPCond.
+ Offset PPCondOff = (Offset) Out.tell();
+
+ // Write out the size of PPCond so that clients can identifer empty tables.
+ Emit32(PPCond.size());
+
+ for (unsigned i = 0, e = PPCond.size(); i!=e; ++i) {
+ Emit32(PPCond[i].first - TokenOff);
+ uint32_t x = PPCond[i].second;
+ assert(x != 0 && "PPCond entry not backpatched.");
+ // Emit zero for #endifs. This allows us to do checking when
+ // we read the PTH file back in.
+ Emit32(x == i ? 0 : x);
+ }
+
+ return PTHEntry(TokenOff, PPCondOff);
+}
+
+Offset PTHWriter::EmitCachedSpellings() {
+ // Write each cached strings to the PTH file.
+ Offset SpellingsOff = Out.tell();
+
+ for (std::vector<llvm::StringMapEntry<OffsetOpt>*>::iterator
+ I = StrEntries.begin(), E = StrEntries.end(); I!=E; ++I)
+ EmitBuf((*I)->getKeyData(), (*I)->getKeyLength()+1 /*nul included*/);
+
+ return SpellingsOff;
+}
+
+void PTHWriter::GeneratePTH(const std::string &MainFile) {
+ // Generate the prologue.
+ Out << "cfe-pth";
+ Emit32(PTHManager::Version);
+
+ // Leave 4 words for the prologue.
+ Offset PrologueOffset = Out.tell();
+ for (unsigned i = 0; i < 4; ++i)
+ Emit32(0);
+
+ // Write the name of the MainFile.
+ if (!MainFile.empty()) {
+ EmitString(MainFile);
+ } else {
+ // String with 0 bytes.
+ Emit16(0);
+ }
+ Emit8(0);
+
+ // Iterate over all the files in SourceManager. Create a lexer
+ // for each file and cache the tokens.
+ SourceManager &SM = PP.getSourceManager();
+ const LangOptions &LOpts = PP.getLangOptions();
+
+ for (SourceManager::fileinfo_iterator I = SM.fileinfo_begin(),
+ E = SM.fileinfo_end(); I != E; ++I) {
+ const SrcMgr::ContentCache &C = *I->second;
+ const FileEntry *FE = C.Entry;
+
+ // FIXME: Handle files with non-absolute paths.
+ llvm::sys::Path P(FE->getName());
+ if (!P.isAbsolute())
+ continue;
+
+ const llvm::MemoryBuffer *B = C.getBuffer(PP.getDiagnostics(), SM);
+ if (!B) continue;
+
+ FileID FID = SM.createFileID(FE, SourceLocation(), SrcMgr::C_User);
+ const llvm::MemoryBuffer *FromFile = SM.getBuffer(FID);
+ Lexer L(FID, FromFile, SM, LOpts);
+ PM.insert(FE, LexTokens(L));
+ }
+
+ // Write out the identifier table.
+ const std::pair<Offset,Offset> &IdTableOff = EmitIdentifierTable();
+
+ // Write out the cached strings table.
+ Offset SpellingOff = EmitCachedSpellings();
+
+ // Write out the file table.
+ Offset FileTableOff = EmitFileTable();
+
+ // Finally, write the prologue.
+ Out.seek(PrologueOffset);
+ Emit32(IdTableOff.first);
+ Emit32(IdTableOff.second);
+ Emit32(FileTableOff);
+ Emit32(SpellingOff);
+}
+
+namespace {
+/// StatListener - A simple "interpose" object used to monitor stat calls
+/// invoked by FileManager while processing the original sources used
+/// as input to PTH generation. StatListener populates the PTHWriter's
+/// file map with stat information for directories as well as negative stats.
+/// Stat information for files are populated elsewhere.
+class StatListener : public StatSysCallCache {
+ PTHMap &PM;
+public:
+ StatListener(PTHMap &pm) : PM(pm) {}
+ ~StatListener() {}
+
+ int stat(const char *path, struct stat *buf) {
+ int result = StatSysCallCache::stat(path, buf);
+
+ if (result != 0) // Failed 'stat'.
+ PM.insert(PTHEntryKeyVariant(path), PTHEntry());
+ else if (S_ISDIR(buf->st_mode)) {
+ // Only cache directories with absolute paths.
+ if (!llvm::sys::Path(path).isAbsolute())
+ return result;
+
+ PM.insert(PTHEntryKeyVariant(buf, path), PTHEntry());
+ }
+
+ return result;
+ }
+};
+} // end anonymous namespace
+
+
+void clang::CacheTokens(Preprocessor &PP, llvm::raw_fd_ostream* OS) {
+ // Get the name of the main file.
+ const SourceManager &SrcMgr = PP.getSourceManager();
+ const FileEntry *MainFile = SrcMgr.getFileEntryForID(SrcMgr.getMainFileID());
+ llvm::sys::Path MainFilePath(MainFile->getName());
+
+ MainFilePath.makeAbsolute();
+
+ // Create the PTHWriter.
+ PTHWriter PW(*OS, PP);
+
+ // Install the 'stat' system call listener in the FileManager.
+ StatListener *StatCache = new StatListener(PW.getPM());
+ PP.getFileManager().addStatCache(StatCache, /*AtBeginning=*/true);
+
+ // Lex through the entire file. This will populate SourceManager with
+ // all of the header information.
+ Token Tok;
+ PP.EnterMainSourceFile();
+ do { PP.Lex(Tok); } while (Tok.isNot(tok::eof));
+
+ // Generate the PTH file.
+ PP.getFileManager().removeStatCache(StatCache);
+ PW.GeneratePTH(MainFilePath.str());
+}
+
+//===----------------------------------------------------------------------===//
+
+namespace {
+class PTHIdKey {
+public:
+ const IdentifierInfo* II;
+ uint32_t FileOffset;
+};
+
+class PTHIdentifierTableTrait {
+public:
+ typedef PTHIdKey* key_type;
+ typedef key_type key_type_ref;
+
+ typedef uint32_t data_type;
+ typedef data_type data_type_ref;
+
+ static unsigned ComputeHash(PTHIdKey* key) {
+ return llvm::HashString(key->II->getName());
+ }
+
+ static std::pair<unsigned,unsigned>
+ EmitKeyDataLength(llvm::raw_ostream& Out, const PTHIdKey* key, uint32_t) {
+ unsigned n = key->II->getLength() + 1;
+ ::Emit16(Out, n);
+ return std::make_pair(n, sizeof(uint32_t));
+ }
+
+ static void EmitKey(llvm::raw_ostream& Out, PTHIdKey* key, unsigned n) {
+ // Record the location of the key data. This is used when generating
+ // the mapping from persistent IDs to strings.
+ key->FileOffset = Out.tell();
+ Out.write(key->II->getNameStart(), n);
+ }
+
+ static void EmitData(llvm::raw_ostream& Out, PTHIdKey*, uint32_t pID,
+ unsigned) {
+ ::Emit32(Out, pID);
+ }
+};
+} // end anonymous namespace
+
+/// EmitIdentifierTable - Emits two tables to the PTH file. The first is
+/// a hashtable mapping from identifier strings to persistent IDs. The second
+/// is a straight table mapping from persistent IDs to string data (the
+/// keys of the first table).
+///
+std::pair<Offset,Offset> PTHWriter::EmitIdentifierTable() {
+ // Build two maps:
+ // (1) an inverse map from persistent IDs -> (IdentifierInfo*,Offset)
+ // (2) a map from (IdentifierInfo*, Offset)* -> persistent IDs
+
+ // Note that we use 'calloc', so all the bytes are 0.
+ PTHIdKey *IIDMap = (PTHIdKey*)calloc(idcount, sizeof(PTHIdKey));
+
+ // Create the hashtable.
+ OnDiskChainedHashTableGenerator<PTHIdentifierTableTrait> IIOffMap;
+
+ // Generate mapping from persistent IDs -> IdentifierInfo*.
+ for (IDMap::iterator I = IM.begin(), E = IM.end(); I != E; ++I) {
+ // Decrement by 1 because we are using a vector for the lookup and
+ // 0 is reserved for NULL.
+ assert(I->second > 0);
+ assert(I->second-1 < idcount);
+ unsigned idx = I->second-1;
+
+ // Store the mapping from persistent ID to IdentifierInfo*
+ IIDMap[idx].II = I->first;
+
+ // Store the reverse mapping in a hashtable.
+ IIOffMap.insert(&IIDMap[idx], I->second);
+ }
+
+ // Write out the inverse map first. This causes the PCIDKey entries to
+ // record PTH file offsets for the string data. This is used to write
+ // the second table.
+ Offset StringTableOffset = IIOffMap.Emit(Out);
+
+ // Now emit the table mapping from persistent IDs to PTH file offsets.
+ Offset IDOff = Out.tell();
+ Emit32(idcount); // Emit the number of identifiers.
+ for (unsigned i = 0 ; i < idcount; ++i)
+ Emit32(IIDMap[i].FileOffset);
+
+ // Finally, release the inverse map.
+ free(IIDMap);
+
+ return std::make_pair(IDOff, StringTableOffset);
+}
diff --git a/contrib/llvm/tools/clang/lib/Frontend/CompilerInstance.cpp b/contrib/llvm/tools/clang/lib/Frontend/CompilerInstance.cpp
new file mode 100644
index 0000000..5037c83
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Frontend/CompilerInstance.cpp
@@ -0,0 +1,535 @@
+//===--- CompilerInstance.cpp ---------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/Version.h"
+#include "clang/Lex/HeaderSearch.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/PTHManager.h"
+#include "clang/Frontend/ChainedDiagnosticClient.h"
+#include "clang/Frontend/FrontendAction.h"
+#include "clang/Frontend/PCHReader.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
+#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "clang/Frontend/VerifyDiagnosticsClient.h"
+#include "clang/Frontend/Utils.h"
+#include "clang/Sema/CodeCompleteConsumer.h"
+#include "llvm/LLVMContext.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/Support/Timer.h"
+#include "llvm/System/Host.h"
+#include "llvm/System/Path.h"
+#include "llvm/System/Program.h"
+using namespace clang;
+
+CompilerInstance::CompilerInstance()
+ : Invocation(new CompilerInvocation()), Reader(0) {
+}
+
+CompilerInstance::~CompilerInstance() {
+}
+
+void CompilerInstance::setLLVMContext(llvm::LLVMContext *Value) {
+ LLVMContext.reset(Value);
+}
+
+void CompilerInstance::setInvocation(CompilerInvocation *Value) {
+ Invocation.reset(Value);
+}
+
+void CompilerInstance::setDiagnostics(Diagnostic *Value) {
+ Diagnostics = Value;
+}
+
+void CompilerInstance::setDiagnosticClient(DiagnosticClient *Value) {
+ DiagClient.reset(Value);
+}
+
+void CompilerInstance::setTarget(TargetInfo *Value) {
+ Target.reset(Value);
+}
+
+void CompilerInstance::setFileManager(FileManager *Value) {
+ FileMgr.reset(Value);
+}
+
+void CompilerInstance::setSourceManager(SourceManager *Value) {
+ SourceMgr.reset(Value);
+}
+
+void CompilerInstance::setPreprocessor(Preprocessor *Value) {
+ PP.reset(Value);
+}
+
+void CompilerInstance::setASTContext(ASTContext *Value) {
+ Context.reset(Value);
+}
+
+void CompilerInstance::setASTConsumer(ASTConsumer *Value) {
+ Consumer.reset(Value);
+}
+
+void CompilerInstance::setCodeCompletionConsumer(CodeCompleteConsumer *Value) {
+ CompletionConsumer.reset(Value);
+}
+
+// Diagnostics
+namespace {
+ class BinaryDiagnosticSerializer : public DiagnosticClient {
+ llvm::raw_ostream &OS;
+ SourceManager *SourceMgr;
+ public:
+ explicit BinaryDiagnosticSerializer(llvm::raw_ostream &OS)
+ : OS(OS), SourceMgr(0) { }
+
+ virtual void HandleDiagnostic(Diagnostic::Level DiagLevel,
+ const DiagnosticInfo &Info);
+ };
+}
+
+void BinaryDiagnosticSerializer::HandleDiagnostic(Diagnostic::Level DiagLevel,
+ const DiagnosticInfo &Info) {
+ StoredDiagnostic(DiagLevel, Info).Serialize(OS);
+}
+
+static void SetUpBuildDumpLog(const DiagnosticOptions &DiagOpts,
+ unsigned argc, char **argv,
+ Diagnostic &Diags) {
+ std::string ErrorInfo;
+ llvm::OwningPtr<llvm::raw_ostream> OS(
+ new llvm::raw_fd_ostream(DiagOpts.DumpBuildInformation.c_str(), ErrorInfo));
+ if (!ErrorInfo.empty()) {
+ Diags.Report(diag::err_fe_unable_to_open_logfile)
+ << DiagOpts.DumpBuildInformation << ErrorInfo;
+ return;
+ }
+
+ (*OS) << "clang -cc1 command line arguments: ";
+ for (unsigned i = 0; i != argc; ++i)
+ (*OS) << argv[i] << ' ';
+ (*OS) << '\n';
+
+ // Chain in a diagnostic client which will log the diagnostics.
+ DiagnosticClient *Logger =
+ new TextDiagnosticPrinter(*OS.take(), DiagOpts, /*OwnsOutputStream=*/true);
+ Diags.setClient(new ChainedDiagnosticClient(Diags.getClient(), Logger));
+}
+
+void CompilerInstance::createDiagnostics(int Argc, char **Argv) {
+ Diagnostics = createDiagnostics(getDiagnosticOpts(), Argc, Argv);
+
+ if (Diagnostics)
+ DiagClient.reset(Diagnostics->getClient());
+}
+
+llvm::IntrusiveRefCntPtr<Diagnostic>
+CompilerInstance::createDiagnostics(const DiagnosticOptions &Opts,
+ int Argc, char **Argv) {
+ llvm::IntrusiveRefCntPtr<Diagnostic> Diags(new Diagnostic());
+
+ // Create the diagnostic client for reporting errors or for
+ // implementing -verify.
+ llvm::OwningPtr<DiagnosticClient> DiagClient;
+ if (Opts.BinaryOutput) {
+ if (llvm::sys::Program::ChangeStderrToBinary()) {
+ // We weren't able to set standard error to binary, which is a
+ // bit of a problem. So, just create a text diagnostic printer
+ // to complain about this problem, and pretend that the user
+ // didn't try to use binary output.
+ DiagClient.reset(new TextDiagnosticPrinter(llvm::errs(), Opts));
+ Diags->setClient(DiagClient.take());
+ Diags->Report(diag::err_fe_stderr_binary);
+ return Diags;
+ } else {
+ DiagClient.reset(new BinaryDiagnosticSerializer(llvm::errs()));
+ }
+ } else {
+ DiagClient.reset(new TextDiagnosticPrinter(llvm::errs(), Opts));
+ }
+
+ // Chain in -verify checker, if requested.
+ if (Opts.VerifyDiagnostics)
+ DiagClient.reset(new VerifyDiagnosticsClient(*Diags, DiagClient.take()));
+
+ Diags->setClient(DiagClient.take());
+ if (!Opts.DumpBuildInformation.empty())
+ SetUpBuildDumpLog(Opts, Argc, Argv, *Diags);
+
+ // Configure our handling of diagnostics.
+ ProcessWarningOptions(*Diags, Opts);
+
+ return Diags;
+}
+
+// File Manager
+
+void CompilerInstance::createFileManager() {
+ FileMgr.reset(new FileManager());
+}
+
+// Source Manager
+
+void CompilerInstance::createSourceManager() {
+ SourceMgr.reset(new SourceManager(getDiagnostics()));
+}
+
+// Preprocessor
+
+void CompilerInstance::createPreprocessor() {
+ PP.reset(createPreprocessor(getDiagnostics(), getLangOpts(),
+ getPreprocessorOpts(), getHeaderSearchOpts(),
+ getDependencyOutputOpts(), getTarget(),
+ getFrontendOpts(), getSourceManager(),
+ getFileManager()));
+}
+
+Preprocessor *
+CompilerInstance::createPreprocessor(Diagnostic &Diags,
+ const LangOptions &LangInfo,
+ const PreprocessorOptions &PPOpts,
+ const HeaderSearchOptions &HSOpts,
+ const DependencyOutputOptions &DepOpts,
+ const TargetInfo &Target,
+ const FrontendOptions &FEOpts,
+ SourceManager &SourceMgr,
+ FileManager &FileMgr) {
+ // Create a PTH manager if we are using some form of a token cache.
+ PTHManager *PTHMgr = 0;
+ if (!PPOpts.TokenCache.empty())
+ PTHMgr = PTHManager::Create(PPOpts.TokenCache, Diags);
+
+ // Create the Preprocessor.
+ HeaderSearch *HeaderInfo = new HeaderSearch(FileMgr);
+ Preprocessor *PP = new Preprocessor(Diags, LangInfo, Target,
+ SourceMgr, *HeaderInfo, PTHMgr,
+ /*OwnsHeaderSearch=*/true);
+
+ // Note that this is different then passing PTHMgr to Preprocessor's ctor.
+ // That argument is used as the IdentifierInfoLookup argument to
+ // IdentifierTable's ctor.
+ if (PTHMgr) {
+ PTHMgr->setPreprocessor(PP);
+ PP->setPTHManager(PTHMgr);
+ }
+
+ if (PPOpts.DetailedRecord)
+ PP->createPreprocessingRecord();
+
+ InitializePreprocessor(*PP, PPOpts, HSOpts, FEOpts);
+
+ // Handle generating dependencies, if requested.
+ if (!DepOpts.OutputFile.empty())
+ AttachDependencyFileGen(*PP, DepOpts);
+
+ return PP;
+}
+
+// ASTContext
+
+void CompilerInstance::createASTContext() {
+ Preprocessor &PP = getPreprocessor();
+ Context.reset(new ASTContext(getLangOpts(), PP.getSourceManager(),
+ getTarget(), PP.getIdentifierTable(),
+ PP.getSelectorTable(), PP.getBuiltinInfo(),
+ /*FreeMemory=*/ !getFrontendOpts().DisableFree,
+ /*size_reserve=*/ 0));
+}
+
+// ExternalASTSource
+
+void CompilerInstance::createPCHExternalASTSource(llvm::StringRef Path) {
+ llvm::OwningPtr<ExternalASTSource> Source;
+ Source.reset(createPCHExternalASTSource(Path, getHeaderSearchOpts().Sysroot,
+ getPreprocessor(), getASTContext()));
+ // Remember the PCHReader, but in a non-owning way.
+ Reader = static_cast<PCHReader*>(Source.get());
+ getASTContext().setExternalSource(Source);
+}
+
+ExternalASTSource *
+CompilerInstance::createPCHExternalASTSource(llvm::StringRef Path,
+ const std::string &Sysroot,
+ Preprocessor &PP,
+ ASTContext &Context) {
+ llvm::OwningPtr<PCHReader> Reader;
+ Reader.reset(new PCHReader(PP, &Context,
+ Sysroot.empty() ? 0 : Sysroot.c_str()));
+
+ switch (Reader->ReadPCH(Path)) {
+ case PCHReader::Success:
+ // Set the predefines buffer as suggested by the PCH reader. Typically, the
+ // predefines buffer will be empty.
+ PP.setPredefines(Reader->getSuggestedPredefines());
+ return Reader.take();
+
+ case PCHReader::Failure:
+ // Unrecoverable failure: don't even try to process the input file.
+ break;
+
+ case PCHReader::IgnorePCH:
+ // No suitable PCH file could be found. Return an error.
+ break;
+ }
+
+ return 0;
+}
+
+// Code Completion
+
+void CompilerInstance::createCodeCompletionConsumer() {
+ const ParsedSourceLocation &Loc = getFrontendOpts().CodeCompletionAt;
+ CompletionConsumer.reset(
+ createCodeCompletionConsumer(getPreprocessor(),
+ Loc.FileName, Loc.Line, Loc.Column,
+ getFrontendOpts().DebugCodeCompletionPrinter,
+ getFrontendOpts().ShowMacrosInCodeCompletion,
+ getFrontendOpts().ShowCodePatternsInCodeCompletion,
+ llvm::outs()));
+ if (!CompletionConsumer)
+ return;
+
+ if (CompletionConsumer->isOutputBinary() &&
+ llvm::sys::Program::ChangeStdoutToBinary()) {
+ getPreprocessor().getDiagnostics().Report(diag::err_fe_stdout_binary);
+ CompletionConsumer.reset();
+ }
+}
+
+void CompilerInstance::createFrontendTimer() {
+ FrontendTimer.reset(new llvm::Timer("Clang front-end timer"));
+}
+
+CodeCompleteConsumer *
+CompilerInstance::createCodeCompletionConsumer(Preprocessor &PP,
+ const std::string &Filename,
+ unsigned Line,
+ unsigned Column,
+ bool UseDebugPrinter,
+ bool ShowMacros,
+ bool ShowCodePatterns,
+ llvm::raw_ostream &OS) {
+ // Tell the source manager to chop off the given file at a specific
+ // line and column.
+ const FileEntry *Entry = PP.getFileManager().getFile(Filename);
+ if (!Entry) {
+ PP.getDiagnostics().Report(diag::err_fe_invalid_code_complete_file)
+ << Filename;
+ return 0;
+ }
+
+ // Truncate the named file at the given line/column.
+ PP.SetCodeCompletionPoint(Entry, Line, Column);
+
+ // Set up the creation routine for code-completion.
+ if (UseDebugPrinter)
+ return new PrintingCodeCompleteConsumer(ShowMacros, ShowCodePatterns, OS);
+ else
+ return new CIndexCodeCompleteConsumer(ShowMacros, ShowCodePatterns, OS);
+}
+
+// Output Files
+
+void CompilerInstance::addOutputFile(llvm::StringRef Path,
+ llvm::raw_ostream *OS) {
+ assert(OS && "Attempt to add empty stream to output list!");
+ OutputFiles.push_back(std::make_pair(Path, OS));
+}
+
+void CompilerInstance::clearOutputFiles(bool EraseFiles) {
+ for (std::list< std::pair<std::string, llvm::raw_ostream*> >::iterator
+ it = OutputFiles.begin(), ie = OutputFiles.end(); it != ie; ++it) {
+ delete it->second;
+ if (EraseFiles && !it->first.empty())
+ llvm::sys::Path(it->first).eraseFromDisk();
+ }
+ OutputFiles.clear();
+}
+
+llvm::raw_fd_ostream *
+CompilerInstance::createDefaultOutputFile(bool Binary,
+ llvm::StringRef InFile,
+ llvm::StringRef Extension) {
+ return createOutputFile(getFrontendOpts().OutputFile, Binary,
+ InFile, Extension);
+}
+
+llvm::raw_fd_ostream *
+CompilerInstance::createOutputFile(llvm::StringRef OutputPath,
+ bool Binary,
+ llvm::StringRef InFile,
+ llvm::StringRef Extension) {
+ std::string Error, OutputPathName;
+ llvm::raw_fd_ostream *OS = createOutputFile(OutputPath, Error, Binary,
+ InFile, Extension,
+ &OutputPathName);
+ if (!OS) {
+ getDiagnostics().Report(diag::err_fe_unable_to_open_output)
+ << OutputPath << Error;
+ return 0;
+ }
+
+ // Add the output file -- but don't try to remove "-", since this means we are
+ // using stdin.
+ addOutputFile((OutputPathName != "-") ? OutputPathName : "", OS);
+
+ return OS;
+}
+
+llvm::raw_fd_ostream *
+CompilerInstance::createOutputFile(llvm::StringRef OutputPath,
+ std::string &Error,
+ bool Binary,
+ llvm::StringRef InFile,
+ llvm::StringRef Extension,
+ std::string *ResultPathName) {
+ std::string OutFile;
+ if (!OutputPath.empty()) {
+ OutFile = OutputPath;
+ } else if (InFile == "-") {
+ OutFile = "-";
+ } else if (!Extension.empty()) {
+ llvm::sys::Path Path(InFile);
+ Path.eraseSuffix();
+ Path.appendSuffix(Extension);
+ OutFile = Path.str();
+ } else {
+ OutFile = "-";
+ }
+
+ llvm::OwningPtr<llvm::raw_fd_ostream> OS(
+ new llvm::raw_fd_ostream(OutFile.c_str(), Error,
+ (Binary ? llvm::raw_fd_ostream::F_Binary : 0)));
+ if (!Error.empty())
+ return 0;
+
+ if (ResultPathName)
+ *ResultPathName = OutFile;
+
+ return OS.take();
+}
+
+// Initialization Utilities
+
+bool CompilerInstance::InitializeSourceManager(llvm::StringRef InputFile) {
+ return InitializeSourceManager(InputFile, getDiagnostics(), getFileManager(),
+ getSourceManager(), getFrontendOpts());
+}
+
+bool CompilerInstance::InitializeSourceManager(llvm::StringRef InputFile,
+ Diagnostic &Diags,
+ FileManager &FileMgr,
+ SourceManager &SourceMgr,
+ const FrontendOptions &Opts) {
+ // Figure out where to get and map in the main file.
+ if (InputFile != "-") {
+ const FileEntry *File = FileMgr.getFile(InputFile);
+ if (File) SourceMgr.createMainFileID(File, SourceLocation());
+ if (SourceMgr.getMainFileID().isInvalid()) {
+ Diags.Report(diag::err_fe_error_reading) << InputFile;
+ return false;
+ }
+ } else {
+ llvm::MemoryBuffer *SB = llvm::MemoryBuffer::getSTDIN();
+ if (SB) SourceMgr.createMainFileIDForMemBuffer(SB);
+ if (SourceMgr.getMainFileID().isInvalid()) {
+ Diags.Report(diag::err_fe_error_reading_stdin);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+// High-Level Operations
+
+bool CompilerInstance::ExecuteAction(FrontendAction &Act) {
+ assert(hasDiagnostics() && "Diagnostics engine is not initialized!");
+ assert(!getFrontendOpts().ShowHelp && "Client must handle '-help'!");
+ assert(!getFrontendOpts().ShowVersion && "Client must handle '-version'!");
+
+ // FIXME: Take this as an argument, once all the APIs we used have moved to
+ // taking it as an input instead of hard-coding llvm::errs.
+ llvm::raw_ostream &OS = llvm::errs();
+
+ // Create the target instance.
+ setTarget(TargetInfo::CreateTargetInfo(getDiagnostics(), getTargetOpts()));
+ if (!hasTarget())
+ return false;
+
+ // Inform the target of the language options.
+ //
+ // FIXME: We shouldn't need to do this, the target should be immutable once
+ // created. This complexity should be lifted elsewhere.
+ getTarget().setForcedLangOptions(getLangOpts());
+
+ // Validate/process some options.
+ if (getHeaderSearchOpts().Verbose)
+ OS << "clang -cc1 version " CLANG_VERSION_STRING
+ << " based upon " << PACKAGE_STRING
+ << " hosted on " << llvm::sys::getHostTriple() << "\n";
+
+ if (getFrontendOpts().ShowTimers)
+ createFrontendTimer();
+
+ if (getFrontendOpts().ShowStats)
+ llvm::EnableStatistics();
+
+ for (unsigned i = 0, e = getFrontendOpts().Inputs.size(); i != e; ++i) {
+ const std::string &InFile = getFrontendOpts().Inputs[i].second;
+
+ // Reset the ID tables if we are reusing the SourceManager.
+ if (hasSourceManager())
+ getSourceManager().clearIDTables();
+
+ if (Act.BeginSourceFile(*this, InFile, getFrontendOpts().Inputs[i].first)) {
+ Act.Execute();
+ Act.EndSourceFile();
+ }
+ }
+
+ if (getDiagnosticOpts().ShowCarets) {
+ unsigned NumWarnings = getDiagnostics().getNumWarnings();
+ unsigned NumErrors = getDiagnostics().getNumErrors() -
+ getDiagnostics().getNumErrorsSuppressed();
+
+ if (NumWarnings)
+ OS << NumWarnings << " warning" << (NumWarnings == 1 ? "" : "s");
+ if (NumWarnings && NumErrors)
+ OS << " and ";
+ if (NumErrors)
+ OS << NumErrors << " error" << (NumErrors == 1 ? "" : "s");
+ if (NumWarnings || NumErrors)
+ OS << " generated.\n";
+ }
+
+ if (getFrontendOpts().ShowStats && hasFileManager()) {
+ getFileManager().PrintStats();
+ OS << "\n";
+ }
+
+ // Return the appropriate status when verifying diagnostics.
+ //
+ // FIXME: If we could make getNumErrors() do the right thing, we wouldn't need
+ // this.
+ if (getDiagnosticOpts().VerifyDiagnostics)
+ return !static_cast<VerifyDiagnosticsClient&>(
+ getDiagnosticClient()).HadErrors();
+
+ return !getDiagnostics().getNumErrors();
+}
+
+
diff --git a/contrib/llvm/tools/clang/lib/Frontend/CompilerInvocation.cpp b/contrib/llvm/tools/clang/lib/Frontend/CompilerInvocation.cpp
new file mode 100644
index 0000000..53debdb
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Frontend/CompilerInvocation.cpp
@@ -0,0 +1,1473 @@
+//===--- CompilerInvocation.cpp -------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/CompilerInvocation.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/Version.h"
+#include "clang/Driver/Arg.h"
+#include "clang/Driver/ArgList.h"
+#include "clang/Driver/CC1Options.h"
+#include "clang/Driver/DriverDiagnostic.h"
+#include "clang/Driver/OptTable.h"
+#include "clang/Driver/Option.h"
+#include "clang/Frontend/CompilerInvocation.h"
+#include "clang/Frontend/LangStandard.h"
+#include "clang/Frontend/PCHReader.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/System/Host.h"
+#include "llvm/System/Path.h"
+using namespace clang;
+
+static const char *getAnalysisName(Analyses Kind) {
+ switch (Kind) {
+ default:
+ llvm_unreachable("Unknown analysis kind!");
+#define ANALYSIS(NAME, CMDFLAG, DESC, SCOPE)\
+ case NAME: return "-" CMDFLAG;
+#include "clang/Frontend/Analyses.def"
+ }
+}
+
+static const char *getAnalysisStoreName(AnalysisStores Kind) {
+ switch (Kind) {
+ default:
+ llvm_unreachable("Unknown analysis store!");
+#define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATFN) \
+ case NAME##Model: return CMDFLAG;
+#include "clang/Frontend/Analyses.def"
+ }
+}
+
+static const char *getAnalysisConstraintName(AnalysisConstraints Kind) {
+ switch (Kind) {
+ default:
+ llvm_unreachable("Unknown analysis constraints!");
+#define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATFN) \
+ case NAME##Model: return CMDFLAG;
+#include "clang/Frontend/Analyses.def"
+ }
+}
+
+static const char *getAnalysisDiagClientName(AnalysisDiagClients Kind) {
+ switch (Kind) {
+ default:
+ llvm_unreachable("Unknown analysis client!");
+#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATFN, AUTOCREATE) \
+ case PD_##NAME: return CMDFLAG;
+#include "clang/Frontend/Analyses.def"
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// Serialization (to args)
+//===----------------------------------------------------------------------===//
+
+static void AnalyzerOptsToArgs(const AnalyzerOptions &Opts,
+ std::vector<std::string> &Res) {
+ for (unsigned i = 0, e = Opts.AnalysisList.size(); i != e; ++i)
+ Res.push_back(getAnalysisName(Opts.AnalysisList[i]));
+ if (Opts.AnalysisStoreOpt != BasicStoreModel) {
+ Res.push_back("-analyzer-store");
+ Res.push_back(getAnalysisStoreName(Opts.AnalysisStoreOpt));
+ }
+ if (Opts.AnalysisConstraintsOpt != RangeConstraintsModel) {
+ Res.push_back("-analyzer-constraints");
+ Res.push_back(getAnalysisConstraintName(Opts.AnalysisConstraintsOpt));
+ }
+ if (Opts.AnalysisDiagOpt != PD_HTML) {
+ Res.push_back("-analyzer-output");
+ Res.push_back(getAnalysisDiagClientName(Opts.AnalysisDiagOpt));
+ }
+ if (!Opts.AnalyzeSpecificFunction.empty()) {
+ Res.push_back("-analyze-function");
+ Res.push_back(Opts.AnalyzeSpecificFunction);
+ }
+ if (Opts.AnalyzeAll)
+ Res.push_back("-analyzer-opt-analyze-headers");
+ if (Opts.AnalyzerDisplayProgress)
+ Res.push_back("-analyzer-display-progress");
+ if (Opts.AnalyzeNestedBlocks)
+ Res.push_back("-analyzer-opt-analyze-nested-blocks");
+ if (Opts.EagerlyAssume)
+ Res.push_back("-analyzer-eagerly-assume");
+ if (!Opts.PurgeDead)
+ Res.push_back("-analyzer-no-purge-dead");
+ if (Opts.TrimGraph)
+ Res.push_back("-trim-egraph");
+ if (Opts.VisualizeEGDot)
+ Res.push_back("-analyzer-viz-egraph-graphviz");
+ if (Opts.VisualizeEGDot)
+ Res.push_back("-analyzer-viz-egraph-ubigraph");
+ if (Opts.EnableExperimentalChecks)
+ Res.push_back("-analyzer-experimental-checks");
+ if (Opts.EnableExperimentalInternalChecks)
+ Res.push_back("-analyzer-experimental-internal-checks");
+ if (Opts.EnableIdempotentOperationChecker)
+ Res.push_back("-analyzer-idempotent-operation");
+}
+
+static void CodeGenOptsToArgs(const CodeGenOptions &Opts,
+ std::vector<std::string> &Res) {
+ if (Opts.DebugInfo)
+ Res.push_back("-g");
+ if (Opts.DisableLLVMOpts)
+ Res.push_back("-disable-llvm-optzns");
+ if (Opts.DisableRedZone)
+ Res.push_back("-disable-red-zone");
+ if (!Opts.DwarfDebugFlags.empty()) {
+ Res.push_back("-dwarf-debug-flags");
+ Res.push_back(Opts.DwarfDebugFlags);
+ }
+ if (!Opts.MergeAllConstants)
+ Res.push_back("-fno-merge-all-constants");
+ if (Opts.NoCommon)
+ Res.push_back("-fno-common");
+ if (Opts.NoImplicitFloat)
+ Res.push_back("-no-implicit-float");
+ if (Opts.OmitLeafFramePointer)
+ Res.push_back("-momit-leaf-frame-pointer");
+ if (Opts.OptimizeSize) {
+ assert(Opts.OptimizationLevel == 2 && "Invalid options!");
+ Res.push_back("-Os");
+ } else if (Opts.OptimizationLevel != 0)
+ Res.push_back("-O" + llvm::utostr(Opts.OptimizationLevel));
+ if (!Opts.MainFileName.empty()) {
+ Res.push_back("-main-file-name");
+ Res.push_back(Opts.MainFileName);
+ }
+ // SimplifyLibCalls is only derived.
+ // TimePasses is only derived.
+ // UnitAtATime is unused.
+ // UnrollLoops is only derived.
+ // Inlining is only derived.
+
+ if (Opts.DataSections)
+ Res.push_back("-fdata-sections");
+ if (Opts.FunctionSections)
+ Res.push_back("-ffunction-sections");
+ if (Opts.AsmVerbose)
+ Res.push_back("-masm-verbose");
+ if (!Opts.CodeModel.empty()) {
+ Res.push_back("-mcode-model");
+ Res.push_back(Opts.CodeModel);
+ }
+ if (!Opts.CXAAtExit)
+ Res.push_back("-fno-use-cxa-atexit");
+ if (Opts.CXXCtorDtorAliases)
+ Res.push_back("-mconstructor-aliases");
+ if (!Opts.DebugPass.empty()) {
+ Res.push_back("-mdebug-pass");
+ Res.push_back(Opts.DebugPass);
+ }
+ if (Opts.DisableFPElim)
+ Res.push_back("-mdisable-fp-elim");
+ if (!Opts.FloatABI.empty()) {
+ Res.push_back("-mfloat-abi");
+ Res.push_back(Opts.FloatABI);
+ }
+ if (!Opts.LimitFloatPrecision.empty()) {
+ Res.push_back("-mlimit-float-precision");
+ Res.push_back(Opts.LimitFloatPrecision);
+ }
+ if (Opts.NoZeroInitializedInBSS)
+ Res.push_back("-mno-zero-initialized-bss");
+ switch (Opts.getObjCDispatchMethod()) {
+ case CodeGenOptions::Legacy:
+ break;
+ case CodeGenOptions::Mixed:
+ Res.push_back("-fobjc-dispatch-method=mixed");
+ break;
+ case CodeGenOptions::NonLegacy:
+ Res.push_back("-fobjc-dispatch-method=non-legacy");
+ break;
+ }
+ if (Opts.RelaxAll)
+ Res.push_back("-mrelax-all");
+ if (Opts.SoftFloat)
+ Res.push_back("-msoft-float");
+ if (Opts.UnwindTables)
+ Res.push_back("-munwind-tables");
+ if (Opts.RelocationModel != "pic") {
+ Res.push_back("-mrelocation-model");
+ Res.push_back(Opts.RelocationModel);
+ }
+ if (!Opts.VerifyModule)
+ Res.push_back("-disable-llvm-verifier");
+}
+
+static void DependencyOutputOptsToArgs(const DependencyOutputOptions &Opts,
+ std::vector<std::string> &Res) {
+ if (Opts.IncludeSystemHeaders)
+ Res.push_back("-sys-header-deps");
+ if (Opts.UsePhonyTargets)
+ Res.push_back("-MP");
+ if (!Opts.OutputFile.empty()) {
+ Res.push_back("-dependency-file");
+ Res.push_back(Opts.OutputFile);
+ }
+ for (unsigned i = 0, e = Opts.Targets.size(); i != e; ++i) {
+ Res.push_back("-MT");
+ Res.push_back(Opts.Targets[i]);
+ }
+}
+
+static void DiagnosticOptsToArgs(const DiagnosticOptions &Opts,
+ std::vector<std::string> &Res) {
+ if (Opts.IgnoreWarnings)
+ Res.push_back("-w");
+ if (Opts.NoRewriteMacros)
+ Res.push_back("-Wno-rewrite-macros");
+ if (Opts.Pedantic)
+ Res.push_back("-pedantic");
+ if (Opts.PedanticErrors)
+ Res.push_back("-pedantic-errors");
+ if (!Opts.ShowColumn)
+ Res.push_back("-fno-show-column");
+ if (!Opts.ShowLocation)
+ Res.push_back("-fno-show-source-location");
+ if (!Opts.ShowCarets)
+ Res.push_back("-fno-caret-diagnostics");
+ if (!Opts.ShowFixits)
+ Res.push_back("-fno-diagnostics-fixit-info");
+ if (Opts.ShowSourceRanges)
+ Res.push_back("-fdiagnostics-print-source-range-info");
+ if (Opts.ShowColors)
+ Res.push_back("-fcolor-diagnostics");
+ if (Opts.VerifyDiagnostics)
+ Res.push_back("-verify");
+ if (Opts.BinaryOutput)
+ Res.push_back("-fdiagnostics-binary");
+ if (Opts.ShowOptionNames)
+ Res.push_back("-fdiagnostics-show-option");
+ if (Opts.ShowCategories == 1)
+ Res.push_back("-fdiagnostics-show-category=id");
+ else if (Opts.ShowCategories == 2)
+ Res.push_back("-fdiagnostics-show-category=name");
+ if (Opts.ErrorLimit) {
+ Res.push_back("-ferror-limit");
+ Res.push_back(llvm::utostr(Opts.ErrorLimit));
+ }
+ if (Opts.MacroBacktraceLimit
+ != DiagnosticOptions::DefaultMacroBacktraceLimit) {
+ Res.push_back("-fmacro-backtrace-limit");
+ Res.push_back(llvm::utostr(Opts.MacroBacktraceLimit));
+ }
+ if (Opts.TemplateBacktraceLimit
+ != DiagnosticOptions::DefaultTemplateBacktraceLimit) {
+ Res.push_back("-ftemplate-backtrace-limit");
+ Res.push_back(llvm::utostr(Opts.TemplateBacktraceLimit));
+ }
+
+ if (Opts.TabStop != DiagnosticOptions::DefaultTabStop) {
+ Res.push_back("-ftabstop");
+ Res.push_back(llvm::utostr(Opts.TabStop));
+ }
+ if (Opts.MessageLength) {
+ Res.push_back("-fmessage-length");
+ Res.push_back(llvm::utostr(Opts.MessageLength));
+ }
+ if (!Opts.DumpBuildInformation.empty()) {
+ Res.push_back("-dump-build-information");
+ Res.push_back(Opts.DumpBuildInformation);
+ }
+ for (unsigned i = 0, e = Opts.Warnings.size(); i != e; ++i)
+ Res.push_back("-W" + Opts.Warnings[i]);
+}
+
+static const char *getInputKindName(InputKind Kind) {
+ switch (Kind) {
+ case IK_None: break;
+ case IK_AST: return "ast";
+ case IK_Asm: return "assembler-with-cpp";
+ case IK_C: return "c";
+ case IK_CXX: return "c++";
+ case IK_LLVM_IR: return "ir";
+ case IK_ObjC: return "objective-c";
+ case IK_ObjCXX: return "objective-c++";
+ case IK_OpenCL: return "cl";
+ case IK_PreprocessedC: return "cpp-output";
+ case IK_PreprocessedCXX: return "c++-cpp-output";
+ case IK_PreprocessedObjC: return "objective-c-cpp-output";
+ case IK_PreprocessedObjCXX:return "objective-c++-cpp-output";
+ }
+
+ llvm_unreachable("Unexpected language kind!");
+ return 0;
+}
+
+static const char *getActionName(frontend::ActionKind Kind) {
+ switch (Kind) {
+ case frontend::PluginAction:
+ case frontend::InheritanceView:
+ llvm_unreachable("Invalid kind!");
+
+ case frontend::ASTDump: return "-ast-dump";
+ case frontend::ASTPrint: return "-ast-print";
+ case frontend::ASTPrintXML: return "-ast-print-xml";
+ case frontend::ASTView: return "-ast-view";
+ case frontend::BoostCon: return "-boostcon";
+ case frontend::DumpRawTokens: return "-dump-raw-tokens";
+ case frontend::DumpTokens: return "-dump-tokens";
+ case frontend::EmitAssembly: return "-S";
+ case frontend::EmitBC: return "-emit-llvm-bc";
+ case frontend::EmitHTML: return "-emit-html";
+ case frontend::EmitLLVM: return "-emit-llvm";
+ case frontend::EmitLLVMOnly: return "-emit-llvm-only";
+ case frontend::EmitCodeGenOnly: return "-emit-codegen-only";
+ case frontend::EmitObj: return "-emit-obj";
+ case frontend::FixIt: return "-fixit";
+ case frontend::GeneratePCH: return "-emit-pch";
+ case frontend::GeneratePTH: return "-emit-pth";
+ case frontend::InitOnly: return "-init-only";
+ case frontend::ParseNoop: return "-parse-noop";
+ case frontend::ParsePrintCallbacks: return "-parse-print-callbacks";
+ case frontend::ParseSyntaxOnly: return "-fsyntax-only";
+ case frontend::PrintDeclContext: return "-print-decl-contexts";
+ case frontend::PrintPreprocessedInput: return "-E";
+ case frontend::RewriteMacros: return "-rewrite-macros";
+ case frontend::RewriteObjC: return "-rewrite-objc";
+ case frontend::RewriteTest: return "-rewrite-test";
+ case frontend::RunAnalysis: return "-analyze";
+ case frontend::RunPreprocessorOnly: return "-Eonly";
+ }
+
+ llvm_unreachable("Unexpected language kind!");
+ return 0;
+}
+
+static void FrontendOptsToArgs(const FrontendOptions &Opts,
+ std::vector<std::string> &Res) {
+ if (!Opts.DebugCodeCompletionPrinter)
+ Res.push_back("-no-code-completion-debug-printer");
+ if (Opts.DisableFree)
+ Res.push_back("-disable-free");
+ if (Opts.RelocatablePCH)
+ Res.push_back("-relocatable-pch");
+ if (Opts.ChainedPCH)
+ Res.push_back("-chained-pch");
+ if (Opts.ShowHelp)
+ Res.push_back("-help");
+ if (Opts.ShowMacrosInCodeCompletion)
+ Res.push_back("-code-completion-macros");
+ if (Opts.ShowCodePatternsInCodeCompletion)
+ Res.push_back("-code-completion-patterns");
+ if (Opts.ShowStats)
+ Res.push_back("-print-stats");
+ if (Opts.ShowTimers)
+ Res.push_back("-ftime-report");
+ if (Opts.ShowVersion)
+ Res.push_back("-version");
+
+ bool NeedLang = false;
+ for (unsigned i = 0, e = Opts.Inputs.size(); i != e; ++i)
+ if (FrontendOptions::getInputKindForExtension(Opts.Inputs[i].second) !=
+ Opts.Inputs[i].first)
+ NeedLang = true;
+ if (NeedLang) {
+ Res.push_back("-x");
+ Res.push_back(getInputKindName(Opts.Inputs[0].first));
+ }
+ for (unsigned i = 0, e = Opts.Inputs.size(); i != e; ++i) {
+ assert((!NeedLang || Opts.Inputs[i].first == Opts.Inputs[0].first) &&
+ "Unable to represent this input vector!");
+ Res.push_back(Opts.Inputs[i].second);
+ }
+
+ if (!Opts.OutputFile.empty()) {
+ Res.push_back("-o");
+ Res.push_back(Opts.OutputFile);
+ }
+ if (!Opts.ViewClassInheritance.empty()) {
+ Res.push_back("-cxx-inheritance-view");
+ Res.push_back(Opts.ViewClassInheritance);
+ }
+ if (!Opts.CodeCompletionAt.FileName.empty()) {
+ Res.push_back("-code-completion-at");
+ Res.push_back(Opts.CodeCompletionAt.FileName + ":" +
+ llvm::utostr(Opts.CodeCompletionAt.Line) + ":" +
+ llvm::utostr(Opts.CodeCompletionAt.Column));
+ }
+ if (Opts.ProgramAction != frontend::InheritanceView &&
+ Opts.ProgramAction != frontend::PluginAction)
+ Res.push_back(getActionName(Opts.ProgramAction));
+ if (!Opts.ActionName.empty()) {
+ Res.push_back("-plugin");
+ Res.push_back(Opts.ActionName);
+ for(unsigned i = 0, e = Opts.PluginArgs.size(); i != e; ++i) {
+ Res.push_back("-plugin-arg-" + Opts.ActionName);
+ Res.push_back(Opts.PluginArgs[i]);
+ }
+ }
+ for (unsigned i = 0, e = Opts.Plugins.size(); i != e; ++i) {
+ Res.push_back("-load");
+ Res.push_back(Opts.Plugins[i]);
+ }
+ for (unsigned i = 0, e = Opts.ASTMergeFiles.size(); i != e; ++i) {
+ Res.push_back("-ast-merge");
+ Res.push_back(Opts.ASTMergeFiles[i]);
+ }
+ for (unsigned i = 0, e = Opts.LLVMArgs.size(); i != e; ++i) {
+ Res.push_back("-mllvm");
+ Res.push_back(Opts.LLVMArgs[i]);
+ }
+}
+
+static void HeaderSearchOptsToArgs(const HeaderSearchOptions &Opts,
+ std::vector<std::string> &Res) {
+ if (Opts.Sysroot != "/") {
+ Res.push_back("-isysroot");
+ Res.push_back(Opts.Sysroot);
+ }
+
+ /// User specified include entries.
+ for (unsigned i = 0, e = Opts.UserEntries.size(); i != e; ++i) {
+ const HeaderSearchOptions::Entry &E = Opts.UserEntries[i];
+ if (E.IsFramework && (E.Group != frontend::Angled || !E.IsUserSupplied))
+ llvm::report_fatal_error("Invalid option set!");
+ if (E.IsUserSupplied) {
+ if (E.Group == frontend::After) {
+ Res.push_back("-idirafter");
+ } else if (E.Group == frontend::Quoted) {
+ Res.push_back("-iquote");
+ } else if (E.Group == frontend::System) {
+ Res.push_back("-isystem");
+ } else {
+ assert(E.Group == frontend::Angled && "Invalid group!");
+ Res.push_back(E.IsFramework ? "-F" : "-I");
+ }
+ } else {
+ if (E.Group != frontend::Angled && E.Group != frontend::System)
+ llvm::report_fatal_error("Invalid option set!");
+ Res.push_back(E.Group == frontend::Angled ? "-iwithprefixbefore" :
+ "-iwithprefix");
+ }
+ Res.push_back(E.Path);
+ }
+
+ if (!Opts.EnvIncPath.empty()) {
+ // FIXME: Provide an option for this, and move env detection to driver.
+ llvm::report_fatal_error("Not yet implemented!");
+ }
+ if (!Opts.CEnvIncPath.empty()) {
+ // FIXME: Provide an option for this, and move env detection to driver.
+ llvm::report_fatal_error("Not yet implemented!");
+ }
+ if (!Opts.ObjCEnvIncPath.empty()) {
+ // FIXME: Provide an option for this, and move env detection to driver.
+ llvm::report_fatal_error("Not yet implemented!");
+ }
+ if (!Opts.CXXEnvIncPath.empty()) {
+ // FIXME: Provide an option for this, and move env detection to driver.
+ llvm::report_fatal_error("Not yet implemented!");
+ }
+ if (!Opts.ObjCXXEnvIncPath.empty()) {
+ // FIXME: Provide an option for this, and move env detection to driver.
+ llvm::report_fatal_error("Not yet implemented!");
+ }
+ if (!Opts.ResourceDir.empty()) {
+ Res.push_back("-resource-dir");
+ Res.push_back(Opts.ResourceDir);
+ }
+ if (!Opts.UseStandardIncludes)
+ Res.push_back("-nostdinc");
+ if (!Opts.UseStandardCXXIncludes)
+ Res.push_back("-nostdinc++");
+ if (Opts.Verbose)
+ Res.push_back("-v");
+}
+
+static void LangOptsToArgs(const LangOptions &Opts,
+ std::vector<std::string> &Res) {
+ LangOptions DefaultLangOpts;
+
+ // FIXME: Need to set -std to get all the implicit options.
+
+ // FIXME: We want to only pass options relative to the defaults, which
+ // requires constructing a target. :(
+ //
+ // It would be better to push the all target specific choices into the driver,
+ // so that everything below that was more uniform.
+
+ if (Opts.Trigraphs)
+ Res.push_back("-trigraphs");
+ // Implicit based on the input kind:
+ // AsmPreprocessor, CPlusPlus, ObjC1, ObjC2, OpenCL
+ // Implicit based on the input language standard:
+ // BCPLComment, C99, CPlusPlus0x, Digraphs, GNUInline, ImplicitInt, GNUMode
+ if (Opts.DollarIdents)
+ Res.push_back("-fdollars-in-identifiers");
+ if (Opts.GNUMode && !Opts.GNUKeywords)
+ Res.push_back("-fno-gnu-keywords");
+ if (!Opts.GNUMode && Opts.GNUKeywords)
+ Res.push_back("-fgnu-keywords");
+ if (Opts.Microsoft)
+ Res.push_back("-fms-extensions");
+ if (Opts.ObjCNonFragileABI)
+ Res.push_back("-fobjc-nonfragile-abi");
+ if (Opts.ObjCNonFragileABI2)
+ Res.push_back("-fobjc-nonfragile-abi2");
+ // NoInline is implicit.
+ if (!Opts.CXXOperatorNames)
+ Res.push_back("-fno-operator-names");
+ if (Opts.PascalStrings)
+ Res.push_back("-fpascal-strings");
+ if (Opts.CatchUndefined)
+ Res.push_back("-fcatch-undefined-behavior");
+ if (Opts.WritableStrings)
+ Res.push_back("-fwritable-strings");
+ if (Opts.ConstStrings)
+ Res.push_back("-Wwrite-strings");
+ if (!Opts.LaxVectorConversions)
+ Res.push_back("-fno-lax-vector-conversions");
+ if (Opts.AltiVec)
+ Res.push_back("-faltivec");
+ if (Opts.Exceptions)
+ Res.push_back("-fexceptions");
+ if (Opts.SjLjExceptions)
+ Res.push_back("-fsjlj-exceptions");
+ if (!Opts.RTTI)
+ Res.push_back("-fno-rtti");
+ if (!Opts.NeXTRuntime)
+ Res.push_back("-fgnu-runtime");
+ if (Opts.Freestanding)
+ Res.push_back("-ffreestanding");
+ if (Opts.FormatExtensions)
+ Res.push_back("-fformat-extensions");
+ if (Opts.NoBuiltin)
+ Res.push_back("-fno-builtin");
+ if (!Opts.AssumeSaneOperatorNew)
+ Res.push_back("-fno-assume-sane-operator-new");
+ if (!Opts.ThreadsafeStatics)
+ Res.push_back("-fno-threadsafe-statics");
+ if (Opts.POSIXThreads)
+ Res.push_back("-pthread");
+ if (Opts.Blocks)
+ Res.push_back("-fblocks");
+ if (Opts.EmitAllDecls)
+ Res.push_back("-femit-all-decls");
+ if (Opts.MathErrno)
+ Res.push_back("-fmath-errno");
+ switch (Opts.getSignedOverflowBehavior()) {
+ case LangOptions::SOB_Undefined: break;
+ case LangOptions::SOB_Defined: Res.push_back("-fwrapv"); break;
+ case LangOptions::SOB_Trapping: Res.push_back("-ftrapv"); break;
+ }
+ if (Opts.HeinousExtensions)
+ Res.push_back("-fheinous-gnu-extensions");
+ // Optimize is implicit.
+ // OptimizeSize is implicit.
+ if (Opts.Static)
+ Res.push_back("-static-define");
+ if (Opts.DumpRecordLayouts)
+ Res.push_back("-fdump-record-layouts");
+ if (Opts.DumpVTableLayouts)
+ Res.push_back("-fdump-vtable-layouts");
+ if (Opts.NoBitFieldTypeAlign)
+ Res.push_back("-fno-bitfield-type-alignment");
+ if (Opts.SjLjExceptions)
+ Res.push_back("-fsjlj-exceptions");
+ if (Opts.PICLevel) {
+ Res.push_back("-pic-level");
+ Res.push_back(llvm::utostr(Opts.PICLevel));
+ }
+ if (Opts.ObjCGCBitmapPrint)
+ Res.push_back("-print-ivar-layout");
+ if (Opts.NoConstantCFStrings)
+ Res.push_back("-fno-constant-cfstrings");
+ if (!Opts.AccessControl)
+ Res.push_back("-fno-access-control");
+ if (!Opts.CharIsSigned)
+ Res.push_back("-fno-signed-char");
+ if (Opts.ShortWChar)
+ Res.push_back("-fshort-wchar");
+ if (!Opts.ElideConstructors)
+ Res.push_back("-fno-elide-constructors");
+ if (Opts.getGCMode() != LangOptions::NonGC) {
+ if (Opts.getGCMode() == LangOptions::HybridGC) {
+ Res.push_back("-fobjc-gc");
+ } else {
+ assert(Opts.getGCMode() == LangOptions::GCOnly && "Invalid GC mode!");
+ Res.push_back("-fobjc-gc-only");
+ }
+ }
+ if (Opts.getVisibilityMode() != LangOptions::Default) {
+ Res.push_back("-fvisibility");
+ if (Opts.getVisibilityMode() == LangOptions::Hidden) {
+ Res.push_back("hidden");
+ } else {
+ assert(Opts.getVisibilityMode() == LangOptions::Protected &&
+ "Invalid visibility!");
+ Res.push_back("protected");
+ }
+ }
+ if (Opts.InlineVisibilityHidden)
+ Res.push_back("-fvisibility-inlines-hidden");
+
+ if (Opts.getStackProtectorMode() != 0) {
+ Res.push_back("-stack-protector");
+ Res.push_back(llvm::utostr(Opts.getStackProtectorMode()));
+ }
+ if (Opts.InstantiationDepth != DefaultLangOpts.InstantiationDepth) {
+ Res.push_back("-ftemplate-depth");
+ Res.push_back(llvm::utostr(Opts.InstantiationDepth));
+ }
+ if (!Opts.ObjCConstantStringClass.empty()) {
+ Res.push_back("-fconstant-string-class");
+ Res.push_back(Opts.ObjCConstantStringClass);
+ }
+}
+
+static void PreprocessorOptsToArgs(const PreprocessorOptions &Opts,
+ std::vector<std::string> &Res) {
+ for (unsigned i = 0, e = Opts.Macros.size(); i != e; ++i)
+ Res.push_back(std::string(Opts.Macros[i].second ? "-U" : "-D") +
+ Opts.Macros[i].first);
+ for (unsigned i = 0, e = Opts.Includes.size(); i != e; ++i) {
+ // FIXME: We need to avoid reincluding the implicit PCH and PTH includes.
+ Res.push_back("-include");
+ Res.push_back(Opts.Includes[i]);
+ }
+ for (unsigned i = 0, e = Opts.MacroIncludes.size(); i != e; ++i) {
+ Res.push_back("-imacros");
+ Res.push_back(Opts.MacroIncludes[i]);
+ }
+ if (!Opts.UsePredefines)
+ Res.push_back("-undef");
+ if (Opts.DetailedRecord)
+ Res.push_back("-detailed-preprocessing-record");
+ if (!Opts.ImplicitPCHInclude.empty()) {
+ Res.push_back("-include-pch");
+ Res.push_back(Opts.ImplicitPCHInclude);
+ }
+ if (!Opts.ImplicitPTHInclude.empty()) {
+ Res.push_back("-include-pth");
+ Res.push_back(Opts.ImplicitPTHInclude);
+ }
+ if (!Opts.TokenCache.empty()) {
+ if (Opts.ImplicitPTHInclude.empty()) {
+ Res.push_back("-token-cache");
+ Res.push_back(Opts.TokenCache);
+ } else
+ assert(Opts.ImplicitPTHInclude == Opts.TokenCache &&
+ "Unsupported option combination!");
+ }
+ for (unsigned i = 0, e = Opts.RemappedFiles.size(); i != e; ++i) {
+ Res.push_back("-remap-file");
+ Res.push_back(Opts.RemappedFiles[i].first + ";" +
+ Opts.RemappedFiles[i].second);
+ }
+}
+
+static void PreprocessorOutputOptsToArgs(const PreprocessorOutputOptions &Opts,
+ std::vector<std::string> &Res) {
+ if (!Opts.ShowCPP && !Opts.ShowMacros)
+ llvm::report_fatal_error("Invalid option combination!");
+
+ if (Opts.ShowCPP && Opts.ShowMacros)
+ Res.push_back("-dD");
+ else if (!Opts.ShowCPP && Opts.ShowMacros)
+ Res.push_back("-dM");
+
+ if (!Opts.ShowLineMarkers)
+ Res.push_back("-P");
+ if (Opts.ShowComments)
+ Res.push_back("-C");
+ if (Opts.ShowMacroComments)
+ Res.push_back("-CC");
+}
+
+static void TargetOptsToArgs(const TargetOptions &Opts,
+ std::vector<std::string> &Res) {
+ Res.push_back("-triple");
+ Res.push_back(Opts.Triple);
+ if (!Opts.CPU.empty()) {
+ Res.push_back("-target-cpu");
+ Res.push_back(Opts.CPU);
+ }
+ if (!Opts.ABI.empty()) {
+ Res.push_back("-target-abi");
+ Res.push_back(Opts.ABI);
+ }
+ Res.push_back("-cxx-abi");
+ Res.push_back(Opts.CXXABI);
+ for (unsigned i = 0, e = Opts.Features.size(); i != e; ++i) {
+ Res.push_back("-target-feature");
+ Res.push_back(Opts.Features[i]);
+ }
+}
+
+void CompilerInvocation::toArgs(std::vector<std::string> &Res) {
+ AnalyzerOptsToArgs(getAnalyzerOpts(), Res);
+ CodeGenOptsToArgs(getCodeGenOpts(), Res);
+ DependencyOutputOptsToArgs(getDependencyOutputOpts(), Res);
+ DiagnosticOptsToArgs(getDiagnosticOpts(), Res);
+ FrontendOptsToArgs(getFrontendOpts(), Res);
+ HeaderSearchOptsToArgs(getHeaderSearchOpts(), Res);
+ LangOptsToArgs(getLangOpts(), Res);
+ PreprocessorOptsToArgs(getPreprocessorOpts(), Res);
+ PreprocessorOutputOptsToArgs(getPreprocessorOutputOpts(), Res);
+ TargetOptsToArgs(getTargetOpts(), Res);
+}
+
+//===----------------------------------------------------------------------===//
+// Deserialization (to args)
+//===----------------------------------------------------------------------===//
+
+using namespace clang::driver;
+using namespace clang::driver::cc1options;
+
+//
+
+static void ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
+ Diagnostic &Diags) {
+ using namespace cc1options;
+
+ Opts.AnalysisList.clear();
+#define ANALYSIS(NAME, CMDFLAG, DESC, SCOPE) \
+ if (Args.hasArg(OPT_analysis_##NAME)) Opts.AnalysisList.push_back(NAME);
+#include "clang/Frontend/Analyses.def"
+
+ if (Arg *A = Args.getLastArg(OPT_analyzer_store)) {
+ llvm::StringRef Name = A->getValue(Args);
+ AnalysisStores Value = llvm::StringSwitch<AnalysisStores>(Name)
+#define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATFN) \
+ .Case(CMDFLAG, NAME##Model)
+#include "clang/Frontend/Analyses.def"
+ .Default(NumStores);
+ // FIXME: Error handling.
+ if (Value == NumStores)
+ Diags.Report(diag::err_drv_invalid_value)
+ << A->getAsString(Args) << Name;
+ else
+ Opts.AnalysisStoreOpt = Value;
+ }
+
+ if (Arg *A = Args.getLastArg(OPT_analyzer_constraints)) {
+ llvm::StringRef Name = A->getValue(Args);
+ AnalysisConstraints Value = llvm::StringSwitch<AnalysisConstraints>(Name)
+#define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATFN) \
+ .Case(CMDFLAG, NAME##Model)
+#include "clang/Frontend/Analyses.def"
+ .Default(NumConstraints);
+ // FIXME: Error handling.
+ if (Value == NumConstraints)
+ Diags.Report(diag::err_drv_invalid_value)
+ << A->getAsString(Args) << Name;
+ else
+ Opts.AnalysisConstraintsOpt = Value;
+ }
+
+ if (Arg *A = Args.getLastArg(OPT_analyzer_output)) {
+ llvm::StringRef Name = A->getValue(Args);
+ AnalysisDiagClients Value = llvm::StringSwitch<AnalysisDiagClients>(Name)
+#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATFN, AUTOCREAT) \
+ .Case(CMDFLAG, PD_##NAME)
+#include "clang/Frontend/Analyses.def"
+ .Default(NUM_ANALYSIS_DIAG_CLIENTS);
+ // FIXME: Error handling.
+ if (Value == NUM_ANALYSIS_DIAG_CLIENTS)
+ Diags.Report(diag::err_drv_invalid_value)
+ << A->getAsString(Args) << Name;
+ else
+ Opts.AnalysisDiagOpt = Value;
+ }
+
+ Opts.VisualizeEGDot = Args.hasArg(OPT_analyzer_viz_egraph_graphviz);
+ Opts.VisualizeEGUbi = Args.hasArg(OPT_analyzer_viz_egraph_ubigraph);
+ Opts.AnalyzeAll = Args.hasArg(OPT_analyzer_opt_analyze_headers);
+ Opts.AnalyzerDisplayProgress = Args.hasArg(OPT_analyzer_display_progress);
+ Opts.AnalyzeNestedBlocks =
+ Args.hasArg(OPT_analyzer_opt_analyze_nested_blocks);
+ Opts.PurgeDead = !Args.hasArg(OPT_analyzer_no_purge_dead);
+ Opts.EagerlyAssume = Args.hasArg(OPT_analyzer_eagerly_assume);
+ Opts.AnalyzeSpecificFunction = Args.getLastArgValue(OPT_analyze_function);
+ Opts.EnableExperimentalChecks = Args.hasArg(OPT_analyzer_experimental_checks);
+ Opts.EnableExperimentalInternalChecks =
+ Args.hasArg(OPT_analyzer_experimental_internal_checks);
+ Opts.EnableIdempotentOperationChecker =
+ Args.hasArg(OPT_analyzer_idempotent_operation);
+ Opts.TrimGraph = Args.hasArg(OPT_trim_egraph);
+ Opts.MaxNodes = Args.getLastArgIntValue(OPT_analyzer_max_nodes, 150000,Diags);
+ Opts.MaxLoop = Args.getLastArgIntValue(OPT_analyzer_max_loop, 3, Diags);
+ Opts.InlineCall = Args.hasArg(OPT_analyzer_inline_call);
+}
+
+static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
+ Diagnostic &Diags) {
+ using namespace cc1options;
+ // -Os implies -O2
+ if (Args.hasArg(OPT_Os))
+ Opts.OptimizationLevel = 2;
+ else {
+ Opts.OptimizationLevel = Args.getLastArgIntValue(OPT_O, 0, Diags);
+ if (Opts.OptimizationLevel > 3) {
+ Diags.Report(diag::err_drv_invalid_value)
+ << Args.getLastArg(OPT_O)->getAsString(Args) << Opts.OptimizationLevel;
+ Opts.OptimizationLevel = 3;
+ }
+ }
+
+ // We must always run at least the always inlining pass.
+ Opts.Inlining = (Opts.OptimizationLevel > 1) ? CodeGenOptions::NormalInlining
+ : CodeGenOptions::OnlyAlwaysInlining;
+
+ Opts.DebugInfo = Args.hasArg(OPT_g);
+ Opts.DisableLLVMOpts = Args.hasArg(OPT_disable_llvm_optzns);
+ Opts.DisableRedZone = Args.hasArg(OPT_disable_red_zone);
+ Opts.DwarfDebugFlags = Args.getLastArgValue(OPT_dwarf_debug_flags);
+ Opts.MergeAllConstants = !Args.hasArg(OPT_fno_merge_all_constants);
+ Opts.NoCommon = Args.hasArg(OPT_fno_common);
+ Opts.NoImplicitFloat = Args.hasArg(OPT_no_implicit_float);
+ Opts.OptimizeSize = Args.hasArg(OPT_Os);
+ Opts.SimplifyLibCalls = !(Args.hasArg(OPT_fno_builtin) ||
+ Args.hasArg(OPT_ffreestanding));
+ Opts.UnrollLoops = (Opts.OptimizationLevel > 1 && !Opts.OptimizeSize);
+
+ Opts.AsmVerbose = Args.hasArg(OPT_masm_verbose);
+ Opts.CXAAtExit = !Args.hasArg(OPT_fno_use_cxa_atexit);
+ Opts.CXXCtorDtorAliases = Args.hasArg(OPT_mconstructor_aliases);
+ Opts.CodeModel = Args.getLastArgValue(OPT_mcode_model);
+ Opts.DebugPass = Args.getLastArgValue(OPT_mdebug_pass);
+ Opts.DisableFPElim = Args.hasArg(OPT_mdisable_fp_elim);
+ Opts.FloatABI = Args.getLastArgValue(OPT_mfloat_abi);
+ Opts.LimitFloatPrecision = Args.getLastArgValue(OPT_mlimit_float_precision);
+ Opts.NoZeroInitializedInBSS = Args.hasArg(OPT_mno_zero_initialized_in_bss);
+ Opts.RelaxAll = Args.hasArg(OPT_mrelax_all);
+ Opts.OmitLeafFramePointer = Args.hasArg(OPT_momit_leaf_frame_pointer);
+ Opts.SoftFloat = Args.hasArg(OPT_msoft_float);
+ Opts.UnwindTables = Args.hasArg(OPT_munwind_tables);
+ Opts.RelocationModel = Args.getLastArgValue(OPT_mrelocation_model, "pic");
+
+ Opts.FunctionSections = Args.hasArg(OPT_ffunction_sections);
+ Opts.DataSections = Args.hasArg(OPT_fdata_sections);
+
+ Opts.MainFileName = Args.getLastArgValue(OPT_main_file_name);
+ Opts.VerifyModule = !Args.hasArg(OPT_disable_llvm_verifier);
+
+ Opts.InstrumentFunctions = Args.hasArg(OPT_finstrument_functions);
+
+ if (Arg *A = Args.getLastArg(OPT_fobjc_dispatch_method_EQ)) {
+ llvm::StringRef Name = A->getValue(Args);
+ unsigned Method = llvm::StringSwitch<unsigned>(Name)
+ .Case("legacy", CodeGenOptions::Legacy)
+ .Case("non-legacy", CodeGenOptions::NonLegacy)
+ .Case("mixed", CodeGenOptions::Mixed)
+ .Default(~0U);
+ if (Method == ~0U)
+ Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Name;
+ else
+ Opts.ObjCDispatchMethod = Method;
+ }
+}
+
+static void ParseDependencyOutputArgs(DependencyOutputOptions &Opts,
+ ArgList &Args) {
+ using namespace cc1options;
+ Opts.OutputFile = Args.getLastArgValue(OPT_dependency_file);
+ Opts.Targets = Args.getAllArgValues(OPT_MT);
+ Opts.IncludeSystemHeaders = Args.hasArg(OPT_sys_header_deps);
+ Opts.UsePhonyTargets = Args.hasArg(OPT_MP);
+}
+
+static void ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args,
+ Diagnostic &Diags) {
+ using namespace cc1options;
+ Opts.IgnoreWarnings = Args.hasArg(OPT_w);
+ Opts.NoRewriteMacros = Args.hasArg(OPT_Wno_rewrite_macros);
+ Opts.Pedantic = Args.hasArg(OPT_pedantic);
+ Opts.PedanticErrors = Args.hasArg(OPT_pedantic_errors);
+ Opts.ShowCarets = !Args.hasArg(OPT_fno_caret_diagnostics);
+ Opts.ShowColors = Args.hasArg(OPT_fcolor_diagnostics);
+ Opts.ShowColumn = !Args.hasArg(OPT_fno_show_column);
+ Opts.ShowFixits = !Args.hasArg(OPT_fno_diagnostics_fixit_info);
+ Opts.ShowLocation = !Args.hasArg(OPT_fno_show_source_location);
+ Opts.ShowOptionNames = Args.hasArg(OPT_fdiagnostics_show_option);
+
+ llvm::StringRef ShowOverloads =
+ Args.getLastArgValue(OPT_fshow_overloads_EQ, "all");
+ if (ShowOverloads == "best")
+ Opts.ShowOverloads = Diagnostic::Ovl_Best;
+ else if (ShowOverloads == "all")
+ Opts.ShowOverloads = Diagnostic::Ovl_All;
+ else
+ Diags.Report(diag::err_drv_invalid_value)
+ << Args.getLastArg(OPT_fshow_overloads_EQ)->getAsString(Args)
+ << ShowOverloads;
+
+ llvm::StringRef ShowCategory =
+ Args.getLastArgValue(OPT_fdiagnostics_show_category, "none");
+ if (ShowCategory == "none")
+ Opts.ShowCategories = 0;
+ else if (ShowCategory == "id")
+ Opts.ShowCategories = 1;
+ else if (ShowCategory == "name")
+ Opts.ShowCategories = 2;
+ else
+ Diags.Report(diag::err_drv_invalid_value)
+ << Args.getLastArg(OPT_fdiagnostics_show_category)->getAsString(Args)
+ << ShowCategory;
+
+ Opts.ShowSourceRanges = Args.hasArg(OPT_fdiagnostics_print_source_range_info);
+ Opts.VerifyDiagnostics = Args.hasArg(OPT_verify);
+ Opts.BinaryOutput = Args.hasArg(OPT_fdiagnostics_binary);
+ Opts.ErrorLimit = Args.getLastArgIntValue(OPT_ferror_limit, 0, Diags);
+ Opts.MacroBacktraceLimit
+ = Args.getLastArgIntValue(OPT_fmacro_backtrace_limit,
+ DiagnosticOptions::DefaultMacroBacktraceLimit, Diags);
+ Opts.TemplateBacktraceLimit
+ = Args.getLastArgIntValue(OPT_ftemplate_backtrace_limit,
+ DiagnosticOptions::DefaultTemplateBacktraceLimit,
+ Diags);
+ Opts.TabStop = Args.getLastArgIntValue(OPT_ftabstop,
+ DiagnosticOptions::DefaultTabStop, Diags);
+ if (Opts.TabStop == 0 || Opts.TabStop > DiagnosticOptions::MaxTabStop) {
+ Diags.Report(diag::warn_ignoring_ftabstop_value)
+ << Opts.TabStop << DiagnosticOptions::DefaultTabStop;
+ Opts.TabStop = DiagnosticOptions::DefaultTabStop;
+ }
+ Opts.MessageLength = Args.getLastArgIntValue(OPT_fmessage_length, 0, Diags);
+ Opts.DumpBuildInformation = Args.getLastArgValue(OPT_dump_build_information);
+ Opts.Warnings = Args.getAllArgValues(OPT_W);
+}
+
+static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
+ Diagnostic &Diags) {
+ using namespace cc1options;
+ Opts.ProgramAction = frontend::ParseSyntaxOnly;
+ if (const Arg *A = Args.getLastArg(OPT_Action_Group)) {
+ switch (A->getOption().getID()) {
+ default:
+ assert(0 && "Invalid option in group!");
+ case OPT_ast_dump:
+ Opts.ProgramAction = frontend::ASTDump; break;
+ case OPT_ast_print:
+ Opts.ProgramAction = frontend::ASTPrint; break;
+ case OPT_ast_print_xml:
+ Opts.ProgramAction = frontend::ASTPrintXML; break;
+ case OPT_ast_view:
+ Opts.ProgramAction = frontend::ASTView; break;
+ case OPT_boostcon:
+ Opts.ProgramAction = frontend::BoostCon; break;
+ case OPT_dump_raw_tokens:
+ Opts.ProgramAction = frontend::DumpRawTokens; break;
+ case OPT_dump_tokens:
+ Opts.ProgramAction = frontend::DumpTokens; break;
+ case OPT_S:
+ Opts.ProgramAction = frontend::EmitAssembly; break;
+ case OPT_emit_llvm_bc:
+ Opts.ProgramAction = frontend::EmitBC; break;
+ case OPT_emit_html:
+ Opts.ProgramAction = frontend::EmitHTML; break;
+ case OPT_emit_llvm:
+ Opts.ProgramAction = frontend::EmitLLVM; break;
+ case OPT_emit_llvm_only:
+ Opts.ProgramAction = frontend::EmitLLVMOnly; break;
+ case OPT_emit_codegen_only:
+ Opts.ProgramAction = frontend::EmitCodeGenOnly; break;
+ case OPT_emit_obj:
+ Opts.ProgramAction = frontend::EmitObj; break;
+ case OPT_fixit_EQ:
+ Opts.FixItSuffix = A->getValue(Args);
+ // fall-through!
+ case OPT_fixit:
+ Opts.ProgramAction = frontend::FixIt; break;
+ case OPT_emit_pch:
+ Opts.ProgramAction = frontend::GeneratePCH; break;
+ case OPT_emit_pth:
+ Opts.ProgramAction = frontend::GeneratePTH; break;
+ case OPT_init_only:
+ Opts.ProgramAction = frontend::InitOnly; break;
+ case OPT_parse_noop:
+ Opts.ProgramAction = frontend::ParseNoop; break;
+ case OPT_parse_print_callbacks:
+ Opts.ProgramAction = frontend::ParsePrintCallbacks; break;
+ case OPT_fsyntax_only:
+ Opts.ProgramAction = frontend::ParseSyntaxOnly; break;
+ case OPT_print_decl_contexts:
+ Opts.ProgramAction = frontend::PrintDeclContext; break;
+ case OPT_E:
+ Opts.ProgramAction = frontend::PrintPreprocessedInput; break;
+ case OPT_rewrite_macros:
+ Opts.ProgramAction = frontend::RewriteMacros; break;
+ case OPT_rewrite_objc:
+ Opts.ProgramAction = frontend::RewriteObjC; break;
+ case OPT_rewrite_test:
+ Opts.ProgramAction = frontend::RewriteTest; break;
+ case OPT_analyze:
+ Opts.ProgramAction = frontend::RunAnalysis; break;
+ case OPT_Eonly:
+ Opts.ProgramAction = frontend::RunPreprocessorOnly; break;
+ }
+ }
+
+ if (const Arg* A = Args.getLastArg(OPT_plugin)) {
+ Opts.Plugins.push_back(A->getValue(Args,0));
+ Opts.ProgramAction = frontend::PluginAction;
+ Opts.ActionName = A->getValue(Args);
+
+ for (arg_iterator it = Args.filtered_begin(OPT_plugin_arg),
+ end = Args.filtered_end(); it != end; ++it) {
+ if ((*it)->getValue(Args, 0) == Opts.ActionName)
+ Opts.PluginArgs.push_back((*it)->getValue(Args, 1));
+ }
+ }
+
+ if (const Arg *A = Args.getLastArg(OPT_code_completion_at)) {
+ Opts.CodeCompletionAt =
+ ParsedSourceLocation::FromString(A->getValue(Args));
+ if (Opts.CodeCompletionAt.FileName.empty())
+ Diags.Report(diag::err_drv_invalid_value)
+ << A->getAsString(Args) << A->getValue(Args);
+ }
+ Opts.DebugCodeCompletionPrinter =
+ !Args.hasArg(OPT_no_code_completion_debug_printer);
+ Opts.DisableFree = Args.hasArg(OPT_disable_free);
+
+ Opts.OutputFile = Args.getLastArgValue(OPT_o);
+ Opts.Plugins = Args.getAllArgValues(OPT_load);
+ Opts.RelocatablePCH = Args.hasArg(OPT_relocatable_pch);
+ Opts.ChainedPCH = Args.hasArg(OPT_chained_pch);
+ Opts.ShowHelp = Args.hasArg(OPT_help);
+ Opts.ShowMacrosInCodeCompletion = Args.hasArg(OPT_code_completion_macros);
+ Opts.ShowCodePatternsInCodeCompletion
+ = Args.hasArg(OPT_code_completion_patterns);
+ Opts.ShowStats = Args.hasArg(OPT_print_stats);
+ Opts.ShowTimers = Args.hasArg(OPT_ftime_report);
+ Opts.ShowVersion = Args.hasArg(OPT_version);
+ Opts.ViewClassInheritance = Args.getLastArgValue(OPT_cxx_inheritance_view);
+ Opts.ASTMergeFiles = Args.getAllArgValues(OPT_ast_merge);
+ Opts.LLVMArgs = Args.getAllArgValues(OPT_mllvm);
+
+ InputKind DashX = IK_None;
+ if (const Arg *A = Args.getLastArg(OPT_x)) {
+ DashX = llvm::StringSwitch<InputKind>(A->getValue(Args))
+ .Case("c", IK_C)
+ .Case("cl", IK_OpenCL)
+ .Case("c", IK_C)
+ .Case("cl", IK_OpenCL)
+ .Case("c++", IK_CXX)
+ .Case("objective-c", IK_ObjC)
+ .Case("objective-c++", IK_ObjCXX)
+ .Case("cpp-output", IK_PreprocessedC)
+ .Case("assembler-with-cpp", IK_Asm)
+ .Case("c++-cpp-output", IK_PreprocessedCXX)
+ .Case("objective-c-cpp-output", IK_PreprocessedObjC)
+ .Case("objective-c++-cpp-output", IK_PreprocessedObjCXX)
+ .Case("c-header", IK_C)
+ .Case("objective-c-header", IK_ObjC)
+ .Case("c++-header", IK_CXX)
+ .Case("objective-c++-header", IK_ObjCXX)
+ .Case("ast", IK_AST)
+ .Case("ir", IK_LLVM_IR)
+ .Default(IK_None);
+ if (DashX == IK_None)
+ Diags.Report(diag::err_drv_invalid_value)
+ << A->getAsString(Args) << A->getValue(Args);
+ }
+
+ // '-' is the default input if none is given.
+ std::vector<std::string> Inputs = Args.getAllArgValues(OPT_INPUT);
+ Opts.Inputs.clear();
+ if (Inputs.empty())
+ Inputs.push_back("-");
+ for (unsigned i = 0, e = Inputs.size(); i != e; ++i) {
+ InputKind IK = DashX;
+ if (IK == IK_None) {
+ IK = FrontendOptions::getInputKindForExtension(
+ llvm::StringRef(Inputs[i]).rsplit('.').second);
+ // FIXME: Remove this hack.
+ if (i == 0)
+ DashX = IK;
+ }
+ Opts.Inputs.push_back(std::make_pair(IK, Inputs[i]));
+ }
+
+ return DashX;
+}
+
+std::string CompilerInvocation::GetResourcesPath(const char *Argv0,
+ void *MainAddr) {
+ llvm::sys::Path P = llvm::sys::Path::GetMainExecutable(Argv0, MainAddr);
+
+ if (!P.isEmpty()) {
+ P.eraseComponent(); // Remove /clang from foo/bin/clang
+ P.eraseComponent(); // Remove /bin from foo/bin
+
+ // Get foo/lib/clang/<version>/include
+ P.appendComponent("lib");
+ P.appendComponent("clang");
+ P.appendComponent(CLANG_VERSION_STRING);
+ }
+
+ return P.str();
+}
+
+static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) {
+ using namespace cc1options;
+ Opts.Sysroot = Args.getLastArgValue(OPT_isysroot, "/");
+ Opts.Verbose = Args.hasArg(OPT_v);
+ Opts.UseBuiltinIncludes = !Args.hasArg(OPT_nobuiltininc);
+ Opts.UseStandardIncludes = !Args.hasArg(OPT_nostdinc);
+ Opts.UseStandardCXXIncludes = !Args.hasArg(OPT_nostdincxx);
+ Opts.ResourceDir = Args.getLastArgValue(OPT_resource_dir);
+
+ // Add -I... and -F... options in order.
+ for (arg_iterator it = Args.filtered_begin(OPT_I, OPT_F),
+ ie = Args.filtered_end(); it != ie; ++it)
+ Opts.AddPath((*it)->getValue(Args), frontend::Angled, true,
+ /*IsFramework=*/ (*it)->getOption().matches(OPT_F));
+
+ // Add -iprefix/-iwith-prefix/-iwithprefixbefore options.
+ llvm::StringRef Prefix = ""; // FIXME: This isn't the correct default prefix.
+ for (arg_iterator it = Args.filtered_begin(OPT_iprefix, OPT_iwithprefix,
+ OPT_iwithprefixbefore),
+ ie = Args.filtered_end(); it != ie; ++it) {
+ const Arg *A = *it;
+ if (A->getOption().matches(OPT_iprefix))
+ Prefix = A->getValue(Args);
+ else if (A->getOption().matches(OPT_iwithprefix))
+ Opts.AddPath(Prefix.str() + A->getValue(Args),
+ frontend::System, false, false);
+ else
+ Opts.AddPath(Prefix.str() + A->getValue(Args),
+ frontend::Angled, false, false);
+ }
+
+ for (arg_iterator it = Args.filtered_begin(OPT_idirafter),
+ ie = Args.filtered_end(); it != ie; ++it)
+ Opts.AddPath((*it)->getValue(Args), frontend::After, true, false);
+ for (arg_iterator it = Args.filtered_begin(OPT_iquote),
+ ie = Args.filtered_end(); it != ie; ++it)
+ Opts.AddPath((*it)->getValue(Args), frontend::Quoted, true, false);
+ for (arg_iterator it = Args.filtered_begin(OPT_isystem),
+ ie = Args.filtered_end(); it != ie; ++it)
+ Opts.AddPath((*it)->getValue(Args), frontend::System, true, false);
+
+ // FIXME: Need options for the various environment variables!
+}
+
+static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
+ Diagnostic &Diags) {
+ // FIXME: Cleanup per-file based stuff.
+
+ // Set some properties which depend soley on the input kind; it would be nice
+ // to move these to the language standard, and have the driver resolve the
+ // input kind + language standard.
+ if (IK == IK_Asm) {
+ Opts.AsmPreprocessor = 1;
+ } else if (IK == IK_ObjC ||
+ IK == IK_ObjCXX ||
+ IK == IK_PreprocessedObjC ||
+ IK == IK_PreprocessedObjCXX) {
+ Opts.ObjC1 = Opts.ObjC2 = 1;
+ }
+
+ LangStandard::Kind LangStd = LangStandard::lang_unspecified;
+ if (const Arg *A = Args.getLastArg(OPT_std_EQ)) {
+ LangStd = llvm::StringSwitch<LangStandard::Kind>(A->getValue(Args))
+#define LANGSTANDARD(id, name, desc, features) \
+ .Case(name, LangStandard::lang_##id)
+#include "clang/Frontend/LangStandards.def"
+ .Default(LangStandard::lang_unspecified);
+ if (LangStd == LangStandard::lang_unspecified)
+ Diags.Report(diag::err_drv_invalid_value)
+ << A->getAsString(Args) << A->getValue(Args);
+ }
+
+ if (LangStd == LangStandard::lang_unspecified) {
+ // Based on the base language, pick one.
+ switch (IK) {
+ case IK_None:
+ case IK_AST:
+ case IK_LLVM_IR:
+ assert(0 && "Invalid input kind!");
+ case IK_OpenCL:
+ LangStd = LangStandard::lang_opencl;
+ break;
+ case IK_Asm:
+ case IK_C:
+ case IK_PreprocessedC:
+ case IK_ObjC:
+ case IK_PreprocessedObjC:
+ LangStd = LangStandard::lang_gnu99;
+ break;
+ case IK_CXX:
+ case IK_PreprocessedCXX:
+ case IK_ObjCXX:
+ case IK_PreprocessedObjCXX:
+ LangStd = LangStandard::lang_gnucxx98;
+ break;
+ }
+ }
+
+ const LangStandard &Std = LangStandard::getLangStandardForKind(LangStd);
+ Opts.BCPLComment = Std.hasBCPLComments();
+ Opts.C99 = Std.isC99();
+ Opts.CPlusPlus = Std.isCPlusPlus();
+ Opts.CPlusPlus0x = Std.isCPlusPlus0x();
+ Opts.Digraphs = Std.hasDigraphs();
+ Opts.GNUMode = Std.isGNUMode();
+ Opts.GNUInline = !Std.isC99();
+ Opts.HexFloats = Std.hasHexFloats();
+ Opts.ImplicitInt = Std.hasImplicitInt();
+
+ // OpenCL has some additional defaults.
+ if (LangStd == LangStandard::lang_opencl) {
+ Opts.OpenCL = 1;
+ Opts.AltiVec = 1;
+ Opts.CXXOperatorNames = 1;
+ Opts.LaxVectorConversions = 1;
+ }
+
+ // OpenCL and C++ both have bool, true, false keywords.
+ Opts.Bool = Opts.OpenCL || Opts.CPlusPlus;
+
+ // We abuse '-f[no-]gnu-keywords' to force overriding all GNU-extension
+ // keywords. This behavior is provided by GCC's poorly named '-fasm' flag,
+ // while a subset (the non-C++ GNU keywords) is provided by GCC's
+ // '-fgnu-keywords'. Clang conflates the two for simplicity under the single
+ // name, as it doesn't seem a useful distinction.
+ Opts.GNUKeywords = Args.hasFlag(OPT_fgnu_keywords, OPT_fno_gnu_keywords,
+ Opts.GNUMode);
+
+ if (Opts.CPlusPlus)
+ Opts.CXXOperatorNames = !Args.hasArg(OPT_fno_operator_names);
+
+ if (Args.hasArg(OPT_fobjc_gc_only))
+ Opts.setGCMode(LangOptions::GCOnly);
+ else if (Args.hasArg(OPT_fobjc_gc))
+ Opts.setGCMode(LangOptions::HybridGC);
+
+ if (Args.hasArg(OPT_print_ivar_layout))
+ Opts.ObjCGCBitmapPrint = 1;
+ if (Args.hasArg(OPT_fno_constant_cfstrings))
+ Opts.NoConstantCFStrings = 1;
+
+ if (Args.hasArg(OPT_faltivec))
+ Opts.AltiVec = 1;
+
+ if (Args.hasArg(OPT_pthread))
+ Opts.POSIXThreads = 1;
+
+ llvm::StringRef Vis = Args.getLastArgValue(OPT_fvisibility, "default");
+ if (Vis == "default")
+ Opts.setVisibilityMode(LangOptions::Default);
+ else if (Vis == "hidden")
+ Opts.setVisibilityMode(LangOptions::Hidden);
+ else if (Vis == "protected")
+ Opts.setVisibilityMode(LangOptions::Protected);
+ else
+ Diags.Report(diag::err_drv_invalid_value)
+ << Args.getLastArg(OPT_fvisibility)->getAsString(Args) << Vis;
+
+ if (Args.hasArg(OPT_fvisibility_inlines_hidden))
+ Opts.InlineVisibilityHidden = 1;
+
+ if (Args.hasArg(OPT_ftrapv))
+ Opts.setSignedOverflowBehavior(LangOptions::SOB_Trapping);
+ else if (Args.hasArg(OPT_fwrapv))
+ Opts.setSignedOverflowBehavior(LangOptions::SOB_Defined);
+
+ // Mimicing gcc's behavior, trigraphs are only enabled if -trigraphs
+ // is specified, or -std is set to a conforming mode.
+ Opts.Trigraphs = !Opts.GNUMode;
+ if (Args.hasArg(OPT_trigraphs))
+ Opts.Trigraphs = 1;
+
+ Opts.DollarIdents = Args.hasFlag(OPT_fdollars_in_identifiers,
+ OPT_fno_dollars_in_identifiers,
+ !Opts.AsmPreprocessor);
+ Opts.PascalStrings = Args.hasArg(OPT_fpascal_strings);
+ Opts.Microsoft = Args.hasArg(OPT_fms_extensions);
+ Opts.WritableStrings = Args.hasArg(OPT_fwritable_strings);
+ Opts.ConstStrings = Args.hasArg(OPT_Wwrite_strings);
+ if (Args.hasArg(OPT_fno_lax_vector_conversions))
+ Opts.LaxVectorConversions = 0;
+ if (Args.hasArg(OPT_fno_threadsafe_statics))
+ Opts.ThreadsafeStatics = 0;
+ Opts.Exceptions = Args.hasArg(OPT_fexceptions);
+ Opts.RTTI = !Args.hasArg(OPT_fno_rtti);
+ Opts.Blocks = Args.hasArg(OPT_fblocks);
+ Opts.CharIsSigned = !Args.hasArg(OPT_fno_signed_char);
+ Opts.ShortWChar = Args.hasArg(OPT_fshort_wchar);
+ Opts.Freestanding = Args.hasArg(OPT_ffreestanding);
+ Opts.FormatExtensions = Args.hasArg(OPT_fformat_extensions);
+ Opts.NoBuiltin = Args.hasArg(OPT_fno_builtin) || Opts.Freestanding;
+ Opts.AssumeSaneOperatorNew = !Args.hasArg(OPT_fno_assume_sane_operator_new);
+ Opts.HeinousExtensions = Args.hasArg(OPT_fheinous_gnu_extensions);
+ Opts.AccessControl = !Args.hasArg(OPT_fno_access_control);
+ Opts.ElideConstructors = !Args.hasArg(OPT_fno_elide_constructors);
+ Opts.MathErrno = Args.hasArg(OPT_fmath_errno);
+ Opts.InstantiationDepth = Args.getLastArgIntValue(OPT_ftemplate_depth, 1024,
+ Diags);
+ Opts.NeXTRuntime = !Args.hasArg(OPT_fgnu_runtime);
+ Opts.ObjCConstantStringClass =
+ Args.getLastArgValue(OPT_fconstant_string_class);
+ Opts.ObjCNonFragileABI = Args.hasArg(OPT_fobjc_nonfragile_abi);
+ Opts.ObjCNonFragileABI2 = Args.hasArg(OPT_fobjc_nonfragile_abi2);
+ if (Opts.ObjCNonFragileABI2)
+ Opts.ObjCNonFragileABI = true;
+ Opts.CatchUndefined = Args.hasArg(OPT_fcatch_undefined_behavior);
+ Opts.EmitAllDecls = Args.hasArg(OPT_femit_all_decls);
+ Opts.PICLevel = Args.getLastArgIntValue(OPT_pic_level, 0, Diags);
+ Opts.SjLjExceptions = Args.hasArg(OPT_fsjlj_exceptions);
+ Opts.Static = Args.hasArg(OPT_static_define);
+ Opts.DumpRecordLayouts = Args.hasArg(OPT_fdump_record_layouts);
+ Opts.DumpVTableLayouts = Args.hasArg(OPT_fdump_vtable_layouts);
+ Opts.SpellChecking = !Args.hasArg(OPT_fno_spell_checking);
+ Opts.NoBitFieldTypeAlign = Args.hasArg(OPT_fno_bitfield_type_align);
+ Opts.OptimizeSize = 0;
+
+ // FIXME: Eliminate this dependency.
+ unsigned Opt =
+ Args.hasArg(OPT_Os) ? 2 : Args.getLastArgIntValue(OPT_O, 0, Diags);
+ Opts.Optimize = Opt != 0;
+
+ // This is the __NO_INLINE__ define, which just depends on things like the
+ // optimization level and -fno-inline, not actually whether the backend has
+ // inlining enabled.
+ //
+ // FIXME: This is affected by other options (-fno-inline).
+ Opts.NoInline = !Opt;
+
+ unsigned SSP = Args.getLastArgIntValue(OPT_stack_protector, 0, Diags);
+ switch (SSP) {
+ default:
+ Diags.Report(diag::err_drv_invalid_value)
+ << Args.getLastArg(OPT_stack_protector)->getAsString(Args) << SSP;
+ break;
+ case 0: Opts.setStackProtectorMode(LangOptions::SSPOff); break;
+ case 1: Opts.setStackProtectorMode(LangOptions::SSPOn); break;
+ case 2: Opts.setStackProtectorMode(LangOptions::SSPReq); break;
+ }
+}
+
+static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args,
+ Diagnostic &Diags) {
+ using namespace cc1options;
+ Opts.ImplicitPCHInclude = Args.getLastArgValue(OPT_include_pch);
+ Opts.ImplicitPTHInclude = Args.getLastArgValue(OPT_include_pth);
+ if (const Arg *A = Args.getLastArg(OPT_token_cache))
+ Opts.TokenCache = A->getValue(Args);
+ else
+ Opts.TokenCache = Opts.ImplicitPTHInclude;
+ Opts.UsePredefines = !Args.hasArg(OPT_undef);
+ Opts.DetailedRecord = Args.hasArg(OPT_detailed_preprocessing_record);
+ // Add macros from the command line.
+ for (arg_iterator it = Args.filtered_begin(OPT_D, OPT_U),
+ ie = Args.filtered_end(); it != ie; ++it) {
+ if ((*it)->getOption().matches(OPT_D))
+ Opts.addMacroDef((*it)->getValue(Args));
+ else
+ Opts.addMacroUndef((*it)->getValue(Args));
+ }
+
+ Opts.MacroIncludes = Args.getAllArgValues(OPT_imacros);
+
+ // Add the ordered list of -includes.
+ for (arg_iterator it = Args.filtered_begin(OPT_include, OPT_include_pch,
+ OPT_include_pth),
+ ie = Args.filtered_end(); it != ie; ++it) {
+ const Arg *A = *it;
+ // PCH is handled specially, we need to extra the original include path.
+ if (A->getOption().matches(OPT_include_pch)) {
+ std::string OriginalFile =
+ PCHReader::getOriginalSourceFile(A->getValue(Args), Diags);
+ if (OriginalFile.empty())
+ continue;
+
+ Opts.Includes.push_back(OriginalFile);
+ } else
+ Opts.Includes.push_back(A->getValue(Args));
+ }
+
+ // Include 'altivec.h' if -faltivec option present
+ if (Args.hasArg(OPT_faltivec))
+ Opts.Includes.push_back("altivec.h");
+
+ for (arg_iterator it = Args.filtered_begin(OPT_remap_file),
+ ie = Args.filtered_end(); it != ie; ++it) {
+ const Arg *A = *it;
+ std::pair<llvm::StringRef,llvm::StringRef> Split =
+ llvm::StringRef(A->getValue(Args)).split(';');
+
+ if (Split.second.empty()) {
+ Diags.Report(diag::err_drv_invalid_remap_file) << A->getAsString(Args);
+ continue;
+ }
+
+ Opts.addRemappedFile(Split.first, Split.second);
+ }
+}
+
+static void ParsePreprocessorOutputArgs(PreprocessorOutputOptions &Opts,
+ ArgList &Args) {
+ using namespace cc1options;
+ Opts.ShowCPP = !Args.hasArg(OPT_dM);
+ Opts.ShowMacros = Args.hasArg(OPT_dM) || Args.hasArg(OPT_dD);
+ Opts.ShowLineMarkers = !Args.hasArg(OPT_P);
+ Opts.ShowComments = Args.hasArg(OPT_C);
+ Opts.ShowMacroComments = Args.hasArg(OPT_CC);
+}
+
+static void ParseTargetArgs(TargetOptions &Opts, ArgList &Args) {
+ using namespace cc1options;
+ Opts.ABI = Args.getLastArgValue(OPT_target_abi);
+ Opts.CXXABI = Args.getLastArgValue(OPT_cxx_abi);
+ Opts.CPU = Args.getLastArgValue(OPT_target_cpu);
+ Opts.Triple = Args.getLastArgValue(OPT_triple);
+ Opts.Features = Args.getAllArgValues(OPT_target_feature);
+
+ // Use the host triple if unspecified.
+ if (Opts.Triple.empty())
+ Opts.Triple = llvm::sys::getHostTriple();
+
+ // Use the Itanium C++ ABI if unspecified.
+ if (Opts.CXXABI.empty())
+ Opts.CXXABI = "itanium";
+}
+
+//
+
+void CompilerInvocation::CreateFromArgs(CompilerInvocation &Res,
+ const char **ArgBegin,
+ const char **ArgEnd,
+ Diagnostic &Diags) {
+ // Parse the arguments.
+ llvm::OwningPtr<OptTable> Opts(createCC1OptTable());
+ unsigned MissingArgIndex, MissingArgCount;
+ llvm::OwningPtr<InputArgList> Args(
+ Opts->ParseArgs(ArgBegin, ArgEnd,MissingArgIndex, MissingArgCount));
+
+ // Check for missing argument error.
+ if (MissingArgCount)
+ Diags.Report(diag::err_drv_missing_argument)
+ << Args->getArgString(MissingArgIndex) << MissingArgCount;
+
+ // Issue errors on unknown arguments.
+ for (arg_iterator it = Args->filtered_begin(OPT_UNKNOWN),
+ ie = Args->filtered_end(); it != ie; ++it)
+ Diags.Report(diag::err_drv_unknown_argument) << (*it)->getAsString(*Args);
+
+ ParseAnalyzerArgs(Res.getAnalyzerOpts(), *Args, Diags);
+ ParseCodeGenArgs(Res.getCodeGenOpts(), *Args, Diags);
+ ParseDependencyOutputArgs(Res.getDependencyOutputOpts(), *Args);
+ ParseDiagnosticArgs(Res.getDiagnosticOpts(), *Args, Diags);
+ InputKind DashX = ParseFrontendArgs(Res.getFrontendOpts(), *Args, Diags);
+ ParseHeaderSearchArgs(Res.getHeaderSearchOpts(), *Args);
+ if (DashX != IK_AST && DashX != IK_LLVM_IR)
+ ParseLangArgs(Res.getLangOpts(), *Args, DashX, Diags);
+ ParsePreprocessorArgs(Res.getPreprocessorOpts(), *Args, Diags);
+ ParsePreprocessorOutputArgs(Res.getPreprocessorOutputOpts(), *Args);
+ ParseTargetArgs(Res.getTargetOpts(), *Args);
+}
diff --git a/contrib/llvm/tools/clang/lib/Frontend/DeclXML.cpp b/contrib/llvm/tools/clang/lib/Frontend/DeclXML.cpp
new file mode 100644
index 0000000..97a7f55
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Frontend/DeclXML.cpp
@@ -0,0 +1,189 @@
+//===--- DeclXML.cpp - XML implementation for Decl ASTs -------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the XML document class, which provides the means to
+// dump out the AST in a XML form that exposes type details and other fields.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/DocumentXML.h"
+#include "clang/AST/DeclVisitor.h"
+#include "clang/AST/Expr.h"
+
+namespace clang {
+
+//---------------------------------------------------------
+class DocumentXML::DeclPrinter : public DeclVisitor<DocumentXML::DeclPrinter> {
+ DocumentXML& Doc;
+
+ void addSubNodes(FunctionDecl* FD) {
+ for (unsigned i = 0, e = FD->getNumParams(); i != e; ++i) {
+ Visit(FD->getParamDecl(i));
+ Doc.toParent();
+ }
+ }
+
+ void addFunctionBody(FunctionDecl* FD) {
+ if (FD->isThisDeclarationADefinition()) {
+ Doc.addSubNode("Body");
+ Doc.PrintStmt(FD->getBody());
+ Doc.toParent();
+ }
+ }
+
+ void addSubNodes(RecordDecl* RD) {
+ for (RecordDecl::field_iterator i = RD->field_begin(),
+ e = RD->field_end(); i != e; ++i) {
+ Visit(*i);
+ Doc.toParent();
+ }
+ }
+
+ void addSubNodes(CXXRecordDecl* RD) {
+ addSubNodes(cast<RecordDecl>(RD));
+
+ if (RD->isDefinition()) {
+ // FIXME: This breaks XML generation
+ //Doc.addAttribute("num_bases", RD->getNumBases());
+
+ for (CXXRecordDecl::base_class_iterator
+ base = RD->bases_begin(),
+ bend = RD->bases_end();
+ base != bend;
+ ++base) {
+ Doc.addSubNode("Base");
+ Doc.addAttribute("id", base->getType());
+ AccessSpecifier as = base->getAccessSpecifierAsWritten();
+ const char* as_name = "";
+ switch(as) {
+ case AS_none: as_name = ""; break;
+ case AS_public: as_name = "public"; break;
+ case AS_protected: as_name = "protected"; break;
+ case AS_private: as_name = "private"; break;
+ }
+ Doc.addAttributeOptional("access", as_name);
+ Doc.addAttribute("is_virtual", base->isVirtual());
+ Doc.toParent();
+ }
+
+ for (CXXRecordDecl::method_iterator i = RD->method_begin(),
+ e = RD->method_end(); i != e; ++i) {
+ Visit(*i);
+ Doc.toParent();
+ }
+
+ }
+
+ }
+
+ void addSubNodes(EnumDecl* ED) {
+ for (EnumDecl::enumerator_iterator i = ED->enumerator_begin(),
+ e = ED->enumerator_end(); i != e; ++i) {
+ Visit(*i);
+ Doc.toParent();
+ }
+ }
+
+ void addSubNodes(EnumConstantDecl* ECD) {
+ if (ECD->getInitExpr())
+ Doc.PrintStmt(ECD->getInitExpr());
+ }
+
+ void addSubNodes(FieldDecl* FdD) {
+ if (FdD->isBitField())
+ Doc.PrintStmt(FdD->getBitWidth());
+ }
+
+ void addSubNodes(VarDecl* V) {
+ if (V->getInit())
+ Doc.PrintStmt(V->getInit());
+ }
+
+ void addSubNodes(ParmVarDecl* argDecl) {
+ if (argDecl->getDefaultArg())
+ Doc.PrintStmt(argDecl->getDefaultArg());
+ }
+
+ void addSubNodes(NamespaceDecl* ns) {
+
+ for (DeclContext::decl_iterator
+ d = ns->decls_begin(),
+ dend = ns->decls_end();
+ d != dend;
+ ++d) {
+ Visit(*d);
+ Doc.toParent();
+ }
+ }
+
+ void addSpecialAttribute(const char* pName, EnumDecl* ED) {
+ const QualType& enumType = ED->getIntegerType();
+ if (!enumType.isNull())
+ Doc.addAttribute(pName, enumType);
+ }
+
+ void addIdAttribute(LinkageSpecDecl* ED) {
+ Doc.addAttribute("id", ED);
+ }
+
+ void addIdAttribute(NamedDecl* ND) {
+ Doc.addAttribute("id", ND);
+ }
+
+public:
+ DeclPrinter(DocumentXML& doc) : Doc(doc) {}
+
+#define NODE_XML( CLASS, NAME ) \
+ void Visit##CLASS(CLASS* T) \
+ { \
+ Doc.addSubNode(NAME);
+
+#define ID_ATTRIBUTE_XML addIdAttribute(T);
+#define ATTRIBUTE_XML( FN, NAME ) Doc.addAttribute(NAME, T->FN);
+#define ATTRIBUTE_OPT_XML( FN, NAME ) Doc.addAttributeOptional(NAME, T->FN);
+#define ATTRIBUTE_FILE_LOCATION_XML Doc.addLocation(T->getLocation());
+#define ATTRIBUTE_SPECIAL_XML( FN, NAME ) addSpecialAttribute(NAME, T);
+
+#define ATTRIBUTE_ENUM_XML( FN, NAME ) \
+ { \
+ const char* pAttributeName = NAME; \
+ const bool optional = false; \
+ switch (T->FN) { \
+ default: assert(0 && "unknown enum value");
+
+#define ATTRIBUTE_ENUM_OPT_XML( FN, NAME ) \
+ { \
+ const char* pAttributeName = NAME; \
+ const bool optional = true; \
+ switch (T->FN) { \
+ default: assert(0 && "unknown enum value");
+
+#define ENUM_XML( VALUE, NAME ) case VALUE: if ((!optional) || NAME[0]) Doc.addAttribute(pAttributeName, NAME); break;
+#define END_ENUM_XML } }
+#define END_NODE_XML }
+
+#define SUB_NODE_XML( CLASS ) addSubNodes(T);
+#define SUB_NODE_SEQUENCE_XML( CLASS ) addSubNodes(T);
+#define SUB_NODE_OPT_XML( CLASS ) addSubNodes(T);
+
+#define SUB_NODE_FN_BODY_XML addFunctionBody(T);
+
+#include "clang/Frontend/DeclXML.def"
+};
+
+
+//---------------------------------------------------------
+void DocumentXML::writeDeclToXML(Decl *D) {
+ DeclPrinter(*this).Visit(D);
+ toParent();
+}
+
+//---------------------------------------------------------
+} // NS clang
+
diff --git a/contrib/llvm/tools/clang/lib/Frontend/DependencyFile.cpp b/contrib/llvm/tools/clang/lib/Frontend/DependencyFile.cpp
new file mode 100644
index 0000000..14aee35
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Frontend/DependencyFile.cpp
@@ -0,0 +1,174 @@
+//===--- DependencyFile.cpp - Generate dependency file --------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This code generates dependency files.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/Utils.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Frontend/DependencyOutputOptions.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
+#include "clang/Lex/DirectoryLookup.h"
+#include "clang/Lex/PPCallbacks.h"
+#include "clang/Lex/Preprocessor.h"
+#include "llvm/ADT/StringSet.h"
+#include "llvm/Support/raw_ostream.h"
+#include <string>
+
+using namespace clang;
+
+namespace {
+class DependencyFileCallback : public PPCallbacks {
+ std::vector<std::string> Files;
+ llvm::StringSet<> FilesSet;
+ const Preprocessor *PP;
+ std::vector<std::string> Targets;
+ llvm::raw_ostream *OS;
+ bool IncludeSystemHeaders;
+ bool PhonyTarget;
+private:
+ bool FileMatchesDepCriteria(const char *Filename,
+ SrcMgr::CharacteristicKind FileType);
+ void OutputDependencyFile();
+
+public:
+ DependencyFileCallback(const Preprocessor *_PP,
+ llvm::raw_ostream *_OS,
+ const DependencyOutputOptions &Opts)
+ : PP(_PP), Targets(Opts.Targets), OS(_OS),
+ IncludeSystemHeaders(Opts.IncludeSystemHeaders),
+ PhonyTarget(Opts.UsePhonyTargets) {}
+
+ virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason,
+ SrcMgr::CharacteristicKind FileType);
+
+ virtual void EndOfMainFile() {
+ OutputDependencyFile();
+ OS->flush();
+ delete OS;
+ OS = 0;
+ }
+};
+}
+
+void clang::AttachDependencyFileGen(Preprocessor &PP,
+ const DependencyOutputOptions &Opts) {
+ if (Opts.Targets.empty()) {
+ PP.getDiagnostics().Report(diag::err_fe_dependency_file_requires_MT);
+ return;
+ }
+
+ std::string Err;
+ llvm::raw_ostream *OS(new llvm::raw_fd_ostream(Opts.OutputFile.c_str(), Err));
+ if (!Err.empty()) {
+ PP.getDiagnostics().Report(diag::err_fe_error_opening)
+ << Opts.OutputFile << Err;
+ return;
+ }
+
+ PP.addPPCallbacks(new DependencyFileCallback(&PP, OS, Opts));
+}
+
+/// FileMatchesDepCriteria - Determine whether the given Filename should be
+/// considered as a dependency.
+bool DependencyFileCallback::FileMatchesDepCriteria(const char *Filename,
+ SrcMgr::CharacteristicKind FileType) {
+ if (strcmp("<built-in>", Filename) == 0)
+ return false;
+
+ if (IncludeSystemHeaders)
+ return true;
+
+ return FileType == SrcMgr::C_User;
+}
+
+void DependencyFileCallback::FileChanged(SourceLocation Loc,
+ FileChangeReason Reason,
+ SrcMgr::CharacteristicKind FileType) {
+ if (Reason != PPCallbacks::EnterFile)
+ return;
+
+ // Dependency generation really does want to go all the way to the
+ // file entry for a source location to find out what is depended on.
+ // We do not want #line markers to affect dependency generation!
+ SourceManager &SM = PP->getSourceManager();
+
+ const FileEntry *FE =
+ SM.getFileEntryForID(SM.getFileID(SM.getInstantiationLoc(Loc)));
+ if (FE == 0) return;
+
+ const char *Filename = FE->getName();
+ if (!FileMatchesDepCriteria(Filename, FileType))
+ return;
+
+ // Remove leading "./"
+ if (Filename[0] == '.' && Filename[1] == '/')
+ Filename = &Filename[2];
+
+ if (FilesSet.insert(Filename))
+ Files.push_back(Filename);
+}
+
+void DependencyFileCallback::OutputDependencyFile() {
+ // Write out the dependency targets, trying to avoid overly long
+ // lines when possible. We try our best to emit exactly the same
+ // dependency file as GCC (4.2), assuming the included files are the
+ // same.
+ const unsigned MaxColumns = 75;
+ unsigned Columns = 0;
+
+ for (std::vector<std::string>::iterator
+ I = Targets.begin(), E = Targets.end(); I != E; ++I) {
+ unsigned N = I->length();
+ if (Columns == 0) {
+ Columns += N;
+ *OS << *I;
+ } else if (Columns + N + 2 > MaxColumns) {
+ Columns = N + 2;
+ *OS << " \\\n " << *I;
+ } else {
+ Columns += N + 1;
+ *OS << ' ' << *I;
+ }
+ }
+
+ *OS << ':';
+ Columns += 1;
+
+ // Now add each dependency in the order it was seen, but avoiding
+ // duplicates.
+ for (std::vector<std::string>::iterator I = Files.begin(),
+ E = Files.end(); I != E; ++I) {
+ // Start a new line if this would exceed the column limit. Make
+ // sure to leave space for a trailing " \" in case we need to
+ // break the line on the next iteration.
+ unsigned N = I->length();
+ if (Columns + (N + 1) + 2 > MaxColumns) {
+ *OS << " \\\n ";
+ Columns = 2;
+ }
+ *OS << ' ' << *I;
+ Columns += N + 1;
+ }
+ *OS << '\n';
+
+ // Create phony targets if requested.
+ if (PhonyTarget) {
+ // Skip the first entry, this is always the input file itself.
+ for (std::vector<std::string>::iterator I = Files.begin() + 1,
+ E = Files.end(); I != E; ++I) {
+ *OS << '\n';
+ *OS << *I << ":\n";
+ }
+ }
+}
+
diff --git a/contrib/llvm/tools/clang/lib/Frontend/DiagChecker.cpp b/contrib/llvm/tools/clang/lib/Frontend/DiagChecker.cpp
new file mode 100644
index 0000000..a50cc99
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Frontend/DiagChecker.cpp
@@ -0,0 +1,301 @@
+//===--- DiagChecker.cpp - Diagnostic Checking Functions ------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Process the input files and check that the diagnostic messages are expected.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/Utils.h"
+#include "clang/Frontend/TextDiagnosticBuffer.h"
+#include "clang/Sema/ParseAST.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Lex/Preprocessor.h"
+#include "llvm/Support/raw_ostream.h"
+using namespace clang;
+
+typedef TextDiagnosticBuffer::DiagList DiagList;
+typedef TextDiagnosticBuffer::const_iterator const_diag_iterator;
+
+static void EmitError(Preprocessor &PP, SourceLocation Pos, const char *String){
+ unsigned ID = PP.getDiagnostics().getCustomDiagID(Diagnostic::Error, String);
+ PP.Diag(Pos, ID);
+}
+
+
+// USING THE DIAGNOSTIC CHECKER:
+//
+// Indicating that a line expects an error or a warning is simple. Put a comment
+// on the line that has the diagnostic, use "expected-{error,warning}" to tag
+// if it's an expected error or warning, and place the expected text between {{
+// and }} markers. The full text doesn't have to be included, only enough to
+// ensure that the correct diagnostic was emitted.
+//
+// Here's an example:
+//
+// int A = B; // expected-error {{use of undeclared identifier 'B'}}
+//
+// You can place as many diagnostics on one line as you wish. To make the code
+// more readable, you can use slash-newline to separate out the diagnostics.
+//
+// The simple syntax above allows each specification to match exactly one error.
+// You can use the extended syntax to customize this. The extended syntax is
+// "expected-<type> <n> {{diag text}}", where <type> is one of "error",
+// "warning" or "note", and <n> is a positive integer. This allows the
+// diagnostic to appear as many times as specified. Example:
+//
+// void f(); // expected-note 2 {{previous declaration is here}}
+//
+
+/// FindDiagnostics - Go through the comment and see if it indicates expected
+/// diagnostics. If so, then put them in a diagnostic list.
+///
+static void FindDiagnostics(const char *CommentStart, unsigned CommentLen,
+ DiagList &ExpectedDiags,
+ Preprocessor &PP, SourceLocation Pos,
+ const char *ExpectedStr) {
+ const char *CommentEnd = CommentStart+CommentLen;
+ unsigned ExpectedStrLen = strlen(ExpectedStr);
+
+ // Find all expected-foo diagnostics in the string and add them to
+ // ExpectedDiags.
+ while (CommentStart != CommentEnd) {
+ CommentStart = std::find(CommentStart, CommentEnd, 'e');
+ if (unsigned(CommentEnd-CommentStart) < ExpectedStrLen) return;
+
+ // If this isn't expected-foo, ignore it.
+ if (memcmp(CommentStart, ExpectedStr, ExpectedStrLen)) {
+ ++CommentStart;
+ continue;
+ }
+
+ CommentStart += ExpectedStrLen;
+
+ // Skip whitespace.
+ while (CommentStart != CommentEnd &&
+ isspace(CommentStart[0]))
+ ++CommentStart;
+
+ // Default, if we find the '{' now, is 1 time.
+ int Times = 1;
+ int Temp = 0;
+ // In extended syntax, there could be a digit now.
+ while (CommentStart != CommentEnd &&
+ CommentStart[0] >= '0' && CommentStart[0] <= '9') {
+ Temp *= 10;
+ Temp += CommentStart[0] - '0';
+ ++CommentStart;
+ }
+ if (Temp > 0)
+ Times = Temp;
+
+ // Skip whitespace again.
+ while (CommentStart != CommentEnd &&
+ isspace(CommentStart[0]))
+ ++CommentStart;
+
+ // We should have a {{ now.
+ if (CommentEnd-CommentStart < 2 ||
+ CommentStart[0] != '{' || CommentStart[1] != '{') {
+ if (std::find(CommentStart, CommentEnd, '{') != CommentEnd)
+ EmitError(PP, Pos, "bogus characters before '{{' in expected string");
+ else
+ EmitError(PP, Pos, "cannot find start ('{{') of expected string");
+ return;
+ }
+ CommentStart += 2;
+
+ // Find the }}.
+ const char *ExpectedEnd = CommentStart;
+ while (1) {
+ ExpectedEnd = std::find(ExpectedEnd, CommentEnd, '}');
+ if (CommentEnd-ExpectedEnd < 2) {
+ EmitError(PP, Pos, "cannot find end ('}}') of expected string");
+ return;
+ }
+
+ if (ExpectedEnd[1] == '}')
+ break;
+
+ ++ExpectedEnd; // Skip over singular }'s
+ }
+
+ std::string Msg(CommentStart, ExpectedEnd);
+ std::string::size_type FindPos;
+ while ((FindPos = Msg.find("\\n")) != std::string::npos)
+ Msg.replace(FindPos, 2, "\n");
+ // Add is possibly multiple times.
+ for (int i = 0; i < Times; ++i)
+ ExpectedDiags.push_back(std::make_pair(Pos, Msg));
+
+ CommentStart = ExpectedEnd;
+ }
+}
+
+/// FindExpectedDiags - Lex the main source file to find all of the
+// expected errors and warnings.
+static void FindExpectedDiags(Preprocessor &PP,
+ DiagList &ExpectedErrors,
+ DiagList &ExpectedWarnings,
+ DiagList &ExpectedNotes) {
+ // Create a raw lexer to pull all the comments out of the main file. We don't
+ // want to look in #include'd headers for expected-error strings.
+ FileID FID = PP.getSourceManager().getMainFileID();
+
+ // Create a lexer to lex all the tokens of the main file in raw mode.
+ const llvm::MemoryBuffer *FromFile = PP.getSourceManager().getBuffer(FID);
+ Lexer RawLex(FID, FromFile, PP.getSourceManager(), PP.getLangOptions());
+
+ // Return comments as tokens, this is how we find expected diagnostics.
+ RawLex.SetCommentRetentionState(true);
+
+ Token Tok;
+ Tok.setKind(tok::comment);
+ while (Tok.isNot(tok::eof)) {
+ RawLex.Lex(Tok);
+ if (!Tok.is(tok::comment)) continue;
+
+ std::string Comment = PP.getSpelling(Tok);
+ if (Comment.empty()) continue;
+
+
+ // Find all expected errors.
+ FindDiagnostics(&Comment[0], Comment.size(), ExpectedErrors, PP,
+ Tok.getLocation(), "expected-error");
+
+ // Find all expected warnings.
+ FindDiagnostics(&Comment[0], Comment.size(), ExpectedWarnings, PP,
+ Tok.getLocation(), "expected-warning");
+
+ // Find all expected notes.
+ FindDiagnostics(&Comment[0], Comment.size(), ExpectedNotes, PP,
+ Tok.getLocation(), "expected-note");
+ };
+}
+
+/// PrintProblem - This takes a diagnostic map of the delta between expected and
+/// seen diagnostics. If there's anything in it, then something unexpected
+/// happened. Print the map out in a nice format and return "true". If the map
+/// is empty and we're not going to print things, then return "false".
+///
+static bool PrintProblem(SourceManager &SourceMgr,
+ const_diag_iterator diag_begin,
+ const_diag_iterator diag_end,
+ const char *Msg) {
+ if (diag_begin == diag_end) return false;
+
+ llvm::errs() << Msg << "\n";
+ for (const_diag_iterator I = diag_begin, E = diag_end; I != E; ++I)
+ llvm::errs() << " Line " << SourceMgr.getInstantiationLineNumber(I->first)
+ << " " << I->second << "\n";
+
+ return true;
+}
+
+/// CompareDiagLists - Compare two diagnostic lists and return the difference
+/// between them.
+///
+static bool CompareDiagLists(SourceManager &SourceMgr,
+ const_diag_iterator d1_begin,
+ const_diag_iterator d1_end,
+ const_diag_iterator d2_begin,
+ const_diag_iterator d2_end,
+ const char *MsgLeftOnly,
+ const char *MsgRightOnly) {
+ DiagList LeftOnly;
+ DiagList Left(d1_begin, d1_end);
+ DiagList Right(d2_begin, d2_end);
+
+ for (const_diag_iterator I = Left.begin(), E = Left.end(); I != E; ++I) {
+ unsigned LineNo1 = SourceMgr.getInstantiationLineNumber(I->first);
+ const std::string &Diag1 = I->second;
+
+ DiagList::iterator II, IE;
+ for (II = Right.begin(), IE = Right.end(); II != IE; ++II) {
+ unsigned LineNo2 = SourceMgr.getInstantiationLineNumber(II->first);
+ if (LineNo1 != LineNo2) continue;
+
+ const std::string &Diag2 = II->second;
+ if (Diag2.find(Diag1) != std::string::npos ||
+ Diag1.find(Diag2) != std::string::npos) {
+ break;
+ }
+ }
+ if (II == IE) {
+ // Not found.
+ LeftOnly.push_back(*I);
+ } else {
+ // Found. The same cannot be found twice.
+ Right.erase(II);
+ }
+ }
+ // Now all that's left in Right are those that were not matched.
+
+ return PrintProblem(SourceMgr, LeftOnly.begin(), LeftOnly.end(), MsgLeftOnly)
+ | PrintProblem(SourceMgr, Right.begin(), Right.end(), MsgRightOnly);
+}
+
+/// CheckResults - This compares the expected results to those that
+/// were actually reported. It emits any discrepencies. Return "true" if there
+/// were problems. Return "false" otherwise.
+///
+static bool CheckResults(Preprocessor &PP,
+ const DiagList &ExpectedErrors,
+ const DiagList &ExpectedWarnings,
+ const DiagList &ExpectedNotes) {
+ const DiagnosticClient *DiagClient = PP.getDiagnostics().getClient();
+ assert(DiagClient != 0 &&
+ "DiagChecker requires a valid TextDiagnosticBuffer");
+ const TextDiagnosticBuffer &Diags =
+ static_cast<const TextDiagnosticBuffer&>(*DiagClient);
+ SourceManager &SourceMgr = PP.getSourceManager();
+
+ // We want to capture the delta between what was expected and what was
+ // seen.
+ //
+ // Expected \ Seen - set expected but not seen
+ // Seen \ Expected - set seen but not expected
+ bool HadProblem = false;
+
+ // See if there are error mismatches.
+ HadProblem |= CompareDiagLists(SourceMgr,
+ ExpectedErrors.begin(), ExpectedErrors.end(),
+ Diags.err_begin(), Diags.err_end(),
+ "Errors expected but not seen:",
+ "Errors seen but not expected:");
+
+ // See if there are warning mismatches.
+ HadProblem |= CompareDiagLists(SourceMgr,
+ ExpectedWarnings.begin(),
+ ExpectedWarnings.end(),
+ Diags.warn_begin(), Diags.warn_end(),
+ "Warnings expected but not seen:",
+ "Warnings seen but not expected:");
+
+ // See if there are note mismatches.
+ HadProblem |= CompareDiagLists(SourceMgr,
+ ExpectedNotes.begin(),
+ ExpectedNotes.end(),
+ Diags.note_begin(), Diags.note_end(),
+ "Notes expected but not seen:",
+ "Notes seen but not expected:");
+
+ return HadProblem;
+}
+
+
+/// CheckDiagnostics - Gather the expected diagnostics and check them.
+bool clang::CheckDiagnostics(Preprocessor &PP) {
+ // Gather the set of expected diagnostics.
+ DiagList ExpectedErrors, ExpectedWarnings, ExpectedNotes;
+ FindExpectedDiags(PP, ExpectedErrors, ExpectedWarnings, ExpectedNotes);
+
+ // Check that the expected diagnostics occurred.
+ return CheckResults(PP, ExpectedErrors, ExpectedWarnings, ExpectedNotes);
+}
diff --git a/contrib/llvm/tools/clang/lib/Frontend/DocumentXML.cpp b/contrib/llvm/tools/clang/lib/Frontend/DocumentXML.cpp
new file mode 100644
index 0000000..894f230
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Frontend/DocumentXML.cpp
@@ -0,0 +1,367 @@
+//===--- DocumentXML.cpp - XML document for ASTs --------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the XML document class, which provides the means to
+// dump out the AST in a XML form that exposes type details and other fields.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/DocumentXML.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/Basic/SourceManager.h"
+#include "llvm/ADT/StringExtras.h"
+
+namespace clang {
+
+//---------------------------------------------------------
+DocumentXML::DocumentXML(const std::string& rootName, llvm::raw_ostream& out) :
+ Out(out),
+ Ctx(0),
+ HasCurrentNodeSubNodes(false) {
+ NodeStack.push(rootName);
+ Out << "<?xml version=\"1.0\"?>\n<" << rootName;
+}
+
+//---------------------------------------------------------
+DocumentXML& DocumentXML::addSubNode(const std::string& name) {
+ if (!HasCurrentNodeSubNodes)
+ Out << ">\n";
+ NodeStack.push(name);
+ HasCurrentNodeSubNodes = false;
+ Indent();
+ Out << "<" << NodeStack.top();
+ return *this;
+}
+
+//---------------------------------------------------------
+void DocumentXML::Indent() {
+ for (size_t i = 0, e = (NodeStack.size() - 1) * 2; i < e; ++i)
+ Out << ' ';
+}
+
+//---------------------------------------------------------
+DocumentXML& DocumentXML::toParent() {
+ assert(NodeStack.size() > 1 && "too much backtracking");
+
+ if (HasCurrentNodeSubNodes) {
+ Indent();
+ Out << "</" << NodeStack.top() << ">\n";
+ } else
+ Out << "/>\n";
+ NodeStack.pop();
+ HasCurrentNodeSubNodes = true;
+ return *this;
+}
+
+//---------------------------------------------------------
+namespace {
+
+enum tIdType { ID_NORMAL, ID_FILE, ID_LABEL, ID_LAST };
+
+unsigned getNewId(tIdType idType) {
+ static unsigned int idCounts[ID_LAST] = { 0 };
+ return ++idCounts[idType];
+}
+
+//---------------------------------------------------------
+inline std::string getPrefixedId(unsigned uId, tIdType idType) {
+ static const char idPrefix[ID_LAST] = { '_', 'f', 'l' };
+ char buffer[20];
+ char* BufPtr = llvm::utohex_buffer(uId, buffer + 20);
+ *--BufPtr = idPrefix[idType];
+ return BufPtr;
+}
+
+//---------------------------------------------------------
+template<class T, class V>
+bool addToMap(T& idMap, const V& value, tIdType idType = ID_NORMAL) {
+ typename T::iterator i = idMap.find(value);
+ bool toAdd = i == idMap.end();
+ if (toAdd)
+ idMap.insert(typename T::value_type(value, getNewId(idType)));
+ return toAdd;
+}
+
+} // anon NS
+
+
+//---------------------------------------------------------
+std::string DocumentXML::escapeString(const char* pStr,
+ std::string::size_type len) {
+ std::string value;
+ value.reserve(len + 1);
+ char buffer[16];
+ for (unsigned i = 0; i < len; ++i) {
+ switch (char C = pStr[i]) {
+ default:
+ if (isprint(C))
+ value += C;
+ else {
+ sprintf(buffer, "\\%03o", C);
+ value += buffer;
+ }
+ break;
+
+ case '\n': value += "\\n"; break;
+ case '\t': value += "\\t"; break;
+ case '\a': value += "\\a"; break;
+ case '\b': value += "\\b"; break;
+ case '\r': value += "\\r"; break;
+
+ case '&': value += "&amp;"; break;
+ case '<': value += "&lt;"; break;
+ case '>': value += "&gt;"; break;
+ case '"': value += "&quot;"; break;
+ case '\'': value += "&apos;"; break;
+
+ }
+ }
+ return value;
+}
+
+//---------------------------------------------------------
+void DocumentXML::finalize() {
+ assert(NodeStack.size() == 1 && "not completely backtracked");
+
+ addSubNode("ReferenceSection");
+ addSubNode("Types");
+
+ for (XML::IdMap<QualType>::iterator i = Types.begin(), e = Types.end();
+ i != e; ++i) {
+ if (i->first.hasLocalQualifiers()) {
+ writeTypeToXML(i->first);
+ addAttribute("id", getPrefixedId(i->second, ID_NORMAL));
+ toParent();
+ }
+ }
+
+ for (XML::IdMap<const Type*>::iterator i = BasicTypes.begin(),
+ e = BasicTypes.end(); i != e; ++i) {
+ writeTypeToXML(i->first);
+ addAttribute("id", getPrefixedId(i->second, ID_NORMAL));
+ toParent();
+ }
+
+
+ toParent().addSubNode("Contexts");
+
+ for (XML::IdMap<const DeclContext*>::iterator i = Contexts.begin(),
+ e = Contexts.end(); i != e; ++i) {
+ addSubNode(i->first->getDeclKindName());
+ addAttribute("id", getPrefixedId(i->second, ID_NORMAL));
+ if (const NamedDecl *ND = dyn_cast<NamedDecl>(i->first))
+ addAttribute("name", ND->getNameAsString());
+ if (const TagDecl *TD = dyn_cast<TagDecl>(i->first))
+ addAttribute("type", getPrefixedId(BasicTypes[TD->getTypeForDecl()], ID_NORMAL));
+ else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(i->first))
+ addAttribute("type", getPrefixedId(BasicTypes[FD->getType()->getAs<FunctionType>()], ID_NORMAL));
+
+ if (const DeclContext* parent = i->first->getParent())
+ addAttribute("context", parent);
+ toParent();
+ }
+
+ toParent().addSubNode("Files");
+
+ for (XML::IdMap<std::string>::iterator i = SourceFiles.begin(),
+ e = SourceFiles.end(); i != e; ++i) {
+ addSubNode("File");
+ addAttribute("id", getPrefixedId(i->second, ID_FILE));
+ addAttribute("name", escapeString(i->first.c_str(), i->first.size()));
+ toParent();
+ }
+
+ toParent().toParent();
+
+ // write the root closing node (which has always subnodes)
+ Out << "</" << NodeStack.top() << ">\n";
+}
+
+//---------------------------------------------------------
+void DocumentXML::addAttribute(const char* pAttributeName,
+ const QualType& pType) {
+ addTypeRecursively(pType);
+ addAttribute(pAttributeName, getPrefixedId(Types[pType], ID_NORMAL));
+}
+
+//---------------------------------------------------------
+void DocumentXML::addPtrAttribute(const char* pAttributeName,
+ const Type* pType) {
+ addTypeRecursively(pType);
+ addAttribute(pAttributeName, getPrefixedId(BasicTypes[pType], ID_NORMAL));
+}
+
+//---------------------------------------------------------
+void DocumentXML::addPtrAttribute(const char* pAttributeName,
+ const NestedNameSpecifier* pNNS) {
+ switch (pNNS->getKind()) {
+ case NestedNameSpecifier::Identifier: {
+ IdentifierInfo *ii = pNNS->getAsIdentifier();
+ // FIXME how should we handle those ?
+ addPtrAttribute(pAttributeName, ii->getName().data());
+ break;
+ }
+ case NestedNameSpecifier::Namespace: {
+ addPtrAttribute(pAttributeName, pNNS->getAsNamespace());
+ break;
+ }
+ case NestedNameSpecifier::TypeSpec: {
+ addPtrAttribute(pAttributeName, pNNS->getAsType());
+ break;
+ }
+ case NestedNameSpecifier::TypeSpecWithTemplate: {
+ addPtrAttribute(pAttributeName, pNNS->getAsType());
+ break;
+ }
+ case NestedNameSpecifier::Global: {
+ addPtrAttribute(pAttributeName, "::");
+ break;
+ }
+ }
+}
+
+//---------------------------------------------------------
+void DocumentXML::addTypeRecursively(const QualType& pType)
+{
+ if (addToMap(Types, pType))
+ {
+ addTypeRecursively(pType.getTypePtr());
+ // beautifier: a non-qualified type shall be transparent
+ if (!pType.hasLocalQualifiers())
+ {
+ Types[pType] = BasicTypes[pType.getTypePtr()];
+ }
+ }
+}
+
+//---------------------------------------------------------
+void DocumentXML::addTypeRecursively(const Type* pType)
+{
+ if (addToMap(BasicTypes, pType))
+ {
+ addParentTypes(pType);
+/*
+ // FIXME: doesn't work in the immediate streaming approach
+ if (const VariableArrayType *VAT = dyn_cast<VariableArrayType>(pType))
+ {
+ addSubNode("VariableArraySizeExpression");
+ PrintStmt(VAT->getSizeExpr());
+ toParent();
+ }
+*/
+ }
+}
+
+//---------------------------------------------------------
+void DocumentXML::addPtrAttribute(const char* pName, const DeclContext* DC)
+{
+ addContextsRecursively(DC);
+ addAttribute(pName, getPrefixedId(Contexts[DC], ID_NORMAL));
+}
+
+//---------------------------------------------------------
+void DocumentXML::addPtrAttribute(const char* pAttributeName, const NamedDecl* D)
+{
+ if (const DeclContext* DC = dyn_cast<DeclContext>(D))
+ {
+ addContextsRecursively(DC);
+ addAttribute(pAttributeName, getPrefixedId(Contexts[DC], ID_NORMAL));
+ }
+ else
+ {
+ addToMap(Decls, D);
+ addAttribute(pAttributeName, getPrefixedId(Decls[D], ID_NORMAL));
+ }
+}
+
+//---------------------------------------------------------
+void DocumentXML::addPtrAttribute(const char* pName, const NamespaceDecl* D)
+{
+ addPtrAttribute(pName, static_cast<const DeclContext*>(D));
+}
+
+//---------------------------------------------------------
+void DocumentXML::addContextsRecursively(const DeclContext *DC)
+{
+ if (DC != 0 && addToMap(Contexts, DC))
+ {
+ addContextsRecursively(DC->getParent());
+ }
+}
+
+//---------------------------------------------------------
+void DocumentXML::addSourceFileAttribute(const std::string& fileName)
+{
+ addToMap(SourceFiles, fileName, ID_FILE);
+ addAttribute("file", getPrefixedId(SourceFiles[fileName], ID_FILE));
+}
+
+
+//---------------------------------------------------------
+void DocumentXML::addPtrAttribute(const char* pName, const LabelStmt* L)
+{
+ addToMap(Labels, L, ID_LABEL);
+ addAttribute(pName, getPrefixedId(Labels[L], ID_LABEL));
+}
+
+
+//---------------------------------------------------------
+PresumedLoc DocumentXML::addLocation(const SourceLocation& Loc)
+{
+ SourceManager& SM = Ctx->getSourceManager();
+ SourceLocation SpellingLoc = SM.getSpellingLoc(Loc);
+ PresumedLoc PLoc;
+ if (!SpellingLoc.isInvalid())
+ {
+ PLoc = SM.getPresumedLoc(SpellingLoc);
+ addSourceFileAttribute(PLoc.getFilename());
+ addAttribute("line", PLoc.getLine());
+ addAttribute("col", PLoc.getColumn());
+ }
+ // else there is no error in some cases (eg. CXXThisExpr)
+ return PLoc;
+}
+
+//---------------------------------------------------------
+void DocumentXML::addLocationRange(const SourceRange& R)
+{
+ PresumedLoc PStartLoc = addLocation(R.getBegin());
+ if (R.getBegin() != R.getEnd())
+ {
+ SourceManager& SM = Ctx->getSourceManager();
+ SourceLocation SpellingLoc = SM.getSpellingLoc(R.getEnd());
+ if (!SpellingLoc.isInvalid())
+ {
+ PresumedLoc PLoc = SM.getPresumedLoc(SpellingLoc);
+ if (PStartLoc.isInvalid() ||
+ strcmp(PLoc.getFilename(), PStartLoc.getFilename()) != 0) {
+ addToMap(SourceFiles, PLoc.getFilename(), ID_FILE);
+ addAttribute("endfile", PLoc.getFilename());
+ addAttribute("endline", PLoc.getLine());
+ addAttribute("endcol", PLoc.getColumn());
+ } else if (PLoc.getLine() != PStartLoc.getLine()) {
+ addAttribute("endline", PLoc.getLine());
+ addAttribute("endcol", PLoc.getColumn());
+ } else {
+ addAttribute("endcol", PLoc.getColumn());
+ }
+ }
+ }
+}
+
+//---------------------------------------------------------
+void DocumentXML::PrintDecl(Decl *D)
+{
+ writeDeclToXML(D);
+}
+
+//---------------------------------------------------------
+} // NS clang
+
diff --git a/contrib/llvm/tools/clang/lib/Frontend/FrontendAction.cpp b/contrib/llvm/tools/clang/lib/Frontend/FrontendAction.cpp
new file mode 100644
index 0000000..dbbf69c
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Frontend/FrontendAction.cpp
@@ -0,0 +1,261 @@
+//===--- FrontendAction.cpp -----------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/FrontendAction.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/Lex/HeaderSearch.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Frontend/ASTUnit.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
+#include "clang/Sema/ParseAST.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Timer.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/raw_ostream.h"
+using namespace clang;
+
+FrontendAction::FrontendAction() : Instance(0) {}
+
+FrontendAction::~FrontendAction() {}
+
+void FrontendAction::setCurrentFile(llvm::StringRef Value, InputKind Kind,
+ ASTUnit *AST) {
+ CurrentFile = Value;
+ CurrentFileKind = Kind;
+ CurrentASTUnit.reset(AST);
+}
+
+bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
+ llvm::StringRef Filename,
+ InputKind InputKind) {
+ assert(!Instance && "Already processing a source file!");
+ assert(!Filename.empty() && "Unexpected empty filename!");
+ setCurrentFile(Filename, InputKind);
+ setCompilerInstance(&CI);
+
+ // AST files follow a very different path, since they share objects via the
+ // AST unit.
+ if (InputKind == IK_AST) {
+ assert(!usesPreprocessorOnly() &&
+ "Attempt to pass AST file to preprocessor only action!");
+ assert(hasASTFileSupport() &&
+ "This action does not have AST file support!");
+
+ llvm::IntrusiveRefCntPtr<Diagnostic> Diags(&CI.getDiagnostics());
+ std::string Error;
+ ASTUnit *AST = ASTUnit::LoadFromPCHFile(Filename, Diags);
+ if (!AST)
+ goto failure;
+
+ setCurrentFile(Filename, InputKind, AST);
+
+ // Set the shared objects, these are reset when we finish processing the
+ // file, otherwise the CompilerInstance will happily destroy them.
+ CI.setFileManager(&AST->getFileManager());
+ CI.setSourceManager(&AST->getSourceManager());
+ CI.setPreprocessor(&AST->getPreprocessor());
+ CI.setASTContext(&AST->getASTContext());
+
+ // Initialize the action.
+ if (!BeginSourceFileAction(CI, Filename))
+ goto failure;
+
+ /// Create the AST consumer.
+ CI.setASTConsumer(CreateASTConsumer(CI, Filename));
+ if (!CI.hasASTConsumer())
+ goto failure;
+
+ return true;
+ }
+
+ // Set up the file and source managers, if needed.
+ if (!CI.hasFileManager())
+ CI.createFileManager();
+ if (!CI.hasSourceManager())
+ CI.createSourceManager();
+
+ // IR files bypass the rest of initialization.
+ if (InputKind == IK_LLVM_IR) {
+ assert(hasIRSupport() &&
+ "This action does not have IR file support!");
+
+ // Inform the diagnostic client we are processing a source file.
+ CI.getDiagnosticClient().BeginSourceFile(CI.getLangOpts(), 0);
+
+ // Initialize the action.
+ if (!BeginSourceFileAction(CI, Filename))
+ goto failure;
+
+ return true;
+ }
+
+ // Set up the preprocessor.
+ CI.createPreprocessor();
+
+ // Inform the diagnostic client we are processing a source file.
+ CI.getDiagnosticClient().BeginSourceFile(CI.getLangOpts(),
+ &CI.getPreprocessor());
+
+ // Initialize the action.
+ if (!BeginSourceFileAction(CI, Filename))
+ goto failure;
+
+ /// Create the AST context and consumer unless this is a preprocessor only
+ /// action.
+ if (!usesPreprocessorOnly()) {
+ CI.createASTContext();
+
+ /// Use PCH? If so, we want the PCHReader active before the consumer
+ /// is created, because the consumer might be interested in the reader
+ /// (e.g. the PCH writer for chaining).
+ if (!CI.getPreprocessorOpts().ImplicitPCHInclude.empty()) {
+ assert(hasPCHSupport() && "This action does not have PCH support!");
+ CI.createPCHExternalASTSource(
+ CI.getPreprocessorOpts().ImplicitPCHInclude);
+ if (!CI.getASTContext().getExternalSource())
+ goto failure;
+ }
+
+ CI.setASTConsumer(CreateASTConsumer(CI, Filename));
+ if (!CI.hasASTConsumer())
+ goto failure;
+ }
+
+ // Initialize builtin info as long as we aren't using an external AST
+ // source.
+ if (!CI.hasASTContext() || !CI.getASTContext().getExternalSource()) {
+ Preprocessor &PP = CI.getPreprocessor();
+ PP.getBuiltinInfo().InitializeBuiltins(PP.getIdentifierTable(),
+ PP.getLangOptions().NoBuiltin);
+ }
+
+ return true;
+
+ // If we failed, reset state since the client will not end up calling the
+ // matching EndSourceFile().
+ failure:
+ if (isCurrentFileAST()) {
+ CI.takeASTContext();
+ CI.takePreprocessor();
+ CI.takeSourceManager();
+ CI.takeFileManager();
+ }
+
+ CI.getDiagnosticClient().EndSourceFile();
+ setCurrentFile("", IK_None);
+ setCompilerInstance(0);
+ return false;
+}
+
+void FrontendAction::Execute() {
+ CompilerInstance &CI = getCompilerInstance();
+
+ // Initialize the main file entry. This needs to be delayed until after PCH
+ // has loaded.
+ if (isCurrentFileAST()) {
+ // Set the main file ID to an empty file.
+ //
+ // FIXME: We probably shouldn't need this, but for now this is the
+ // simplest way to reuse the logic in ParseAST.
+ const char *EmptyStr = "";
+ llvm::MemoryBuffer *SB =
+ llvm::MemoryBuffer::getMemBuffer(EmptyStr, "<dummy input>");
+ CI.getSourceManager().createMainFileIDForMemBuffer(SB);
+ } else {
+ if (!CI.InitializeSourceManager(getCurrentFile()))
+ return;
+ }
+
+ if (CI.hasFrontendTimer()) {
+ llvm::TimeRegion Timer(CI.getFrontendTimer());
+ ExecuteAction();
+ }
+ else ExecuteAction();
+}
+
+void FrontendAction::EndSourceFile() {
+ CompilerInstance &CI = getCompilerInstance();
+
+ // Finalize the action.
+ EndSourceFileAction();
+
+ // Release the consumer and the AST, in that order since the consumer may
+ // perform actions in its destructor which require the context.
+ //
+ // FIXME: There is more per-file stuff we could just drop here?
+ if (CI.getFrontendOpts().DisableFree) {
+ CI.takeASTConsumer();
+ if (!isCurrentFileAST())
+ CI.takeASTContext();
+ } else {
+ CI.setASTConsumer(0);
+ if (!isCurrentFileAST())
+ CI.setASTContext(0);
+ }
+
+ // Inform the preprocessor we are done.
+ if (CI.hasPreprocessor())
+ CI.getPreprocessor().EndSourceFile();
+
+ if (CI.getFrontendOpts().ShowStats) {
+ llvm::errs() << "\nSTATISTICS FOR '" << getCurrentFile() << "':\n";
+ CI.getPreprocessor().PrintStats();
+ CI.getPreprocessor().getIdentifierTable().PrintStats();
+ CI.getPreprocessor().getHeaderSearchInfo().PrintStats();
+ CI.getSourceManager().PrintStats();
+ llvm::errs() << "\n";
+ }
+
+ // Cleanup the output streams, and erase the output files if we encountered
+ // an error.
+ CI.clearOutputFiles(/*EraseFiles=*/CI.getDiagnostics().getNumErrors());
+
+ // Inform the diagnostic client we are done with this source file.
+ CI.getDiagnosticClient().EndSourceFile();
+
+ if (isCurrentFileAST()) {
+ CI.takeASTContext();
+ CI.takePreprocessor();
+ CI.takeSourceManager();
+ CI.takeFileManager();
+ }
+
+ setCompilerInstance(0);
+ setCurrentFile("", IK_None);
+}
+
+//===----------------------------------------------------------------------===//
+// Utility Actions
+//===----------------------------------------------------------------------===//
+
+void ASTFrontendAction::ExecuteAction() {
+ CompilerInstance &CI = getCompilerInstance();
+
+ // FIXME: Move the truncation aspect of this into Sema, we delayed this till
+ // here so the source manager would be initialized.
+ if (hasCodeCompletionSupport() &&
+ !CI.getFrontendOpts().CodeCompletionAt.FileName.empty())
+ CI.createCodeCompletionConsumer();
+
+ // Use a code completion consumer?
+ CodeCompleteConsumer *CompletionConsumer = 0;
+ if (CI.hasCodeCompletionConsumer())
+ CompletionConsumer = &CI.getCodeCompletionConsumer();
+
+ ParseAST(CI.getPreprocessor(), &CI.getASTConsumer(), CI.getASTContext(),
+ CI.getFrontendOpts().ShowStats,
+ usesCompleteTranslationUnit(), CompletionConsumer);
+}
+
+ASTConsumer *
+PreprocessorFrontendAction::CreateASTConsumer(CompilerInstance &CI,
+ llvm::StringRef InFile) {
+ llvm_unreachable("Invalid CreateASTConsumer on preprocessor action!");
+}
diff --git a/contrib/llvm/tools/clang/lib/Frontend/FrontendActions.cpp b/contrib/llvm/tools/clang/lib/Frontend/FrontendActions.cpp
new file mode 100644
index 0000000..3a53dee
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Frontend/FrontendActions.cpp
@@ -0,0 +1,194 @@
+//===--- FrontendActions.cpp ----------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/Lex/Pragma.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Parse/Parser.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Frontend/ASTConsumers.h"
+#include "clang/Frontend/ASTUnit.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
+#include "clang/Frontend/Utils.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/Support/raw_ostream.h"
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// Custom Actions
+//===----------------------------------------------------------------------===//
+
+ASTConsumer *InitOnlyAction::CreateASTConsumer(CompilerInstance &CI,
+ llvm::StringRef InFile) {
+ return new ASTConsumer();
+}
+
+void InitOnlyAction::ExecuteAction() {
+}
+
+//===----------------------------------------------------------------------===//
+// AST Consumer Actions
+//===----------------------------------------------------------------------===//
+
+ASTConsumer *ASTPrintAction::CreateASTConsumer(CompilerInstance &CI,
+ llvm::StringRef InFile) {
+ if (llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, InFile))
+ return CreateASTPrinter(OS);
+ return 0;
+}
+
+ASTConsumer *ASTPrintXMLAction::CreateASTConsumer(CompilerInstance &CI,
+ llvm::StringRef InFile) {
+ if (llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, InFile, "xml"))
+ return CreateASTPrinterXML(OS);
+ return 0;
+}
+
+ASTConsumer *ASTDumpAction::CreateASTConsumer(CompilerInstance &CI,
+ llvm::StringRef InFile) {
+ return CreateASTDumper();
+}
+
+ASTConsumer *ASTViewAction::CreateASTConsumer(CompilerInstance &CI,
+ llvm::StringRef InFile) {
+ return CreateASTViewer();
+}
+
+ASTConsumer *DeclContextPrintAction::CreateASTConsumer(CompilerInstance &CI,
+ llvm::StringRef InFile) {
+ return CreateDeclContextPrinter();
+}
+
+ASTConsumer *GeneratePCHAction::CreateASTConsumer(CompilerInstance &CI,
+ llvm::StringRef InFile) {
+ const std::string &Sysroot = CI.getHeaderSearchOpts().Sysroot;
+ if (CI.getFrontendOpts().RelocatablePCH &&
+ Sysroot.empty()) {
+ CI.getDiagnostics().Report(diag::err_relocatable_without_without_isysroot);
+ return 0;
+ }
+
+ llvm::raw_ostream *OS = CI.createDefaultOutputFile(true, InFile);
+ if (!OS)
+ return 0;
+
+ PCHReader *Chain = CI.getInvocation().getFrontendOpts().ChainedPCH ?
+ CI.getPCHReader() : 0;
+ const char *isysroot = CI.getFrontendOpts().RelocatablePCH ?
+ Sysroot.c_str() : 0;
+ return CreatePCHGenerator(CI.getPreprocessor(), OS, Chain, isysroot);
+}
+
+ASTConsumer *InheritanceViewAction::CreateASTConsumer(CompilerInstance &CI,
+ llvm::StringRef InFile) {
+ return CreateInheritanceViewer(CI.getFrontendOpts().ViewClassInheritance);
+}
+
+ASTConsumer *SyntaxOnlyAction::CreateASTConsumer(CompilerInstance &CI,
+ llvm::StringRef InFile) {
+ return new ASTConsumer();
+}
+
+//===----------------------------------------------------------------------===//
+// Preprocessor Actions
+//===----------------------------------------------------------------------===//
+
+void DumpRawTokensAction::ExecuteAction() {
+ Preprocessor &PP = getCompilerInstance().getPreprocessor();
+ SourceManager &SM = PP.getSourceManager();
+
+ // Start lexing the specified input file.
+ const llvm::MemoryBuffer *FromFile = SM.getBuffer(SM.getMainFileID());
+ Lexer RawLex(SM.getMainFileID(), FromFile, SM, PP.getLangOptions());
+ RawLex.SetKeepWhitespaceMode(true);
+
+ Token RawTok;
+ RawLex.LexFromRawLexer(RawTok);
+ while (RawTok.isNot(tok::eof)) {
+ PP.DumpToken(RawTok, true);
+ llvm::errs() << "\n";
+ RawLex.LexFromRawLexer(RawTok);
+ }
+}
+
+void DumpTokensAction::ExecuteAction() {
+ Preprocessor &PP = getCompilerInstance().getPreprocessor();
+ // Start preprocessing the specified input file.
+ Token Tok;
+ PP.EnterMainSourceFile();
+ do {
+ PP.Lex(Tok);
+ PP.DumpToken(Tok, true);
+ llvm::errs() << "\n";
+ } while (Tok.isNot(tok::eof));
+}
+
+void GeneratePTHAction::ExecuteAction() {
+ CompilerInstance &CI = getCompilerInstance();
+ if (CI.getFrontendOpts().OutputFile.empty() ||
+ CI.getFrontendOpts().OutputFile == "-") {
+ // FIXME: Don't fail this way.
+ // FIXME: Verify that we can actually seek in the given file.
+ llvm::report_fatal_error("PTH requires a seekable file for output!");
+ }
+ llvm::raw_fd_ostream *OS =
+ CI.createDefaultOutputFile(true, getCurrentFile());
+ if (!OS) return;
+
+ CacheTokens(CI.getPreprocessor(), OS);
+}
+
+void ParseOnlyAction::ExecuteAction() {
+ Preprocessor &PP = getCompilerInstance().getPreprocessor();
+ llvm::OwningPtr<Action> PA(new MinimalAction(PP));
+
+ Parser P(PP, *PA);
+ PP.EnterMainSourceFile();
+ P.ParseTranslationUnit();
+}
+
+void PreprocessOnlyAction::ExecuteAction() {
+ Preprocessor &PP = getCompilerInstance().getPreprocessor();
+
+ // Ignore unknown pragmas.
+ PP.AddPragmaHandler(new EmptyPragmaHandler());
+
+ Token Tok;
+ // Start parsing the specified input file.
+ PP.EnterMainSourceFile();
+ do {
+ PP.Lex(Tok);
+ } while (Tok.isNot(tok::eof));
+}
+
+void PrintParseAction::ExecuteAction() {
+ CompilerInstance &CI = getCompilerInstance();
+ Preprocessor &PP = getCompilerInstance().getPreprocessor();
+ llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, getCurrentFile());
+ if (!OS) return;
+
+ llvm::OwningPtr<Action> PA(CreatePrintParserActionsAction(PP, OS));
+
+ Parser P(PP, *PA);
+ PP.EnterMainSourceFile();
+ P.ParseTranslationUnit();
+}
+
+void PrintPreprocessedAction::ExecuteAction() {
+ CompilerInstance &CI = getCompilerInstance();
+ // Output file needs to be set to 'Binary', to avoid converting Unix style
+ // line feeds (<LF>) to Microsoft style line feeds (<CR><LF>).
+ llvm::raw_ostream *OS = CI.createDefaultOutputFile(true, getCurrentFile());
+ if (!OS) return;
+
+ DoPrintPreprocessedInput(CI.getPreprocessor(), OS,
+ CI.getPreprocessorOutputOpts());
+}
diff --git a/contrib/llvm/tools/clang/lib/Frontend/FrontendOptions.cpp b/contrib/llvm/tools/clang/lib/Frontend/FrontendOptions.cpp
new file mode 100644
index 0000000..9dfee24
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Frontend/FrontendOptions.cpp
@@ -0,0 +1,31 @@
+//===--- FrontendOptions.cpp ----------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/FrontendOptions.h"
+#include "llvm/ADT/StringSwitch.h"
+using namespace clang;
+
+InputKind FrontendOptions::getInputKindForExtension(llvm::StringRef Extension) {
+ return llvm::StringSwitch<InputKind>(Extension)
+ .Case("ast", IK_AST)
+ .Case("c", IK_C)
+ .Cases("S", "s", IK_Asm)
+ .Case("i", IK_PreprocessedC)
+ .Case("ii", IK_PreprocessedCXX)
+ .Case("m", IK_ObjC)
+ .Case("mi", IK_PreprocessedObjC)
+ .Cases("mm", "M", IK_ObjCXX)
+ .Case("mii", IK_PreprocessedObjCXX)
+ .Case("C", IK_CXX)
+ .Cases("C", "cc", "cp", IK_CXX)
+ .Cases("cpp", "CPP", "c++", "cxx", "hpp", IK_CXX)
+ .Case("cl", IK_OpenCL)
+ .Cases("ll", "bc", IK_LLVM_IR)
+ .Default(IK_C);
+}
diff --git a/contrib/llvm/tools/clang/lib/Frontend/GeneratePCH.cpp b/contrib/llvm/tools/clang/lib/Frontend/GeneratePCH.cpp
new file mode 100644
index 0000000..2f3df94
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Frontend/GeneratePCH.cpp
@@ -0,0 +1,83 @@
+//===--- GeneratePCH.cpp - AST Consumer for PCH Generation ------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the CreatePCHGenerate function, which creates an
+// ASTConsume that generates a PCH file.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/ASTConsumers.h"
+#include "clang/Frontend/PCHWriter.h"
+#include "clang/Sema/SemaConsumer.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Basic/FileManager.h"
+#include "llvm/Bitcode/BitstreamWriter.h"
+#include "llvm/Support/raw_ostream.h"
+#include <string>
+
+using namespace clang;
+
+namespace {
+ class PCHGenerator : public SemaConsumer {
+ const Preprocessor &PP;
+ const char *isysroot;
+ llvm::raw_ostream *Out;
+ Sema *SemaPtr;
+ MemorizeStatCalls *StatCalls; // owned by the FileManager
+ std::vector<unsigned char> Buffer;
+ llvm::BitstreamWriter Stream;
+ PCHWriter Writer;
+
+ public:
+ PCHGenerator(const Preprocessor &PP, PCHReader *Chain,
+ const char *isysroot, llvm::raw_ostream *Out);
+ virtual void InitializeSema(Sema &S) { SemaPtr = &S; }
+ virtual void HandleTranslationUnit(ASTContext &Ctx);
+ };
+}
+
+PCHGenerator::PCHGenerator(const Preprocessor &PP,
+ PCHReader *Chain,
+ const char *isysroot,
+ llvm::raw_ostream *OS)
+ : PP(PP), isysroot(isysroot), Out(OS), SemaPtr(0), StatCalls(0),
+ Stream(Buffer), Writer(Stream, Chain) {
+
+ // Install a stat() listener to keep track of all of the stat()
+ // calls.
+ StatCalls = new MemorizeStatCalls;
+ PP.getFileManager().addStatCache(StatCalls, /*AtBeginning=*/true);
+}
+
+void PCHGenerator::HandleTranslationUnit(ASTContext &Ctx) {
+ if (PP.getDiagnostics().hasErrorOccurred())
+ return;
+
+ // Emit the PCH file
+ assert(SemaPtr && "No Sema?");
+ Writer.WritePCH(*SemaPtr, StatCalls, isysroot);
+
+ // Write the generated bitstream to "Out".
+ Out->write((char *)&Buffer.front(), Buffer.size());
+
+ // Make sure it hits disk now.
+ Out->flush();
+
+ // Free up some memory, in case the process is kept alive.
+ Buffer.clear();
+}
+
+ASTConsumer *clang::CreatePCHGenerator(const Preprocessor &PP,
+ llvm::raw_ostream *OS,
+ PCHReader *Chain,
+ const char *isysroot) {
+ return new PCHGenerator(PP, Chain, isysroot, OS);
+}
diff --git a/contrib/llvm/tools/clang/lib/Frontend/InitHeaderSearch.cpp b/contrib/llvm/tools/clang/lib/Frontend/InitHeaderSearch.cpp
new file mode 100644
index 0000000..fcfee712
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Frontend/InitHeaderSearch.cpp
@@ -0,0 +1,916 @@
+//===--- InitHeaderSearch.cpp - Initialize header search paths ----------*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the InitHeaderSearch class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/Utils.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/Version.h"
+#include "clang/Frontend/HeaderSearchOptions.h"
+#include "clang/Lex/HeaderSearch.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/System/Path.h"
+#include "llvm/Config/config.h"
+#ifdef _MSC_VER
+ #define WIN32_LEAN_AND_MEAN 1
+ #include <windows.h>
+#endif
+using namespace clang;
+using namespace clang::frontend;
+
+namespace {
+
+/// InitHeaderSearch - This class makes it easier to set the search paths of
+/// a HeaderSearch object. InitHeaderSearch stores several search path lists
+/// internally, which can be sent to a HeaderSearch object in one swoop.
+class InitHeaderSearch {
+ std::vector<DirectoryLookup> IncludeGroup[4];
+ HeaderSearch& Headers;
+ bool Verbose;
+ std::string isysroot;
+
+public:
+
+ InitHeaderSearch(HeaderSearch &HS,
+ bool verbose = false, const std::string &iSysroot = "")
+ : Headers(HS), Verbose(verbose), isysroot(iSysroot) {}
+
+ /// AddPath - Add the specified path to the specified group list.
+ void AddPath(const llvm::Twine &Path, IncludeDirGroup Group,
+ bool isCXXAware, bool isUserSupplied,
+ bool isFramework, bool IgnoreSysRoot = false);
+
+ /// AddGnuCPlusPlusIncludePaths - Add the necessary paths to support a gnu
+ /// libstdc++.
+ void AddGnuCPlusPlusIncludePaths(llvm::StringRef Base,
+ llvm::StringRef ArchDir,
+ llvm::StringRef Dir32,
+ llvm::StringRef Dir64,
+ const llvm::Triple &triple);
+
+ /// AddMinGWCPlusPlusIncludePaths - Add the necessary paths to suport a MinGW
+ /// libstdc++.
+ void AddMinGWCPlusPlusIncludePaths(llvm::StringRef Base,
+ llvm::StringRef Arch,
+ llvm::StringRef Version);
+
+ /// AddDelimitedPaths - Add a list of paths delimited by the system PATH
+ /// separator. The processing follows that of the CPATH variable for gcc.
+ void AddDelimitedPaths(llvm::StringRef String);
+
+ // AddDefaultCIncludePaths - Add paths that should always be searched.
+ void AddDefaultCIncludePaths(const llvm::Triple &triple,
+ const HeaderSearchOptions &HSOpts);
+
+ // AddDefaultCPlusPlusIncludePaths - Add paths that should be searched when
+ // compiling c++.
+ void AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple);
+
+ /// AddDefaultSystemIncludePaths - Adds the default system include paths so
+ /// that e.g. stdio.h is found.
+ void AddDefaultSystemIncludePaths(const LangOptions &Lang,
+ const llvm::Triple &triple,
+ const HeaderSearchOptions &HSOpts);
+
+ /// Realize - Merges all search path lists into one list and send it to
+ /// HeaderSearch.
+ void Realize();
+};
+
+}
+
+void InitHeaderSearch::AddPath(const llvm::Twine &Path,
+ IncludeDirGroup Group, bool isCXXAware,
+ bool isUserSupplied, bool isFramework,
+ bool IgnoreSysRoot) {
+ assert(!Path.isTriviallyEmpty() && "can't handle empty path here");
+ FileManager &FM = Headers.getFileMgr();
+
+ // Compute the actual path, taking into consideration -isysroot.
+ llvm::SmallString<256> MappedPathStr;
+ llvm::raw_svector_ostream MappedPath(MappedPathStr);
+
+ // Handle isysroot.
+ if (Group == System && !IgnoreSysRoot) {
+ // FIXME: Portability. This should be a sys::Path interface, this doesn't
+ // handle things like C:\ right, nor win32 \\network\device\blah.
+ if (isysroot.size() != 1 || isysroot[0] != '/') // Add isysroot if present.
+ MappedPath << isysroot;
+ }
+
+ Path.print(MappedPath);
+
+ // Compute the DirectoryLookup type.
+ SrcMgr::CharacteristicKind Type;
+ if (Group == Quoted || Group == Angled)
+ Type = SrcMgr::C_User;
+ else if (isCXXAware)
+ Type = SrcMgr::C_System;
+ else
+ Type = SrcMgr::C_ExternCSystem;
+
+
+ // If the directory exists, add it.
+ if (const DirectoryEntry *DE = FM.getDirectory(MappedPath.str())) {
+ IncludeGroup[Group].push_back(DirectoryLookup(DE, Type, isUserSupplied,
+ isFramework));
+ return;
+ }
+
+ // Check to see if this is an apple-style headermap (which are not allowed to
+ // be frameworks).
+ if (!isFramework) {
+ if (const FileEntry *FE = FM.getFile(MappedPath.str())) {
+ if (const HeaderMap *HM = Headers.CreateHeaderMap(FE)) {
+ // It is a headermap, add it to the search path.
+ IncludeGroup[Group].push_back(DirectoryLookup(HM, Type,isUserSupplied));
+ return;
+ }
+ }
+ }
+
+ if (Verbose)
+ llvm::errs() << "ignoring nonexistent directory \""
+ << MappedPath.str() << "\"\n";
+}
+
+
+void InitHeaderSearch::AddDelimitedPaths(llvm::StringRef at) {
+ if (at.empty()) // Empty string should not add '.' path.
+ return;
+
+ llvm::StringRef::size_type delim;
+ while ((delim = at.find(llvm::sys::PathSeparator)) != llvm::StringRef::npos) {
+ if (delim == 0)
+ AddPath(".", Angled, false, true, false);
+ else
+ AddPath(at.substr(0, delim), Angled, false, true, false);
+ at = at.substr(delim + 1);
+ }
+
+ if (at.empty())
+ AddPath(".", Angled, false, true, false);
+ else
+ AddPath(at, Angled, false, true, false);
+}
+
+void InitHeaderSearch::AddGnuCPlusPlusIncludePaths(llvm::StringRef Base,
+ llvm::StringRef ArchDir,
+ llvm::StringRef Dir32,
+ llvm::StringRef Dir64,
+ const llvm::Triple &triple) {
+ // Add the base dir
+ AddPath(Base, System, true, false, false);
+
+ // Add the multilib dirs
+ llvm::Triple::ArchType arch = triple.getArch();
+ bool is64bit = arch == llvm::Triple::ppc64 || arch == llvm::Triple::x86_64;
+ if (is64bit)
+ AddPath(Base + "/" + ArchDir + "/" + Dir64, System, true, false, false);
+ else
+ AddPath(Base + "/" + ArchDir + "/" + Dir32, System, true, false, false);
+
+ // Add the backward dir
+ AddPath(Base + "/backward", System, true, false, false);
+}
+
+void InitHeaderSearch::AddMinGWCPlusPlusIncludePaths(llvm::StringRef Base,
+ llvm::StringRef Arch,
+ llvm::StringRef Version) {
+ AddPath(Base + "/" + Arch + "/" + Version + "/include",
+ System, true, false, false);
+ AddPath(Base + "/" + Arch + "/" + Version + "/include/c++",
+ System, true, false, false);
+ AddPath(Base + "/" + Arch + "/" + Version + "/include/c++/backward",
+ System, true, false, false);
+}
+
+ // FIXME: This probably should goto to some platform utils place.
+#ifdef _MSC_VER
+
+ // Read registry string.
+ // This also supports a means to look for high-versioned keys by use
+ // of a $VERSION placeholder in the key path.
+ // $VERSION in the key path is a placeholder for the version number,
+ // causing the highest value path to be searched for and used.
+ // I.e. "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\$VERSION".
+ // There can be additional characters in the component. Only the numberic
+ // characters are compared.
+static bool getSystemRegistryString(const char *keyPath, const char *valueName,
+ char *value, size_t maxLength) {
+ HKEY hRootKey = NULL;
+ HKEY hKey = NULL;
+ const char* subKey = NULL;
+ DWORD valueType;
+ DWORD valueSize = maxLength - 1;
+ long lResult;
+ bool returnValue = false;
+ if (strncmp(keyPath, "HKEY_CLASSES_ROOT\\", 18) == 0) {
+ hRootKey = HKEY_CLASSES_ROOT;
+ subKey = keyPath + 18;
+ }
+ else if (strncmp(keyPath, "HKEY_USERS\\", 11) == 0) {
+ hRootKey = HKEY_USERS;
+ subKey = keyPath + 11;
+ }
+ else if (strncmp(keyPath, "HKEY_LOCAL_MACHINE\\", 19) == 0) {
+ hRootKey = HKEY_LOCAL_MACHINE;
+ subKey = keyPath + 19;
+ }
+ else if (strncmp(keyPath, "HKEY_CURRENT_USER\\", 18) == 0) {
+ hRootKey = HKEY_CURRENT_USER;
+ subKey = keyPath + 18;
+ }
+ else
+ return(false);
+ const char *placeHolder = strstr(subKey, "$VERSION");
+ char bestName[256];
+ bestName[0] = '\0';
+ // If we have a $VERSION placeholder, do the highest-version search.
+ if (placeHolder) {
+ const char *keyEnd = placeHolder - 1;
+ const char *nextKey = placeHolder;
+ // Find end of previous key.
+ while ((keyEnd > subKey) && (*keyEnd != '\\'))
+ keyEnd--;
+ // Find end of key containing $VERSION.
+ while (*nextKey && (*nextKey != '\\'))
+ nextKey++;
+ size_t partialKeyLength = keyEnd - subKey;
+ char partialKey[256];
+ if (partialKeyLength > sizeof(partialKey))
+ partialKeyLength = sizeof(partialKey);
+ strncpy(partialKey, subKey, partialKeyLength);
+ partialKey[partialKeyLength] = '\0';
+ HKEY hTopKey = NULL;
+ lResult = RegOpenKeyEx(hRootKey, partialKey, 0, KEY_READ, &hTopKey);
+ if (lResult == ERROR_SUCCESS) {
+ char keyName[256];
+ int bestIndex = -1;
+ double bestValue = 0.0;
+ DWORD index, size = sizeof(keyName) - 1;
+ for (index = 0; RegEnumKeyEx(hTopKey, index, keyName, &size, NULL,
+ NULL, NULL, NULL) == ERROR_SUCCESS; index++) {
+ const char *sp = keyName;
+ while (*sp && !isdigit(*sp))
+ sp++;
+ if (!*sp)
+ continue;
+ const char *ep = sp + 1;
+ while (*ep && (isdigit(*ep) || (*ep == '.')))
+ ep++;
+ char numBuf[32];
+ strncpy(numBuf, sp, sizeof(numBuf) - 1);
+ numBuf[sizeof(numBuf) - 1] = '\0';
+ double value = strtod(numBuf, NULL);
+ if (value > bestValue) {
+ bestIndex = (int)index;
+ bestValue = value;
+ strcpy(bestName, keyName);
+ }
+ size = sizeof(keyName) - 1;
+ }
+ // If we found the highest versioned key, open the key and get the value.
+ if (bestIndex != -1) {
+ // Append rest of key.
+ strncat(bestName, nextKey, sizeof(bestName) - 1);
+ bestName[sizeof(bestName) - 1] = '\0';
+ // Open the chosen key path remainder.
+ lResult = RegOpenKeyEx(hTopKey, bestName, 0, KEY_READ, &hKey);
+ if (lResult == ERROR_SUCCESS) {
+ lResult = RegQueryValueEx(hKey, valueName, NULL, &valueType,
+ (LPBYTE)value, &valueSize);
+ if (lResult == ERROR_SUCCESS)
+ returnValue = true;
+ RegCloseKey(hKey);
+ }
+ }
+ RegCloseKey(hTopKey);
+ }
+ }
+ else {
+ lResult = RegOpenKeyEx(hRootKey, subKey, 0, KEY_READ, &hKey);
+ if (lResult == ERROR_SUCCESS) {
+ lResult = RegQueryValueEx(hKey, valueName, NULL, &valueType,
+ (LPBYTE)value, &valueSize);
+ if (lResult == ERROR_SUCCESS)
+ returnValue = true;
+ RegCloseKey(hKey);
+ }
+ }
+ return(returnValue);
+}
+#else // _MSC_VER
+ // Read registry string.
+static bool getSystemRegistryString(const char*, const char*, char*, size_t) {
+ return(false);
+}
+#endif // _MSC_VER
+
+ // Get Visual Studio installation directory.
+static bool getVisualStudioDir(std::string &path) {
+ char vsIDEInstallDir[256];
+ char vsExpressIDEInstallDir[256];
+ // Try the Windows registry first.
+ bool hasVCDir = getSystemRegistryString(
+ "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\$VERSION",
+ "InstallDir", vsIDEInstallDir, sizeof(vsIDEInstallDir) - 1);
+ bool hasVCExpressDir = getSystemRegistryString(
+ "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VCExpress\\$VERSION",
+ "InstallDir", vsExpressIDEInstallDir, sizeof(vsExpressIDEInstallDir) - 1);
+ // If we have both vc80 and vc90, pick version we were compiled with.
+ if (hasVCDir && vsIDEInstallDir[0]) {
+ char *p = (char*)strstr(vsIDEInstallDir, "\\Common7\\IDE");
+ if (p)
+ *p = '\0';
+ path = vsIDEInstallDir;
+ return(true);
+ }
+ else if (hasVCExpressDir && vsExpressIDEInstallDir[0]) {
+ char *p = (char*)strstr(vsExpressIDEInstallDir, "\\Common7\\IDE");
+ if (p)
+ *p = '\0';
+ path = vsExpressIDEInstallDir;
+ return(true);
+ }
+ else {
+ // Try the environment.
+ const char* vs100comntools = getenv("VS100COMNTOOLS");
+ const char* vs90comntools = getenv("VS90COMNTOOLS");
+ const char* vs80comntools = getenv("VS80COMNTOOLS");
+ const char* vscomntools = NULL;
+
+ // Try to find the version that we were compiled with
+ if(false) {}
+ #if (_MSC_VER >= 1600) // VC100
+ else if(vs100comntools) {
+ vscomntools = vs100comntools;
+ }
+ #elif (_MSC_VER == 1500) // VC80
+ else if(vs90comntools) {
+ vscomntools = vs90comntools;
+ }
+ #elif (_MSC_VER == 1400) // VC80
+ else if(vs80comntools) {
+ vscomntools = vs80comntools;
+ }
+ #endif
+ // Otherwise find any version we can
+ else if (vs100comntools)
+ vscomntools = vs100comntools;
+ else if (vs90comntools)
+ vscomntools = vs90comntools;
+ else if (vs80comntools)
+ vscomntools = vs80comntools;
+
+ if (vscomntools && *vscomntools) {
+ char *p = const_cast<char *>(strstr(vscomntools, "\\Common7\\Tools"));
+ if (p)
+ *p = '\0';
+ path = vscomntools;
+ return(true);
+ }
+ else
+ return(false);
+ }
+ return(false);
+}
+
+ // Get Windows SDK installation directory.
+static bool getWindowsSDKDir(std::string &path) {
+ char windowsSDKInstallDir[256];
+ // Try the Windows registry.
+ bool hasSDKDir = getSystemRegistryString(
+ "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\$VERSION",
+ "InstallationFolder", windowsSDKInstallDir, sizeof(windowsSDKInstallDir) - 1);
+ // If we have both vc80 and vc90, pick version we were compiled with.
+ if (hasSDKDir && windowsSDKInstallDir[0]) {
+ path = windowsSDKInstallDir;
+ return(true);
+ }
+ return(false);
+}
+
+void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple,
+ const HeaderSearchOptions &HSOpts) {
+#if 0 /* Remove unneeded include paths. */
+ // FIXME: temporary hack: hard-coded paths.
+ AddPath("/usr/local/include", System, true, false, false);
+
+ // Builtin includes use #include_next directives and should be positioned
+ // just prior C include dirs.
+ if (HSOpts.UseBuiltinIncludes) {
+ // Ignore the sys root, we *always* look for clang headers relative to
+ // supplied path.
+ llvm::sys::Path P(HSOpts.ResourceDir);
+ P.appendComponent("include");
+ AddPath(P.str(), System, false, false, false, /*IgnoreSysRoot=*/ true);
+ }
+#endif
+
+ // Add dirs specified via 'configure --with-c-include-dirs'.
+ llvm::StringRef CIncludeDirs(C_INCLUDE_DIRS);
+ if (CIncludeDirs != "") {
+ llvm::SmallVector<llvm::StringRef, 5> dirs;
+ CIncludeDirs.split(dirs, ":");
+ for (llvm::SmallVectorImpl<llvm::StringRef>::iterator i = dirs.begin();
+ i != dirs.end();
+ ++i)
+ AddPath(*i, System, false, false, false);
+ return;
+ }
+ llvm::Triple::OSType os = triple.getOS();
+ switch (os) {
+ case llvm::Triple::Win32:
+ {
+ std::string VSDir;
+ std::string WindowsSDKDir;
+ if (getVisualStudioDir(VSDir)) {
+ AddPath(VSDir + "\\VC\\include", System, false, false, false);
+ if (getWindowsSDKDir(WindowsSDKDir))
+ AddPath(WindowsSDKDir, System, false, false, false);
+ else
+ AddPath(VSDir + "\\VC\\PlatformSDK\\Include",
+ System, false, false, false);
+ }
+ else {
+ // Default install paths.
+ AddPath("C:/Program Files/Microsoft Visual Studio 10.0/VC/include",
+ System, false, false, false);
+ AddPath("C:/Program Files/Microsoft Visual Studio 9.0/VC/include",
+ System, false, false, false);
+ AddPath(
+ "C:/Program Files/Microsoft Visual Studio 9.0/VC/PlatformSDK/Include",
+ System, false, false, false);
+ AddPath("C:/Program Files/Microsoft Visual Studio 8/VC/include",
+ System, false, false, false);
+ AddPath(
+ "C:/Program Files/Microsoft Visual Studio 8/VC/PlatformSDK/Include",
+ System, false, false, false);
+ // For some clang developers.
+ AddPath("G:/Program Files/Microsoft Visual Studio 9.0/VC/include",
+ System, false, false, false);
+ AddPath(
+ "G:/Program Files/Microsoft Visual Studio 9.0/VC/PlatformSDK/Include",
+ System, false, false, false);
+ }
+ }
+ break;
+ case llvm::Triple::Haiku:
+ AddPath("/boot/common/include", System, true, false, false);
+ AddPath("/boot/develop/headers/os", System, true, false, false);
+ AddPath("/boot/develop/headers/os/app", System, true, false, false);
+ AddPath("/boot/develop/headers/os/arch", System, true, false, false);
+ AddPath("/boot/develop/headers/os/device", System, true, false, false);
+ AddPath("/boot/develop/headers/os/drivers", System, true, false, false);
+ AddPath("/boot/develop/headers/os/game", System, true, false, false);
+ AddPath("/boot/develop/headers/os/interface", System, true, false, false);
+ AddPath("/boot/develop/headers/os/kernel", System, true, false, false);
+ AddPath("/boot/develop/headers/os/locale", System, true, false, false);
+ AddPath("/boot/develop/headers/os/mail", System, true, false, false);
+ AddPath("/boot/develop/headers/os/media", System, true, false, false);
+ AddPath("/boot/develop/headers/os/midi", System, true, false, false);
+ AddPath("/boot/develop/headers/os/midi2", System, true, false, false);
+ AddPath("/boot/develop/headers/os/net", System, true, false, false);
+ AddPath("/boot/develop/headers/os/storage", System, true, false, false);
+ AddPath("/boot/develop/headers/os/support", System, true, false, false);
+ AddPath("/boot/develop/headers/os/translation",
+ System, true, false, false);
+ AddPath("/boot/develop/headers/os/add-ons/graphics",
+ System, true, false, false);
+ AddPath("/boot/develop/headers/os/add-ons/input_server",
+ System, true, false, false);
+ AddPath("/boot/develop/headers/os/add-ons/screen_saver",
+ System, true, false, false);
+ AddPath("/boot/develop/headers/os/add-ons/tracker",
+ System, true, false, false);
+ AddPath("/boot/develop/headers/os/be_apps/Deskbar",
+ System, true, false, false);
+ AddPath("/boot/develop/headers/os/be_apps/NetPositive",
+ System, true, false, false);
+ AddPath("/boot/develop/headers/os/be_apps/Tracker",
+ System, true, false, false);
+ AddPath("/boot/develop/headers/cpp", System, true, false, false);
+ AddPath("/boot/develop/headers/cpp/i586-pc-haiku",
+ System, true, false, false);
+ AddPath("/boot/develop/headers/3rdparty", System, true, false, false);
+ AddPath("/boot/develop/headers/bsd", System, true, false, false);
+ AddPath("/boot/develop/headers/glibc", System, true, false, false);
+ AddPath("/boot/develop/headers/posix", System, true, false, false);
+ AddPath("/boot/develop/headers", System, true, false, false);
+ break;
+ case llvm::Triple::MinGW64:
+ case llvm::Triple::MinGW32:
+ AddPath("c:/mingw/include", System, true, false, false);
+ break;
+ default:
+ break;
+ }
+
+ AddPath("/usr/include/clang/" CLANG_VERSION_STRING,
+ System, false, false, false);
+ AddPath("/usr/include", System, false, false, false);
+}
+
+void InitHeaderSearch::
+AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple) {
+ llvm::Triple::OSType os = triple.getOS();
+ llvm::StringRef CxxIncludeRoot(CXX_INCLUDE_ROOT);
+ if (CxxIncludeRoot != "") {
+ llvm::StringRef CxxIncludeArch(CXX_INCLUDE_ARCH);
+ if (CxxIncludeArch == "")
+ AddGnuCPlusPlusIncludePaths(CxxIncludeRoot, triple.str().c_str(),
+ CXX_INCLUDE_32BIT_DIR, CXX_INCLUDE_64BIT_DIR,
+ triple);
+ else
+ AddGnuCPlusPlusIncludePaths(CxxIncludeRoot, CXX_INCLUDE_ARCH,
+ CXX_INCLUDE_32BIT_DIR, CXX_INCLUDE_64BIT_DIR,
+ triple);
+ return;
+ }
+ // FIXME: temporary hack: hard-coded paths.
+ switch (os) {
+ case llvm::Triple::Cygwin:
+ AddPath("/lib/gcc/i686-pc-cygwin/3.4.4/include",
+ System, true, false, false);
+ AddPath("/lib/gcc/i686-pc-cygwin/3.4.4/include/c++",
+ System, true, false, false);
+ AddPath("/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/i686-pc-cygwin",
+ System, true, false, false);
+ break;
+ case llvm::Triple::MinGW64:
+ // Try gcc 4.4.0
+ AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw64", "4.4.0");
+ // Try gcc 4.3.0
+ AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw64", "4.3.0");
+ // Fall through.
+ case llvm::Triple::MinGW32:
+ // Try gcc 4.4.0
+ AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.4.0");
+ // Try gcc 4.3.0
+ AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.3.0");
+ break;
+ case llvm::Triple::Darwin:
+ switch (triple.getArch()) {
+ default: break;
+
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.2.1",
+ "powerpc-apple-darwin10", "", "ppc64",
+ triple);
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.0.0",
+ "powerpc-apple-darwin10", "", "ppc64",
+ triple);
+ break;
+
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.2.1",
+ "i686-apple-darwin10", "", "x86_64", triple);
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.0.0",
+ "i686-apple-darwin8", "", "", triple);
+ break;
+
+ case llvm::Triple::arm:
+ case llvm::Triple::thumb:
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.2.1",
+ "arm-apple-darwin10", "v7", "", triple);
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.2.1",
+ "arm-apple-darwin10", "v6", "", triple);
+ break;
+ }
+ break;
+ case llvm::Triple::DragonFly:
+ AddPath("/usr/include/c++/4.1", System, true, false, false);
+ break;
+ case llvm::Triple::Linux:
+ //===------------------------------------------------------------------===//
+ // Debian based distros.
+ // Note: these distros symlink /usr/include/c++/X.Y.Z -> X.Y
+ //===------------------------------------------------------------------===//
+ // Ubuntu 10.04 LTS "Lucid Lynx" -- gcc-4.4.3
+ // Ubuntu 9.10 "Karmic Koala" -- gcc-4.4.1
+ // Debian 6.0 "squeeze" -- gcc-4.4.2
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4",
+ "x86_64-linux-gnu", "32", "", triple);
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4",
+ "i486-linux-gnu", "", "64", triple);
+ // Ubuntu 9.04 "Jaunty Jackalope" -- gcc-4.3.3
+ // Ubuntu 8.10 "Intrepid Ibex" -- gcc-4.3.2
+ // Debian 5.0 "lenny" -- gcc-4.3.2
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3",
+ "x86_64-linux-gnu", "32", "", triple);
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3",
+ "i486-linux-gnu", "", "64", triple);
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3",
+ "arm-linux-gnueabi", "", "", triple);
+ // Ubuntu 8.04.4 LTS "Hardy Heron" -- gcc-4.2.4
+ // Ubuntu 8.04.[0-3] LTS "Hardy Heron" -- gcc-4.2.3
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.2",
+ "x86_64-linux-gnu", "32", "", triple);
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.2",
+ "i486-linux-gnu", "", "64", triple);
+ // Ubuntu 7.10 "Gutsy Gibbon" -- gcc-4.1.3
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.1",
+ "x86_64-linux-gnu", "32", "", triple);
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.1",
+ "i486-linux-gnu", "", "64", triple);
+
+ //===------------------------------------------------------------------===//
+ // Redhat based distros.
+ //===------------------------------------------------------------------===//
+ // Fedora 13
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.4",
+ "x86_64-redhat-linux", "32", "", triple);
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.4",
+ "i686-redhat-linux","", "", triple);
+ // Fedora 12
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.3",
+ "x86_64-redhat-linux", "32", "", triple);
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.3",
+ "i686-redhat-linux","", "", triple);
+ // Fedora 12 (pre-FEB-2010)
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.2",
+ "x86_64-redhat-linux", "32", "", triple);
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.2",
+ "i686-redhat-linux","", "", triple);
+ // Fedora 11
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.1",
+ "x86_64-redhat-linux", "32", "", triple);
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.1",
+ "i586-redhat-linux","", "", triple);
+ // Fedora 10
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.2",
+ "x86_64-redhat-linux", "32", "", triple);
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.2",
+ "i386-redhat-linux","", "", triple);
+ // Fedora 9
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.0",
+ "x86_64-redhat-linux", "32", "", triple);
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.0",
+ "i386-redhat-linux", "", "", triple);
+ // Fedora 8
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.1.2",
+ "x86_64-redhat-linux", "", "", triple);
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.1.2",
+ "i386-redhat-linux", "", "", triple);
+
+ //===------------------------------------------------------------------===//
+
+ // Exherbo (2010-01-25)
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.3",
+ "x86_64-pc-linux-gnu", "32", "", triple);
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.3",
+ "i686-pc-linux-gnu", "", "", triple);
+
+ // openSUSE 11.1 32 bit
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3",
+ "i586-suse-linux", "", "", triple);
+ // openSUSE 11.1 64 bit
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3",
+ "x86_64-suse-linux", "32", "", triple);
+ // openSUSE 11.2
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4",
+ "i586-suse-linux", "", "", triple);
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4",
+ "x86_64-suse-linux", "", "", triple);
+ // Arch Linux 2008-06-24
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.1",
+ "i686-pc-linux-gnu", "", "", triple);
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.1",
+ "x86_64-unknown-linux-gnu", "", "", triple);
+ // Gentoo x86 2009.1 stable
+ AddGnuCPlusPlusIncludePaths(
+ "/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4",
+ "i686-pc-linux-gnu", "", "", triple);
+ // Gentoo x86 2009.0 stable
+ AddGnuCPlusPlusIncludePaths(
+ "/usr/lib/gcc/i686-pc-linux-gnu/4.3.2/include/g++-v4",
+ "i686-pc-linux-gnu", "", "", triple);
+ // Gentoo x86 2008.0 stable
+ AddGnuCPlusPlusIncludePaths(
+ "/usr/lib/gcc/i686-pc-linux-gnu/4.1.2/include/g++-v4",
+ "i686-pc-linux-gnu", "", "", triple);
+ // Gentoo amd64 stable
+ AddGnuCPlusPlusIncludePaths(
+ "/usr/lib/gcc/x86_64-pc-linux-gnu/4.1.2/include/g++-v4",
+ "i686-pc-linux-gnu", "", "", triple);
+
+ // Gentoo amd64 gcc 4.3.2
+ AddGnuCPlusPlusIncludePaths(
+ "/usr/lib/gcc/x86_64-pc-linux-gnu/4.3.2/include/g++-v4",
+ "x86_64-pc-linux-gnu", "", "", triple);
+
+ // Gentoo amd64 gcc 4.4.3
+ AddGnuCPlusPlusIncludePaths(
+ "/usr/lib/gcc/x86_64-pc-linux-gnu/4.4.3/include/g++-v4",
+ "x86_64-pc-linux-gnu", "32", "", triple);
+
+ break;
+ case llvm::Triple::FreeBSD:
+ // FreeBSD 8.0
+ // FreeBSD 7.3
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.2", "", "", "", triple);
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.2/backward", "", "", "", triple);
+ break;
+ case llvm::Triple::Minix:
+ AddGnuCPlusPlusIncludePaths("/usr/gnu/include/c++/4.4.3",
+ "", "", "", triple);
+ break;
+ case llvm::Triple::Solaris:
+ // Solaris - Fall though..
+ case llvm::Triple::AuroraUX:
+ // AuroraUX
+ AddGnuCPlusPlusIncludePaths("/opt/gcc4/include/c++/4.2.4",
+ "i386-pc-solaris2.11", "", "", triple);
+ break;
+ default:
+ break;
+ }
+}
+
+void InitHeaderSearch::AddDefaultSystemIncludePaths(const LangOptions &Lang,
+ const llvm::Triple &triple,
+ const HeaderSearchOptions &HSOpts) {
+ if (Lang.CPlusPlus && HSOpts.UseStandardCXXIncludes)
+ AddDefaultCPlusPlusIncludePaths(triple);
+
+ AddDefaultCIncludePaths(triple, HSOpts);
+
+ // Add the default framework include paths on Darwin.
+ if (triple.getOS() == llvm::Triple::Darwin) {
+ AddPath("/System/Library/Frameworks", System, true, false, true);
+ AddPath("/Library/Frameworks", System, true, false, true);
+ }
+}
+
+/// RemoveDuplicates - If there are duplicate directory entries in the specified
+/// search list, remove the later (dead) ones.
+static void RemoveDuplicates(std::vector<DirectoryLookup> &SearchList,
+ bool Verbose) {
+ llvm::SmallPtrSet<const DirectoryEntry *, 8> SeenDirs;
+ llvm::SmallPtrSet<const DirectoryEntry *, 8> SeenFrameworkDirs;
+ llvm::SmallPtrSet<const HeaderMap *, 8> SeenHeaderMaps;
+ for (unsigned i = 0; i != SearchList.size(); ++i) {
+ unsigned DirToRemove = i;
+
+ const DirectoryLookup &CurEntry = SearchList[i];
+
+ if (CurEntry.isNormalDir()) {
+ // If this isn't the first time we've seen this dir, remove it.
+ if (SeenDirs.insert(CurEntry.getDir()))
+ continue;
+ } else if (CurEntry.isFramework()) {
+ // If this isn't the first time we've seen this framework dir, remove it.
+ if (SeenFrameworkDirs.insert(CurEntry.getFrameworkDir()))
+ continue;
+ } else {
+ assert(CurEntry.isHeaderMap() && "Not a headermap or normal dir?");
+ // If this isn't the first time we've seen this headermap, remove it.
+ if (SeenHeaderMaps.insert(CurEntry.getHeaderMap()))
+ continue;
+ }
+
+ // If we have a normal #include dir/framework/headermap that is shadowed
+ // later in the chain by a system include location, we actually want to
+ // ignore the user's request and drop the user dir... keeping the system
+ // dir. This is weird, but required to emulate GCC's search path correctly.
+ //
+ // Since dupes of system dirs are rare, just rescan to find the original
+ // that we're nuking instead of using a DenseMap.
+ if (CurEntry.getDirCharacteristic() != SrcMgr::C_User) {
+ // Find the dir that this is the same of.
+ unsigned FirstDir;
+ for (FirstDir = 0; ; ++FirstDir) {
+ assert(FirstDir != i && "Didn't find dupe?");
+
+ const DirectoryLookup &SearchEntry = SearchList[FirstDir];
+
+ // If these are different lookup types, then they can't be the dupe.
+ if (SearchEntry.getLookupType() != CurEntry.getLookupType())
+ continue;
+
+ bool isSame;
+ if (CurEntry.isNormalDir())
+ isSame = SearchEntry.getDir() == CurEntry.getDir();
+ else if (CurEntry.isFramework())
+ isSame = SearchEntry.getFrameworkDir() == CurEntry.getFrameworkDir();
+ else {
+ assert(CurEntry.isHeaderMap() && "Not a headermap or normal dir?");
+ isSame = SearchEntry.getHeaderMap() == CurEntry.getHeaderMap();
+ }
+
+ if (isSame)
+ break;
+ }
+
+ // If the first dir in the search path is a non-system dir, zap it
+ // instead of the system one.
+ if (SearchList[FirstDir].getDirCharacteristic() == SrcMgr::C_User)
+ DirToRemove = FirstDir;
+ }
+
+ if (Verbose) {
+ llvm::errs() << "ignoring duplicate directory \""
+ << CurEntry.getName() << "\"\n";
+ if (DirToRemove != i)
+ llvm::errs() << " as it is a non-system directory that duplicates "
+ << "a system directory\n";
+ }
+
+ // This is reached if the current entry is a duplicate. Remove the
+ // DirToRemove (usually the current dir).
+ SearchList.erase(SearchList.begin()+DirToRemove);
+ --i;
+ }
+}
+
+
+void InitHeaderSearch::Realize() {
+ // Concatenate ANGLE+SYSTEM+AFTER chains together into SearchList.
+ std::vector<DirectoryLookup> SearchList;
+ SearchList = IncludeGroup[Angled];
+ SearchList.insert(SearchList.end(), IncludeGroup[System].begin(),
+ IncludeGroup[System].end());
+ SearchList.insert(SearchList.end(), IncludeGroup[After].begin(),
+ IncludeGroup[After].end());
+ RemoveDuplicates(SearchList, Verbose);
+ RemoveDuplicates(IncludeGroup[Quoted], Verbose);
+
+ // Prepend QUOTED list on the search list.
+ SearchList.insert(SearchList.begin(), IncludeGroup[Quoted].begin(),
+ IncludeGroup[Quoted].end());
+
+
+ bool DontSearchCurDir = false; // TODO: set to true if -I- is set?
+ Headers.SetSearchPaths(SearchList, IncludeGroup[Quoted].size(),
+ DontSearchCurDir);
+
+ // If verbose, print the list of directories that will be searched.
+ if (Verbose) {
+ llvm::errs() << "#include \"...\" search starts here:\n";
+ unsigned QuotedIdx = IncludeGroup[Quoted].size();
+ for (unsigned i = 0, e = SearchList.size(); i != e; ++i) {
+ if (i == QuotedIdx)
+ llvm::errs() << "#include <...> search starts here:\n";
+ const char *Name = SearchList[i].getName();
+ const char *Suffix;
+ if (SearchList[i].isNormalDir())
+ Suffix = "";
+ else if (SearchList[i].isFramework())
+ Suffix = " (framework directory)";
+ else {
+ assert(SearchList[i].isHeaderMap() && "Unknown DirectoryLookup");
+ Suffix = " (headermap)";
+ }
+ llvm::errs() << " " << Name << Suffix << "\n";
+ }
+ llvm::errs() << "End of search list.\n";
+ }
+}
+
+void clang::ApplyHeaderSearchOptions(HeaderSearch &HS,
+ const HeaderSearchOptions &HSOpts,
+ const LangOptions &Lang,
+ const llvm::Triple &Triple) {
+ InitHeaderSearch Init(HS, HSOpts.Verbose, HSOpts.Sysroot);
+
+ // Add the user defined entries.
+ for (unsigned i = 0, e = HSOpts.UserEntries.size(); i != e; ++i) {
+ const HeaderSearchOptions::Entry &E = HSOpts.UserEntries[i];
+ Init.AddPath(E.Path, E.Group, false, E.IsUserSupplied, E.IsFramework,
+ false);
+ }
+
+ // Add entries from CPATH and friends.
+ Init.AddDelimitedPaths(HSOpts.EnvIncPath);
+ if (Lang.CPlusPlus && Lang.ObjC1)
+ Init.AddDelimitedPaths(HSOpts.ObjCXXEnvIncPath);
+ else if (Lang.CPlusPlus)
+ Init.AddDelimitedPaths(HSOpts.CXXEnvIncPath);
+ else if (Lang.ObjC1)
+ Init.AddDelimitedPaths(HSOpts.ObjCEnvIncPath);
+ else
+ Init.AddDelimitedPaths(HSOpts.CEnvIncPath);
+
+ if (HSOpts.UseStandardIncludes)
+ Init.AddDefaultSystemIncludePaths(Lang, Triple, HSOpts);
+
+ Init.Realize();
+}
diff --git a/contrib/llvm/tools/clang/lib/Frontend/InitPreprocessor.cpp b/contrib/llvm/tools/clang/lib/Frontend/InitPreprocessor.cpp
new file mode 100644
index 0000000..889b6e5
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Frontend/InitPreprocessor.cpp
@@ -0,0 +1,606 @@
+//===--- InitPreprocessor.cpp - PP initialization code. ---------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the clang::InitializePreprocessor function.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Basic/Version.h"
+#include "clang/Frontend/Utils.h"
+#include "clang/Basic/MacroBuilder.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
+#include "clang/Frontend/FrontendOptions.h"
+#include "clang/Frontend/PreprocessorOptions.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/SourceManager.h"
+#include "llvm/ADT/APFloat.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/System/Path.h"
+using namespace clang;
+
+// Append a #define line to Buf for Macro. Macro should be of the form XXX,
+// in which case we emit "#define XXX 1" or "XXX=Y z W" in which case we emit
+// "#define XXX Y z W". To get a #define with no value, use "XXX=".
+static void DefineBuiltinMacro(MacroBuilder &Builder, llvm::StringRef Macro,
+ Diagnostic &Diags) {
+ std::pair<llvm::StringRef, llvm::StringRef> MacroPair = Macro.split('=');
+ llvm::StringRef MacroName = MacroPair.first;
+ llvm::StringRef MacroBody = MacroPair.second;
+ if (MacroName.size() != Macro.size()) {
+ // Per GCC -D semantics, the macro ends at \n if it exists.
+ llvm::StringRef::size_type End = MacroBody.find_first_of("\n\r");
+ if (End != llvm::StringRef::npos)
+ Diags.Report(diag::warn_fe_macro_contains_embedded_newline)
+ << MacroName;
+ Builder.defineMacro(MacroName, MacroBody.substr(0, End));
+ } else {
+ // Push "macroname 1".
+ Builder.defineMacro(Macro);
+ }
+}
+
+std::string clang::NormalizeDashIncludePath(llvm::StringRef File) {
+ // Implicit include paths should be resolved relative to the current
+ // working directory first, and then use the regular header search
+ // mechanism. The proper way to handle this is to have the
+ // predefines buffer located at the current working directory, but
+ // it has not file entry. For now, workaround this by using an
+ // absolute path if we find the file here, and otherwise letting
+ // header search handle it.
+ llvm::sys::Path Path(File);
+ Path.makeAbsolute();
+ if (!Path.exists())
+ Path = File;
+
+ return Lexer::Stringify(Path.str());
+}
+
+/// AddImplicitInclude - Add an implicit #include of the specified file to the
+/// predefines buffer.
+static void AddImplicitInclude(MacroBuilder &Builder, llvm::StringRef File) {
+ Builder.append("#include \"" +
+ llvm::Twine(NormalizeDashIncludePath(File)) + "\"");
+}
+
+static void AddImplicitIncludeMacros(MacroBuilder &Builder,
+ llvm::StringRef File) {
+ Builder.append("#__include_macros \"" +
+ llvm::Twine(NormalizeDashIncludePath(File)) + "\"");
+ // Marker token to stop the __include_macros fetch loop.
+ Builder.append("##"); // ##?
+}
+
+/// AddImplicitIncludePTH - Add an implicit #include using the original file
+/// used to generate a PTH cache.
+static void AddImplicitIncludePTH(MacroBuilder &Builder, Preprocessor &PP,
+ llvm::StringRef ImplicitIncludePTH) {
+ PTHManager *P = PP.getPTHManager();
+ // Null check 'P' in the corner case where it couldn't be created.
+ const char *OriginalFile = P ? P->getOriginalSourceFile() : 0;
+
+ if (!OriginalFile) {
+ PP.getDiagnostics().Report(diag::err_fe_pth_file_has_no_source_header)
+ << ImplicitIncludePTH;
+ return;
+ }
+
+ AddImplicitInclude(Builder, OriginalFile);
+}
+
+/// PickFP - This is used to pick a value based on the FP semantics of the
+/// specified FP model.
+template <typename T>
+static T PickFP(const llvm::fltSemantics *Sem, T IEEESingleVal,
+ T IEEEDoubleVal, T X87DoubleExtendedVal, T PPCDoubleDoubleVal,
+ T IEEEQuadVal) {
+ if (Sem == (const llvm::fltSemantics*)&llvm::APFloat::IEEEsingle)
+ return IEEESingleVal;
+ if (Sem == (const llvm::fltSemantics*)&llvm::APFloat::IEEEdouble)
+ return IEEEDoubleVal;
+ if (Sem == (const llvm::fltSemantics*)&llvm::APFloat::x87DoubleExtended)
+ return X87DoubleExtendedVal;
+ if (Sem == (const llvm::fltSemantics*)&llvm::APFloat::PPCDoubleDouble)
+ return PPCDoubleDoubleVal;
+ assert(Sem == (const llvm::fltSemantics*)&llvm::APFloat::IEEEquad);
+ return IEEEQuadVal;
+}
+
+static void DefineFloatMacros(MacroBuilder &Builder, llvm::StringRef Prefix,
+ const llvm::fltSemantics *Sem) {
+ const char *DenormMin, *Epsilon, *Max, *Min;
+ DenormMin = PickFP(Sem, "1.40129846e-45F", "4.9406564584124654e-324",
+ "3.64519953188247460253e-4951L",
+ "4.94065645841246544176568792868221e-324L",
+ "6.47517511943802511092443895822764655e-4966L");
+ int Digits = PickFP(Sem, 6, 15, 18, 31, 33);
+ Epsilon = PickFP(Sem, "1.19209290e-7F", "2.2204460492503131e-16",
+ "1.08420217248550443401e-19L",
+ "4.94065645841246544176568792868221e-324L",
+ "1.92592994438723585305597794258492732e-34L");
+ int MantissaDigits = PickFP(Sem, 24, 53, 64, 106, 113);
+ int Min10Exp = PickFP(Sem, -37, -307, -4931, -291, -4931);
+ int Max10Exp = PickFP(Sem, 38, 308, 4932, 308, 4932);
+ int MinExp = PickFP(Sem, -125, -1021, -16381, -968, -16381);
+ int MaxExp = PickFP(Sem, 128, 1024, 16384, 1024, 16384);
+ Min = PickFP(Sem, "1.17549435e-38F", "2.2250738585072014e-308",
+ "3.36210314311209350626e-4932L",
+ "2.00416836000897277799610805135016e-292L",
+ "3.36210314311209350626267781732175260e-4932L");
+ Max = PickFP(Sem, "3.40282347e+38F", "1.7976931348623157e+308",
+ "1.18973149535723176502e+4932L",
+ "1.79769313486231580793728971405301e+308L",
+ "1.18973149535723176508575932662800702e+4932L");
+
+ llvm::SmallString<32> DefPrefix;
+ DefPrefix = "__";
+ DefPrefix += Prefix;
+ DefPrefix += "_";
+
+ Builder.defineMacro(DefPrefix + "DENORM_MIN__", DenormMin);
+ Builder.defineMacro(DefPrefix + "HAS_DENORM__");
+ Builder.defineMacro(DefPrefix + "DIG__", llvm::Twine(Digits));
+ Builder.defineMacro(DefPrefix + "EPSILON__", llvm::Twine(Epsilon));
+ Builder.defineMacro(DefPrefix + "HAS_INFINITY__");
+ Builder.defineMacro(DefPrefix + "HAS_QUIET_NAN__");
+ Builder.defineMacro(DefPrefix + "MANT_DIG__", llvm::Twine(MantissaDigits));
+
+ Builder.defineMacro(DefPrefix + "MAX_10_EXP__", llvm::Twine(Max10Exp));
+ Builder.defineMacro(DefPrefix + "MAX_EXP__", llvm::Twine(MaxExp));
+ Builder.defineMacro(DefPrefix + "MAX__", llvm::Twine(Max));
+
+ Builder.defineMacro(DefPrefix + "MIN_10_EXP__","("+llvm::Twine(Min10Exp)+")");
+ Builder.defineMacro(DefPrefix + "MIN_EXP__", "("+llvm::Twine(MinExp)+")");
+ Builder.defineMacro(DefPrefix + "MIN__", llvm::Twine(Min));
+}
+
+
+/// DefineTypeSize - Emit a macro to the predefines buffer that declares a macro
+/// named MacroName with the max value for a type with width 'TypeWidth' a
+/// signedness of 'isSigned' and with a value suffix of 'ValSuffix' (e.g. LL).
+static void DefineTypeSize(llvm::StringRef MacroName, unsigned TypeWidth,
+ llvm::StringRef ValSuffix, bool isSigned,
+ MacroBuilder& Builder) {
+ long long MaxVal;
+ if (isSigned)
+ MaxVal = (1LL << (TypeWidth - 1)) - 1;
+ else
+ MaxVal = ~0LL >> (64-TypeWidth);
+
+ Builder.defineMacro(MacroName, llvm::Twine(MaxVal) + ValSuffix);
+}
+
+/// DefineTypeSize - An overloaded helper that uses TargetInfo to determine
+/// the width, suffix, and signedness of the given type
+static void DefineTypeSize(llvm::StringRef MacroName, TargetInfo::IntType Ty,
+ const TargetInfo &TI, MacroBuilder &Builder) {
+ DefineTypeSize(MacroName, TI.getTypeWidth(Ty), TI.getTypeConstantSuffix(Ty),
+ TI.isTypeSigned(Ty), Builder);
+}
+
+static void DefineType(const llvm::Twine &MacroName, TargetInfo::IntType Ty,
+ MacroBuilder &Builder) {
+ Builder.defineMacro(MacroName, TargetInfo::getTypeName(Ty));
+}
+
+static void DefineTypeWidth(llvm::StringRef MacroName, TargetInfo::IntType Ty,
+ const TargetInfo &TI, MacroBuilder &Builder) {
+ Builder.defineMacro(MacroName, llvm::Twine(TI.getTypeWidth(Ty)));
+}
+
+static void DefineTypeSizeof(llvm::StringRef MacroName, unsigned BitWidth,
+ const TargetInfo &TI, MacroBuilder &Builder) {
+ Builder.defineMacro(MacroName,
+ llvm::Twine(BitWidth / TI.getCharWidth()));
+}
+
+static void DefineExactWidthIntType(TargetInfo::IntType Ty,
+ const TargetInfo &TI, MacroBuilder &Builder) {
+ int TypeWidth = TI.getTypeWidth(Ty);
+
+ // Use the target specified int64 type, when appropriate, so that [u]int64_t
+ // ends up being defined in terms of the correct type.
+ if (TypeWidth == 64)
+ Ty = TI.getInt64Type();
+
+ DefineType("__INT" + llvm::Twine(TypeWidth) + "_TYPE__", Ty, Builder);
+
+ llvm::StringRef ConstSuffix(TargetInfo::getTypeConstantSuffix(Ty));
+ if (!ConstSuffix.empty())
+ Builder.defineMacro("__INT" + llvm::Twine(TypeWidth) + "_C_SUFFIX__",
+ ConstSuffix);
+}
+
+static void InitializePredefinedMacros(const TargetInfo &TI,
+ const LangOptions &LangOpts,
+ const FrontendOptions &FEOpts,
+ MacroBuilder &Builder) {
+ // Compiler version introspection macros.
+ Builder.defineMacro("__llvm__"); // LLVM Backend
+ Builder.defineMacro("__clang__"); // Clang Frontend
+#define TOSTR2(X) #X
+#define TOSTR(X) TOSTR2(X)
+ Builder.defineMacro("__clang_major__", TOSTR(CLANG_VERSION_MAJOR));
+ Builder.defineMacro("__clang_minor__", TOSTR(CLANG_VERSION_MINOR));
+#ifdef CLANG_VERSION_PATCHLEVEL
+ Builder.defineMacro("__clang_patchlevel__", TOSTR(CLANG_VERSION_PATCHLEVEL));
+#else
+ Builder.defineMacro("__clang_patchlevel__", "0");
+#endif
+ Builder.defineMacro("__clang_version__",
+ "\"" CLANG_VERSION_STRING " ("
+ + getClangFullRepositoryVersion() + ")\"");
+#undef TOSTR
+#undef TOSTR2
+ // Currently claim to be compatible with GCC 4.2.1-5621.
+ Builder.defineMacro("__GNUC_MINOR__", "2");
+ Builder.defineMacro("__GNUC_PATCHLEVEL__", "1");
+ Builder.defineMacro("__GNUC__", "4");
+ Builder.defineMacro("__GXX_ABI_VERSION", "1002");
+ Builder.defineMacro("__VERSION__", "\"4.2.1 Compatible Clang Compiler\"");
+
+ // Initialize language-specific preprocessor defines.
+
+ // These should all be defined in the preprocessor according to the
+ // current language configuration.
+ if (!LangOpts.Microsoft)
+ Builder.defineMacro("__STDC__");
+ if (LangOpts.AsmPreprocessor)
+ Builder.defineMacro("__ASSEMBLER__");
+
+ if (!LangOpts.CPlusPlus) {
+ if (LangOpts.C99)
+ Builder.defineMacro("__STDC_VERSION__", "199901L");
+ else if (!LangOpts.GNUMode && LangOpts.Digraphs)
+ Builder.defineMacro("__STDC_VERSION__", "199409L");
+ }
+
+ // Standard conforming mode?
+ if (!LangOpts.GNUMode)
+ Builder.defineMacro("__STRICT_ANSI__");
+
+ if (LangOpts.CPlusPlus0x)
+ Builder.defineMacro("__GXX_EXPERIMENTAL_CXX0X__");
+
+ if (LangOpts.Freestanding)
+ Builder.defineMacro("__STDC_HOSTED__", "0");
+ else
+ Builder.defineMacro("__STDC_HOSTED__");
+
+ if (LangOpts.ObjC1) {
+ Builder.defineMacro("__OBJC__");
+ if (LangOpts.ObjCNonFragileABI) {
+ Builder.defineMacro("__OBJC2__");
+ Builder.defineMacro("OBJC_ZEROCOST_EXCEPTIONS");
+ }
+
+ if (LangOpts.getGCMode() != LangOptions::NonGC)
+ Builder.defineMacro("__OBJC_GC__");
+
+ if (LangOpts.NeXTRuntime)
+ Builder.defineMacro("__NEXT_RUNTIME__");
+ }
+
+ // darwin_constant_cfstrings controls this. This is also dependent
+ // on other things like the runtime I believe. This is set even for C code.
+ Builder.defineMacro("__CONSTANT_CFSTRINGS__");
+
+ if (LangOpts.ObjC2)
+ Builder.defineMacro("OBJC_NEW_PROPERTIES");
+
+ if (LangOpts.PascalStrings)
+ Builder.defineMacro("__PASCAL_STRINGS__");
+
+ if (LangOpts.Blocks) {
+ Builder.defineMacro("__block", "__attribute__((__blocks__(byref)))");
+ Builder.defineMacro("__BLOCKS__");
+ }
+
+ if (LangOpts.Exceptions)
+ Builder.defineMacro("__EXCEPTIONS");
+ if (LangOpts.RTTI)
+ Builder.defineMacro("__GXX_RTTI");
+ if (LangOpts.SjLjExceptions)
+ Builder.defineMacro("__USING_SJLJ_EXCEPTIONS__");
+
+ if (LangOpts.CPlusPlus) {
+ Builder.defineMacro("__DEPRECATED");
+ Builder.defineMacro("__GNUG__", "4");
+ Builder.defineMacro("__GXX_WEAK__");
+ if (LangOpts.GNUMode)
+ Builder.defineMacro("__cplusplus");
+ else
+ // C++ [cpp.predefined]p1:
+ // The name_ _cplusplusis defined to the value199711Lwhen compiling a
+ // C++ translation unit.
+ Builder.defineMacro("__cplusplus", "199711L");
+ Builder.defineMacro("__private_extern__", "extern");
+ }
+
+ if (LangOpts.Microsoft) {
+ // Filter out some microsoft extensions when trying to parse in ms-compat
+ // mode.
+ Builder.defineMacro("__int8", "__INT8_TYPE__");
+ Builder.defineMacro("__int16", "__INT16_TYPE__");
+ Builder.defineMacro("__int32", "__INT32_TYPE__");
+ Builder.defineMacro("__int64", "__INT64_TYPE__");
+ // Both __PRETTY_FUNCTION__ and __FUNCTION__ are GCC extensions, however
+ // VC++ appears to only like __FUNCTION__.
+ Builder.defineMacro("__PRETTY_FUNCTION__", "__FUNCTION__");
+ // Work around some issues with Visual C++ headerws.
+ if (LangOpts.CPlusPlus) {
+ // Since we define wchar_t in C++ mode.
+ Builder.defineMacro("_WCHAR_T_DEFINED");
+ Builder.defineMacro("_NATIVE_WCHAR_T_DEFINED");
+ // FIXME: This should be temporary until we have a __pragma
+ // solution, to avoid some errors flagged in VC++ headers.
+ Builder.defineMacro("_CRT_SECURE_CPP_OVERLOAD_SECURE_NAMES", "0");
+ }
+ }
+
+ if (LangOpts.Optimize)
+ Builder.defineMacro("__OPTIMIZE__");
+ if (LangOpts.OptimizeSize)
+ Builder.defineMacro("__OPTIMIZE_SIZE__");
+
+ // Initialize target-specific preprocessor defines.
+
+ // Define type sizing macros based on the target properties.
+ assert(TI.getCharWidth() == 8 && "Only support 8-bit char so far");
+ Builder.defineMacro("__CHAR_BIT__", "8");
+
+ DefineTypeSize("__SCHAR_MAX__", TI.getCharWidth(), "", true, Builder);
+ DefineTypeSize("__SHRT_MAX__", TargetInfo::SignedShort, TI, Builder);
+ DefineTypeSize("__INT_MAX__", TargetInfo::SignedInt, TI, Builder);
+ DefineTypeSize("__LONG_MAX__", TargetInfo::SignedLong, TI, Builder);
+ DefineTypeSize("__LONG_LONG_MAX__", TargetInfo::SignedLongLong, TI, Builder);
+ DefineTypeSize("__WCHAR_MAX__", TI.getWCharType(), TI, Builder);
+ DefineTypeSize("__INTMAX_MAX__", TI.getIntMaxType(), TI, Builder);
+
+ DefineTypeSizeof("__SIZEOF_DOUBLE__", TI.getDoubleWidth(), TI, Builder);
+ DefineTypeSizeof("__SIZEOF_FLOAT__", TI.getFloatWidth(), TI, Builder);
+ DefineTypeSizeof("__SIZEOF_INT__", TI.getIntWidth(), TI, Builder);
+ DefineTypeSizeof("__SIZEOF_LONG__", TI.getLongWidth(), TI, Builder);
+ DefineTypeSizeof("__SIZEOF_LONG_DOUBLE__",TI.getLongDoubleWidth(),TI,Builder);
+ DefineTypeSizeof("__SIZEOF_LONG_LONG__", TI.getLongLongWidth(), TI, Builder);
+ DefineTypeSizeof("__SIZEOF_POINTER__", TI.getPointerWidth(0), TI, Builder);
+ DefineTypeSizeof("__SIZEOF_SHORT__", TI.getShortWidth(), TI, Builder);
+ DefineTypeSizeof("__SIZEOF_PTRDIFF_T__",
+ TI.getTypeWidth(TI.getPtrDiffType(0)), TI, Builder);
+ DefineTypeSizeof("__SIZEOF_SIZE_T__",
+ TI.getTypeWidth(TI.getSizeType()), TI, Builder);
+ DefineTypeSizeof("__SIZEOF_WCHAR_T__",
+ TI.getTypeWidth(TI.getWCharType()), TI, Builder);
+ DefineTypeSizeof("__SIZEOF_WINT_T__",
+ TI.getTypeWidth(TI.getWIntType()), TI, Builder);
+
+ DefineType("__INTMAX_TYPE__", TI.getIntMaxType(), Builder);
+ DefineType("__UINTMAX_TYPE__", TI.getUIntMaxType(), Builder);
+ DefineTypeWidth("__INTMAX_WIDTH__", TI.getIntMaxType(), TI, Builder);
+ DefineType("__PTRDIFF_TYPE__", TI.getPtrDiffType(0), Builder);
+ DefineTypeWidth("__PTRDIFF_WIDTH__", TI.getPtrDiffType(0), TI, Builder);
+ DefineType("__INTPTR_TYPE__", TI.getIntPtrType(), Builder);
+ DefineTypeWidth("__INTPTR_WIDTH__", TI.getIntPtrType(), TI, Builder);
+ DefineType("__SIZE_TYPE__", TI.getSizeType(), Builder);
+ DefineTypeWidth("__SIZE_WIDTH__", TI.getSizeType(), TI, Builder);
+ DefineType("__WCHAR_TYPE__", TI.getWCharType(), Builder);
+ DefineTypeWidth("__WCHAR_WIDTH__", TI.getWCharType(), TI, Builder);
+ DefineType("__WINT_TYPE__", TI.getWIntType(), Builder);
+ DefineTypeWidth("__WINT_WIDTH__", TI.getWIntType(), TI, Builder);
+ DefineTypeWidth("__SIG_ATOMIC_WIDTH__", TI.getSigAtomicType(), TI, Builder);
+ DefineType("__CHAR16_TYPE__", TI.getChar16Type(), Builder);
+ DefineType("__CHAR32_TYPE__", TI.getChar32Type(), Builder);
+
+ DefineFloatMacros(Builder, "FLT", &TI.getFloatFormat());
+ DefineFloatMacros(Builder, "DBL", &TI.getDoubleFormat());
+ DefineFloatMacros(Builder, "LDBL", &TI.getLongDoubleFormat());
+
+ // Define a __POINTER_WIDTH__ macro for stdint.h.
+ Builder.defineMacro("__POINTER_WIDTH__",
+ llvm::Twine((int)TI.getPointerWidth(0)));
+
+ if (!LangOpts.CharIsSigned)
+ Builder.defineMacro("__CHAR_UNSIGNED__");
+
+ // Define exact-width integer types for stdint.h
+ Builder.defineMacro("__INT" + llvm::Twine(TI.getCharWidth()) + "_TYPE__",
+ "char");
+
+ if (TI.getShortWidth() > TI.getCharWidth())
+ DefineExactWidthIntType(TargetInfo::SignedShort, TI, Builder);
+
+ if (TI.getIntWidth() > TI.getShortWidth())
+ DefineExactWidthIntType(TargetInfo::SignedInt, TI, Builder);
+
+ if (TI.getLongWidth() > TI.getIntWidth())
+ DefineExactWidthIntType(TargetInfo::SignedLong, TI, Builder);
+
+ if (TI.getLongLongWidth() > TI.getLongWidth())
+ DefineExactWidthIntType(TargetInfo::SignedLongLong, TI, Builder);
+
+ // Add __builtin_va_list typedef.
+ Builder.append(TI.getVAListDeclaration());
+
+ if (const char *Prefix = TI.getUserLabelPrefix())
+ Builder.defineMacro("__USER_LABEL_PREFIX__", Prefix);
+
+ // Build configuration options. FIXME: these should be controlled by
+ // command line options or something.
+ Builder.defineMacro("__FINITE_MATH_ONLY__", "0");
+
+ if (LangOpts.GNUInline)
+ Builder.defineMacro("__GNUC_GNU_INLINE__");
+ else
+ Builder.defineMacro("__GNUC_STDC_INLINE__");
+
+ if (LangOpts.NoInline)
+ Builder.defineMacro("__NO_INLINE__");
+
+ if (unsigned PICLevel = LangOpts.PICLevel) {
+ Builder.defineMacro("__PIC__", llvm::Twine(PICLevel));
+ Builder.defineMacro("__pic__", llvm::Twine(PICLevel));
+ }
+
+ // Macros to control C99 numerics and <float.h>
+ Builder.defineMacro("__FLT_EVAL_METHOD__", "0");
+ Builder.defineMacro("__FLT_RADIX__", "2");
+ int Dig = PickFP(&TI.getLongDoubleFormat(), -1/*FIXME*/, 17, 21, 33, 36);
+ Builder.defineMacro("__DECIMAL_DIG__", llvm::Twine(Dig));
+
+ if (LangOpts.getStackProtectorMode() == LangOptions::SSPOn)
+ Builder.defineMacro("__SSP__");
+ else if (LangOpts.getStackProtectorMode() == LangOptions::SSPReq)
+ Builder.defineMacro("__SSP_ALL__", "2");
+
+ if (FEOpts.ProgramAction == frontend::RewriteObjC)
+ Builder.defineMacro("__weak", "__attribute__((objc_gc(weak)))");
+
+ // Define a macro that exists only when using the static analyzer.
+ if (FEOpts.ProgramAction == frontend::RunAnalysis)
+ Builder.defineMacro("__clang_analyzer__");
+
+ // Get other target #defines.
+ TI.getTargetDefines(LangOpts, Builder);
+}
+
+// Initialize the remapping of files to alternative contents, e.g.,
+// those specified through other files.
+static void InitializeFileRemapping(Diagnostic &Diags,
+ SourceManager &SourceMgr,
+ FileManager &FileMgr,
+ const PreprocessorOptions &InitOpts) {
+ // Remap files in the source manager (with buffers).
+ for (PreprocessorOptions::remapped_file_buffer_iterator
+ Remap = InitOpts.remapped_file_buffer_begin(),
+ RemapEnd = InitOpts.remapped_file_buffer_end();
+ Remap != RemapEnd;
+ ++Remap) {
+ // Create the file entry for the file that we're mapping from.
+ const FileEntry *FromFile = FileMgr.getVirtualFile(Remap->first,
+ Remap->second->getBufferSize(),
+ 0);
+ if (!FromFile) {
+ Diags.Report(diag::err_fe_remap_missing_from_file)
+ << Remap->first;
+ delete Remap->second;
+ continue;
+ }
+
+ // Override the contents of the "from" file with the contents of
+ // the "to" file.
+ SourceMgr.overrideFileContents(FromFile, Remap->second);
+ }
+
+ // Remap files in the source manager (with other files).
+ for (PreprocessorOptions::remapped_file_iterator
+ Remap = InitOpts.remapped_file_begin(),
+ RemapEnd = InitOpts.remapped_file_end();
+ Remap != RemapEnd;
+ ++Remap) {
+ // Find the file that we're mapping to.
+ const FileEntry *ToFile = FileMgr.getFile(Remap->second);
+ if (!ToFile) {
+ Diags.Report(diag::err_fe_remap_missing_to_file)
+ << Remap->first << Remap->second;
+ continue;
+ }
+
+ // Create the file entry for the file that we're mapping from.
+ const FileEntry *FromFile = FileMgr.getVirtualFile(Remap->first,
+ ToFile->getSize(),
+ 0);
+ if (!FromFile) {
+ Diags.Report(diag::err_fe_remap_missing_from_file)
+ << Remap->first;
+ continue;
+ }
+
+ // Load the contents of the file we're mapping to.
+ std::string ErrorStr;
+ const llvm::MemoryBuffer *Buffer
+ = llvm::MemoryBuffer::getFile(ToFile->getName(), &ErrorStr);
+ if (!Buffer) {
+ Diags.Report(diag::err_fe_error_opening)
+ << Remap->second << ErrorStr;
+ continue;
+ }
+
+ // Override the contents of the "from" file with the contents of
+ // the "to" file.
+ SourceMgr.overrideFileContents(FromFile, Buffer);
+ }
+}
+
+/// InitializePreprocessor - Initialize the preprocessor getting it and the
+/// environment ready to process a single file. This returns true on error.
+///
+void clang::InitializePreprocessor(Preprocessor &PP,
+ const PreprocessorOptions &InitOpts,
+ const HeaderSearchOptions &HSOpts,
+ const FrontendOptions &FEOpts) {
+ std::string PredefineBuffer;
+ PredefineBuffer.reserve(4080);
+ llvm::raw_string_ostream Predefines(PredefineBuffer);
+ MacroBuilder Builder(Predefines);
+
+ InitializeFileRemapping(PP.getDiagnostics(), PP.getSourceManager(),
+ PP.getFileManager(), InitOpts);
+
+ // Emit line markers for various builtin sections of the file. We don't do
+ // this in asm preprocessor mode, because "# 4" is not a line marker directive
+ // in this mode.
+ if (!PP.getLangOptions().AsmPreprocessor)
+ Builder.append("# 1 \"<built-in>\" 3");
+
+ // Install things like __POWERPC__, __GNUC__, etc into the macro table.
+ if (InitOpts.UsePredefines)
+ InitializePredefinedMacros(PP.getTargetInfo(), PP.getLangOptions(),
+ FEOpts, Builder);
+
+ // Add on the predefines from the driver. Wrap in a #line directive to report
+ // that they come from the command line.
+ if (!PP.getLangOptions().AsmPreprocessor)
+ Builder.append("# 1 \"<command line>\" 1");
+
+ // Process #define's and #undef's in the order they are given.
+ for (unsigned i = 0, e = InitOpts.Macros.size(); i != e; ++i) {
+ if (InitOpts.Macros[i].second) // isUndef
+ Builder.undefineMacro(InitOpts.Macros[i].first);
+ else
+ DefineBuiltinMacro(Builder, InitOpts.Macros[i].first,
+ PP.getDiagnostics());
+ }
+
+ // If -imacros are specified, include them now. These are processed before
+ // any -include directives.
+ for (unsigned i = 0, e = InitOpts.MacroIncludes.size(); i != e; ++i)
+ AddImplicitIncludeMacros(Builder, InitOpts.MacroIncludes[i]);
+
+ // Process -include directives.
+ for (unsigned i = 0, e = InitOpts.Includes.size(); i != e; ++i) {
+ const std::string &Path = InitOpts.Includes[i];
+ if (Path == InitOpts.ImplicitPTHInclude)
+ AddImplicitIncludePTH(Builder, PP, Path);
+ else
+ AddImplicitInclude(Builder, Path);
+ }
+
+ // Exit the command line and go back to <built-in> (2 is LC_LEAVE).
+ if (!PP.getLangOptions().AsmPreprocessor)
+ Builder.append("# 1 \"<built-in>\" 2");
+
+ // Copy PredefinedBuffer into the Preprocessor.
+ PP.setPredefines(Predefines.str());
+
+ // Initialize the header search object.
+ ApplyHeaderSearchOptions(PP.getHeaderSearchInfo(), HSOpts,
+ PP.getLangOptions(),
+ PP.getTargetInfo().getTriple());
+}
diff --git a/contrib/llvm/tools/clang/lib/Frontend/LangStandards.cpp b/contrib/llvm/tools/clang/lib/Frontend/LangStandards.cpp
new file mode 100644
index 0000000..af1721d
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Frontend/LangStandards.cpp
@@ -0,0 +1,44 @@
+//===--- LangStandards.cpp - Language Standard Definitions ----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/LangStandard.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/ErrorHandling.h"
+using namespace clang;
+using namespace clang::frontend;
+
+#define LANGSTANDARD(id, name, desc, features) \
+ static const LangStandard Lang_##id = { name, desc, features };
+#include "clang/Frontend/LangStandards.def"
+
+const LangStandard &LangStandard::getLangStandardForKind(Kind K) {
+ switch (K) {
+ default:
+ llvm_unreachable("Invalid language kind!");
+ case lang_unspecified:
+ llvm::report_fatal_error("getLangStandardForKind() on unspecified kind");
+#define LANGSTANDARD(id, name, desc, features) \
+ case lang_##id: return Lang_##id;
+#include "clang/Frontend/LangStandards.def"
+ }
+}
+
+const LangStandard *LangStandard::getLangStandardForName(llvm::StringRef Name) {
+ Kind K = llvm::StringSwitch<Kind>(Name)
+#define LANGSTANDARD(id, name, desc, features) \
+ .Case(name, lang_##id)
+#include "clang/Frontend/LangStandards.def"
+ .Default(lang_unspecified);
+ if (K == lang_unspecified)
+ return 0;
+
+ return &getLangStandardForKind(K);
+}
+
+
diff --git a/contrib/llvm/tools/clang/lib/Frontend/Makefile b/contrib/llvm/tools/clang/lib/Frontend/Makefile
new file mode 100644
index 0000000..3eb4bc9
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Frontend/Makefile
@@ -0,0 +1,15 @@
+##===- clang/lib/Frontend/Makefile -------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+CLANG_LEVEL := ../..
+LIBRARYNAME := clangFrontend
+BUILD_ARCHIVE = 1
+
+include $(CLANG_LEVEL)/Makefile
+
diff --git a/contrib/llvm/tools/clang/lib/Frontend/PCHReader.cpp b/contrib/llvm/tools/clang/lib/Frontend/PCHReader.cpp
new file mode 100644
index 0000000..00aee49
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Frontend/PCHReader.cpp
@@ -0,0 +1,3469 @@
+//===--- PCHReader.cpp - Precompiled Headers Reader -------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the PCHReader class, which reads a precompiled header.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/PCHReader.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
+#include "clang/Frontend/PCHDeserializationListener.h"
+#include "clang/Frontend/Utils.h"
+#include "../Sema/Sema.h" // FIXME: move Sema headers elsewhere
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/Type.h"
+#include "clang/AST/TypeLocVisitor.h"
+#include "clang/Lex/MacroInfo.h"
+#include "clang/Lex/PreprocessingRecord.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/HeaderSearch.h"
+#include "clang/Basic/OnDiskHashTable.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/SourceManagerInternals.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/Version.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Bitcode/BitstreamReader.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/System/Path.h"
+#include <algorithm>
+#include <iterator>
+#include <cstdio>
+#include <sys/stat.h>
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// PCH reader validator implementation
+//===----------------------------------------------------------------------===//
+
+PCHReaderListener::~PCHReaderListener() {}
+
+bool
+PCHValidator::ReadLanguageOptions(const LangOptions &LangOpts) {
+ const LangOptions &PPLangOpts = PP.getLangOptions();
+#define PARSE_LANGOPT_BENIGN(Option)
+#define PARSE_LANGOPT_IMPORTANT(Option, DiagID) \
+ if (PPLangOpts.Option != LangOpts.Option) { \
+ Reader.Diag(DiagID) << LangOpts.Option << PPLangOpts.Option; \
+ return true; \
+ }
+
+ PARSE_LANGOPT_BENIGN(Trigraphs);
+ PARSE_LANGOPT_BENIGN(BCPLComment);
+ PARSE_LANGOPT_BENIGN(DollarIdents);
+ PARSE_LANGOPT_BENIGN(AsmPreprocessor);
+ PARSE_LANGOPT_IMPORTANT(GNUMode, diag::warn_pch_gnu_extensions);
+ PARSE_LANGOPT_IMPORTANT(GNUKeywords, diag::warn_pch_gnu_keywords);
+ PARSE_LANGOPT_BENIGN(ImplicitInt);
+ PARSE_LANGOPT_BENIGN(Digraphs);
+ PARSE_LANGOPT_BENIGN(HexFloats);
+ PARSE_LANGOPT_IMPORTANT(C99, diag::warn_pch_c99);
+ PARSE_LANGOPT_IMPORTANT(Microsoft, diag::warn_pch_microsoft_extensions);
+ PARSE_LANGOPT_IMPORTANT(CPlusPlus, diag::warn_pch_cplusplus);
+ PARSE_LANGOPT_IMPORTANT(CPlusPlus0x, diag::warn_pch_cplusplus0x);
+ PARSE_LANGOPT_BENIGN(CXXOperatorName);
+ PARSE_LANGOPT_IMPORTANT(ObjC1, diag::warn_pch_objective_c);
+ PARSE_LANGOPT_IMPORTANT(ObjC2, diag::warn_pch_objective_c2);
+ PARSE_LANGOPT_IMPORTANT(ObjCNonFragileABI, diag::warn_pch_nonfragile_abi);
+ PARSE_LANGOPT_IMPORTANT(ObjCNonFragileABI2, diag::warn_pch_nonfragile_abi2);
+ PARSE_LANGOPT_IMPORTANT(NoConstantCFStrings,
+ diag::warn_pch_no_constant_cfstrings);
+ PARSE_LANGOPT_BENIGN(PascalStrings);
+ PARSE_LANGOPT_BENIGN(WritableStrings);
+ PARSE_LANGOPT_IMPORTANT(LaxVectorConversions,
+ diag::warn_pch_lax_vector_conversions);
+ PARSE_LANGOPT_IMPORTANT(AltiVec, diag::warn_pch_altivec);
+ PARSE_LANGOPT_IMPORTANT(Exceptions, diag::warn_pch_exceptions);
+ PARSE_LANGOPT_IMPORTANT(SjLjExceptions, diag::warn_pch_sjlj_exceptions);
+ PARSE_LANGOPT_IMPORTANT(NeXTRuntime, diag::warn_pch_objc_runtime);
+ PARSE_LANGOPT_IMPORTANT(Freestanding, diag::warn_pch_freestanding);
+ PARSE_LANGOPT_IMPORTANT(NoBuiltin, diag::warn_pch_builtins);
+ PARSE_LANGOPT_IMPORTANT(ThreadsafeStatics,
+ diag::warn_pch_thread_safe_statics);
+ PARSE_LANGOPT_IMPORTANT(POSIXThreads, diag::warn_pch_posix_threads);
+ PARSE_LANGOPT_IMPORTANT(Blocks, diag::warn_pch_blocks);
+ PARSE_LANGOPT_BENIGN(EmitAllDecls);
+ PARSE_LANGOPT_IMPORTANT(MathErrno, diag::warn_pch_math_errno);
+ PARSE_LANGOPT_BENIGN(getSignedOverflowBehavior());
+ PARSE_LANGOPT_IMPORTANT(HeinousExtensions,
+ diag::warn_pch_heinous_extensions);
+ // FIXME: Most of the options below are benign if the macro wasn't
+ // used. Unfortunately, this means that a PCH compiled without
+ // optimization can't be used with optimization turned on, even
+ // though the only thing that changes is whether __OPTIMIZE__ was
+ // defined... but if __OPTIMIZE__ never showed up in the header, it
+ // doesn't matter. We could consider making this some special kind
+ // of check.
+ PARSE_LANGOPT_IMPORTANT(Optimize, diag::warn_pch_optimize);
+ PARSE_LANGOPT_IMPORTANT(OptimizeSize, diag::warn_pch_optimize_size);
+ PARSE_LANGOPT_IMPORTANT(Static, diag::warn_pch_static);
+ PARSE_LANGOPT_IMPORTANT(PICLevel, diag::warn_pch_pic_level);
+ PARSE_LANGOPT_IMPORTANT(GNUInline, diag::warn_pch_gnu_inline);
+ PARSE_LANGOPT_IMPORTANT(NoInline, diag::warn_pch_no_inline);
+ PARSE_LANGOPT_IMPORTANT(AccessControl, diag::warn_pch_access_control);
+ PARSE_LANGOPT_IMPORTANT(CharIsSigned, diag::warn_pch_char_signed);
+ PARSE_LANGOPT_IMPORTANT(ShortWChar, diag::warn_pch_short_wchar);
+ if ((PPLangOpts.getGCMode() != 0) != (LangOpts.getGCMode() != 0)) {
+ Reader.Diag(diag::warn_pch_gc_mode)
+ << LangOpts.getGCMode() << PPLangOpts.getGCMode();
+ return true;
+ }
+ PARSE_LANGOPT_BENIGN(getVisibilityMode());
+ PARSE_LANGOPT_IMPORTANT(getStackProtectorMode(),
+ diag::warn_pch_stack_protector);
+ PARSE_LANGOPT_BENIGN(InstantiationDepth);
+ PARSE_LANGOPT_IMPORTANT(OpenCL, diag::warn_pch_opencl);
+ PARSE_LANGOPT_BENIGN(CatchUndefined);
+ PARSE_LANGOPT_IMPORTANT(ElideConstructors, diag::warn_pch_elide_constructors);
+ PARSE_LANGOPT_BENIGN(SpellChecking);
+#undef PARSE_LANGOPT_IMPORTANT
+#undef PARSE_LANGOPT_BENIGN
+
+ return false;
+}
+
+bool PCHValidator::ReadTargetTriple(llvm::StringRef Triple) {
+ if (Triple == PP.getTargetInfo().getTriple().str())
+ return false;
+
+ Reader.Diag(diag::warn_pch_target_triple)
+ << Triple << PP.getTargetInfo().getTriple().str();
+ return true;
+}
+
+struct EmptyStringRef {
+ bool operator ()(llvm::StringRef r) const { return r.empty(); }
+};
+struct EmptyBlock {
+ bool operator ()(const PCHPredefinesBlock &r) const { return r.Data.empty(); }
+};
+
+static bool EqualConcatenations(llvm::SmallVector<llvm::StringRef, 2> L,
+ PCHPredefinesBlocks R) {
+ // First, sum up the lengths.
+ unsigned LL = 0, RL = 0;
+ for (unsigned I = 0, N = L.size(); I != N; ++I) {
+ LL += L[I].size();
+ }
+ for (unsigned I = 0, N = R.size(); I != N; ++I) {
+ RL += R[I].Data.size();
+ }
+ if (LL != RL)
+ return false;
+ if (LL == 0 && RL == 0)
+ return true;
+
+ // Kick out empty parts, they confuse the algorithm below.
+ L.erase(std::remove_if(L.begin(), L.end(), EmptyStringRef()), L.end());
+ R.erase(std::remove_if(R.begin(), R.end(), EmptyBlock()), R.end());
+
+ // Do it the hard way. At this point, both vectors must be non-empty.
+ llvm::StringRef LR = L[0], RR = R[0].Data;
+ unsigned LI = 0, RI = 0, LN = L.size(), RN = R.size();
+ for (;;) {
+ // Compare the current pieces.
+ if (LR.size() == RR.size()) {
+ // If they're the same length, it's pretty easy.
+ if (LR != RR)
+ return false;
+ // Both pieces are done, advance.
+ ++LI;
+ ++RI;
+ // If either string is done, they're both done, since they're the same
+ // length.
+ if (LI == LN) {
+ assert(RI == RN && "Strings not the same length after all?");
+ return true;
+ }
+ LR = L[LI];
+ RR = R[RI].Data;
+ } else if (LR.size() < RR.size()) {
+ // Right piece is longer.
+ if (!RR.startswith(LR))
+ return false;
+ ++LI;
+ assert(LI != LN && "Strings not the same length after all?");
+ RR = RR.substr(LR.size());
+ LR = L[LI];
+ } else {
+ // Left piece is longer.
+ if (!LR.startswith(RR))
+ return false;
+ ++RI;
+ assert(RI != RN && "Strings not the same length after all?");
+ LR = LR.substr(RR.size());
+ RR = R[RI].Data;
+ }
+ }
+}
+
+static std::pair<FileID, llvm::StringRef::size_type>
+FindMacro(const PCHPredefinesBlocks &Buffers, llvm::StringRef MacroDef) {
+ std::pair<FileID, llvm::StringRef::size_type> Res;
+ for (unsigned I = 0, N = Buffers.size(); I != N; ++I) {
+ Res.second = Buffers[I].Data.find(MacroDef);
+ if (Res.second != llvm::StringRef::npos) {
+ Res.first = Buffers[I].BufferID;
+ break;
+ }
+ }
+ return Res;
+}
+
+bool PCHValidator::ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers,
+ llvm::StringRef OriginalFileName,
+ std::string &SuggestedPredefines) {
+ // We are in the context of an implicit include, so the predefines buffer will
+ // have a #include entry for the PCH file itself (as normalized by the
+ // preprocessor initialization). Find it and skip over it in the checking
+ // below.
+ llvm::SmallString<256> PCHInclude;
+ PCHInclude += "#include \"";
+ PCHInclude += NormalizeDashIncludePath(OriginalFileName);
+ PCHInclude += "\"\n";
+ std::pair<llvm::StringRef,llvm::StringRef> Split =
+ llvm::StringRef(PP.getPredefines()).split(PCHInclude.str());
+ llvm::StringRef Left = Split.first, Right = Split.second;
+ if (Left == PP.getPredefines()) {
+ Error("Missing PCH include entry!");
+ return true;
+ }
+
+ // If the concatenation of all the PCH buffers is equal to the adjusted
+ // command line, we're done.
+ // We build a SmallVector of the command line here, because we'll eventually
+ // need to support an arbitrary amount of pieces anyway (when we have chained
+ // PCH reading).
+ llvm::SmallVector<llvm::StringRef, 2> CommandLine;
+ CommandLine.push_back(Left);
+ CommandLine.push_back(Right);
+ if (EqualConcatenations(CommandLine, Buffers))
+ return false;
+
+ SourceManager &SourceMgr = PP.getSourceManager();
+
+ // The predefines buffers are different. Determine what the differences are,
+ // and whether they require us to reject the PCH file.
+ llvm::SmallVector<llvm::StringRef, 8> PCHLines;
+ for (unsigned I = 0, N = Buffers.size(); I != N; ++I)
+ Buffers[I].Data.split(PCHLines, "\n", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
+
+ llvm::SmallVector<llvm::StringRef, 8> CmdLineLines;
+ Left.split(CmdLineLines, "\n", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
+ Right.split(CmdLineLines, "\n", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
+
+ // Sort both sets of predefined buffer lines, since we allow some extra
+ // definitions and they may appear at any point in the output.
+ std::sort(CmdLineLines.begin(), CmdLineLines.end());
+ std::sort(PCHLines.begin(), PCHLines.end());
+
+ // Determine which predefines that were used to build the PCH file are missing
+ // from the command line.
+ std::vector<llvm::StringRef> MissingPredefines;
+ std::set_difference(PCHLines.begin(), PCHLines.end(),
+ CmdLineLines.begin(), CmdLineLines.end(),
+ std::back_inserter(MissingPredefines));
+
+ bool MissingDefines = false;
+ bool ConflictingDefines = false;
+ for (unsigned I = 0, N = MissingPredefines.size(); I != N; ++I) {
+ llvm::StringRef Missing = MissingPredefines[I];
+ if (!Missing.startswith("#define ")) {
+ Reader.Diag(diag::warn_pch_compiler_options_mismatch);
+ return true;
+ }
+
+ // This is a macro definition. Determine the name of the macro we're
+ // defining.
+ std::string::size_type StartOfMacroName = strlen("#define ");
+ std::string::size_type EndOfMacroName
+ = Missing.find_first_of("( \n\r", StartOfMacroName);
+ assert(EndOfMacroName != std::string::npos &&
+ "Couldn't find the end of the macro name");
+ llvm::StringRef MacroName = Missing.slice(StartOfMacroName, EndOfMacroName);
+
+ // Determine whether this macro was given a different definition on the
+ // command line.
+ std::string MacroDefStart = "#define " + MacroName.str();
+ std::string::size_type MacroDefLen = MacroDefStart.size();
+ llvm::SmallVector<llvm::StringRef, 8>::iterator ConflictPos
+ = std::lower_bound(CmdLineLines.begin(), CmdLineLines.end(),
+ MacroDefStart);
+ for (; ConflictPos != CmdLineLines.end(); ++ConflictPos) {
+ if (!ConflictPos->startswith(MacroDefStart)) {
+ // Different macro; we're done.
+ ConflictPos = CmdLineLines.end();
+ break;
+ }
+
+ assert(ConflictPos->size() > MacroDefLen &&
+ "Invalid #define in predefines buffer?");
+ if ((*ConflictPos)[MacroDefLen] != ' ' &&
+ (*ConflictPos)[MacroDefLen] != '(')
+ continue; // Longer macro name; keep trying.
+
+ // We found a conflicting macro definition.
+ break;
+ }
+
+ if (ConflictPos != CmdLineLines.end()) {
+ Reader.Diag(diag::warn_cmdline_conflicting_macro_def)
+ << MacroName;
+
+ // Show the definition of this macro within the PCH file.
+ std::pair<FileID, llvm::StringRef::size_type> MacroLoc =
+ FindMacro(Buffers, Missing);
+ assert(MacroLoc.second!=llvm::StringRef::npos && "Unable to find macro!");
+ SourceLocation PCHMissingLoc =
+ SourceMgr.getLocForStartOfFile(MacroLoc.first)
+ .getFileLocWithOffset(MacroLoc.second);
+ Reader.Diag(PCHMissingLoc, diag::note_pch_macro_defined_as) << MacroName;
+
+ ConflictingDefines = true;
+ continue;
+ }
+
+ // If the macro doesn't conflict, then we'll just pick up the macro
+ // definition from the PCH file. Warn the user that they made a mistake.
+ if (ConflictingDefines)
+ continue; // Don't complain if there are already conflicting defs
+
+ if (!MissingDefines) {
+ Reader.Diag(diag::warn_cmdline_missing_macro_defs);
+ MissingDefines = true;
+ }
+
+ // Show the definition of this macro within the PCH file.
+ std::pair<FileID, llvm::StringRef::size_type> MacroLoc =
+ FindMacro(Buffers, Missing);
+ assert(MacroLoc.second!=llvm::StringRef::npos && "Unable to find macro!");
+ SourceLocation PCHMissingLoc =
+ SourceMgr.getLocForStartOfFile(MacroLoc.first)
+ .getFileLocWithOffset(MacroLoc.second);
+ Reader.Diag(PCHMissingLoc, diag::note_using_macro_def_from_pch);
+ }
+
+ if (ConflictingDefines)
+ return true;
+
+ // Determine what predefines were introduced based on command-line
+ // parameters that were not present when building the PCH
+ // file. Extra #defines are okay, so long as the identifiers being
+ // defined were not used within the precompiled header.
+ std::vector<llvm::StringRef> ExtraPredefines;
+ std::set_difference(CmdLineLines.begin(), CmdLineLines.end(),
+ PCHLines.begin(), PCHLines.end(),
+ std::back_inserter(ExtraPredefines));
+ for (unsigned I = 0, N = ExtraPredefines.size(); I != N; ++I) {
+ llvm::StringRef &Extra = ExtraPredefines[I];
+ if (!Extra.startswith("#define ")) {
+ Reader.Diag(diag::warn_pch_compiler_options_mismatch);
+ return true;
+ }
+
+ // This is an extra macro definition. Determine the name of the
+ // macro we're defining.
+ std::string::size_type StartOfMacroName = strlen("#define ");
+ std::string::size_type EndOfMacroName
+ = Extra.find_first_of("( \n\r", StartOfMacroName);
+ assert(EndOfMacroName != std::string::npos &&
+ "Couldn't find the end of the macro name");
+ llvm::StringRef MacroName = Extra.slice(StartOfMacroName, EndOfMacroName);
+
+ // Check whether this name was used somewhere in the PCH file. If
+ // so, defining it as a macro could change behavior, so we reject
+ // the PCH file.
+ if (IdentifierInfo *II = Reader.get(MacroName)) {
+ Reader.Diag(diag::warn_macro_name_used_in_pch) << II;
+ return true;
+ }
+
+ // Add this definition to the suggested predefines buffer.
+ SuggestedPredefines += Extra;
+ SuggestedPredefines += '\n';
+ }
+
+ // If we get here, it's because the predefines buffer had compatible
+ // contents. Accept the PCH file.
+ return false;
+}
+
+void PCHValidator::ReadHeaderFileInfo(const HeaderFileInfo &HFI,
+ unsigned ID) {
+ PP.getHeaderSearchInfo().setHeaderFileInfoForUID(HFI, ID);
+ ++NumHeaderInfos;
+}
+
+void PCHValidator::ReadCounter(unsigned Value) {
+ PP.setCounterValue(Value);
+}
+
+//===----------------------------------------------------------------------===//
+// PCH reader implementation
+//===----------------------------------------------------------------------===//
+
+PCHReader::PCHReader(Preprocessor &PP, ASTContext *Context,
+ const char *isysroot)
+ : Listener(new PCHValidator(PP, *this)), DeserializationListener(0),
+ SourceMgr(PP.getSourceManager()), FileMgr(PP.getFileManager()),
+ Diags(PP.getDiagnostics()), SemaObj(0), PP(&PP), Context(Context),
+ StatCache(0), Consumer(0), IdentifierTableData(0), IdentifierLookupTable(0),
+ IdentifierOffsets(0),
+ MethodPoolLookupTable(0), MethodPoolLookupTableData(0),
+ TotalSelectorsInMethodPool(0), SelectorOffsets(0),
+ TotalNumSelectors(0), MacroDefinitionOffsets(0),
+ NumPreallocatedPreprocessingEntities(0),
+ isysroot(isysroot), NumStatHits(0), NumStatMisses(0),
+ NumSLocEntriesRead(0), NumStatementsRead(0),
+ NumMacrosRead(0), NumMethodPoolSelectorsRead(0), NumMethodPoolMisses(0),
+ NumLexicalDeclContextsRead(0), NumVisibleDeclContextsRead(0),
+ CurrentlyLoadingTypeOrDecl(0) {
+ RelocatablePCH = false;
+}
+
+PCHReader::PCHReader(SourceManager &SourceMgr, FileManager &FileMgr,
+ Diagnostic &Diags, const char *isysroot)
+ : DeserializationListener(0), SourceMgr(SourceMgr), FileMgr(FileMgr),
+ Diags(Diags), SemaObj(0), PP(0), Context(0), StatCache(0), Consumer(0),
+ IdentifierTableData(0), IdentifierLookupTable(0),
+ IdentifierOffsets(0),
+ MethodPoolLookupTable(0), MethodPoolLookupTableData(0),
+ TotalSelectorsInMethodPool(0), SelectorOffsets(0),
+ TotalNumSelectors(0), MacroDefinitionOffsets(0),
+ NumPreallocatedPreprocessingEntities(0),
+ isysroot(isysroot), NumStatHits(0), NumStatMisses(0),
+ NumSLocEntriesRead(0), NumStatementsRead(0),
+ NumMacrosRead(0), NumMethodPoolSelectorsRead(0), NumMethodPoolMisses(0),
+ NumLexicalDeclContextsRead(0), NumVisibleDeclContextsRead(0),
+ CurrentlyLoadingTypeOrDecl(0) {
+ RelocatablePCH = false;
+}
+
+PCHReader::~PCHReader() {}
+
+
+namespace {
+class PCHMethodPoolLookupTrait {
+ PCHReader &Reader;
+
+public:
+ typedef std::pair<ObjCMethodList, ObjCMethodList> data_type;
+
+ typedef Selector external_key_type;
+ typedef external_key_type internal_key_type;
+
+ explicit PCHMethodPoolLookupTrait(PCHReader &Reader) : Reader(Reader) { }
+
+ static bool EqualKey(const internal_key_type& a,
+ const internal_key_type& b) {
+ return a == b;
+ }
+
+ static unsigned ComputeHash(Selector Sel) {
+ unsigned N = Sel.getNumArgs();
+ if (N == 0)
+ ++N;
+ unsigned R = 5381;
+ for (unsigned I = 0; I != N; ++I)
+ if (IdentifierInfo *II = Sel.getIdentifierInfoForSlot(I))
+ R = llvm::HashString(II->getName(), R);
+ return R;
+ }
+
+ // This hopefully will just get inlined and removed by the optimizer.
+ static const internal_key_type&
+ GetInternalKey(const external_key_type& x) { return x; }
+
+ static std::pair<unsigned, unsigned>
+ ReadKeyDataLength(const unsigned char*& d) {
+ using namespace clang::io;
+ unsigned KeyLen = ReadUnalignedLE16(d);
+ unsigned DataLen = ReadUnalignedLE16(d);
+ return std::make_pair(KeyLen, DataLen);
+ }
+
+ internal_key_type ReadKey(const unsigned char* d, unsigned) {
+ using namespace clang::io;
+ SelectorTable &SelTable = Reader.getContext()->Selectors;
+ unsigned N = ReadUnalignedLE16(d);
+ IdentifierInfo *FirstII
+ = Reader.DecodeIdentifierInfo(ReadUnalignedLE32(d));
+ if (N == 0)
+ return SelTable.getNullarySelector(FirstII);
+ else if (N == 1)
+ return SelTable.getUnarySelector(FirstII);
+
+ llvm::SmallVector<IdentifierInfo *, 16> Args;
+ Args.push_back(FirstII);
+ for (unsigned I = 1; I != N; ++I)
+ Args.push_back(Reader.DecodeIdentifierInfo(ReadUnalignedLE32(d)));
+
+ return SelTable.getSelector(N, Args.data());
+ }
+
+ data_type ReadData(Selector, const unsigned char* d, unsigned DataLen) {
+ using namespace clang::io;
+ unsigned NumInstanceMethods = ReadUnalignedLE16(d);
+ unsigned NumFactoryMethods = ReadUnalignedLE16(d);
+
+ data_type Result;
+
+ // Load instance methods
+ ObjCMethodList *Prev = 0;
+ for (unsigned I = 0; I != NumInstanceMethods; ++I) {
+ ObjCMethodDecl *Method
+ = cast<ObjCMethodDecl>(Reader.GetDecl(ReadUnalignedLE32(d)));
+ if (!Result.first.Method) {
+ // This is the first method, which is the easy case.
+ Result.first.Method = Method;
+ Prev = &Result.first;
+ continue;
+ }
+
+ ObjCMethodList *Mem =
+ Reader.getSema()->BumpAlloc.Allocate<ObjCMethodList>();
+ Prev->Next = new (Mem) ObjCMethodList(Method, 0);
+ Prev = Prev->Next;
+ }
+
+ // Load factory methods
+ Prev = 0;
+ for (unsigned I = 0; I != NumFactoryMethods; ++I) {
+ ObjCMethodDecl *Method
+ = cast<ObjCMethodDecl>(Reader.GetDecl(ReadUnalignedLE32(d)));
+ if (!Result.second.Method) {
+ // This is the first method, which is the easy case.
+ Result.second.Method = Method;
+ Prev = &Result.second;
+ continue;
+ }
+
+ ObjCMethodList *Mem =
+ Reader.getSema()->BumpAlloc.Allocate<ObjCMethodList>();
+ Prev->Next = new (Mem) ObjCMethodList(Method, 0);
+ Prev = Prev->Next;
+ }
+
+ return Result;
+ }
+};
+
+} // end anonymous namespace
+
+/// \brief The on-disk hash table used for the global method pool.
+typedef OnDiskChainedHashTable<PCHMethodPoolLookupTrait>
+ PCHMethodPoolLookupTable;
+
+namespace {
+class PCHIdentifierLookupTrait {
+ PCHReader &Reader;
+
+ // If we know the IdentifierInfo in advance, it is here and we will
+ // not build a new one. Used when deserializing information about an
+ // identifier that was constructed before the PCH file was read.
+ IdentifierInfo *KnownII;
+
+public:
+ typedef IdentifierInfo * data_type;
+
+ typedef const std::pair<const char*, unsigned> external_key_type;
+
+ typedef external_key_type internal_key_type;
+
+ explicit PCHIdentifierLookupTrait(PCHReader &Reader, IdentifierInfo *II = 0)
+ : Reader(Reader), KnownII(II) { }
+
+ static bool EqualKey(const internal_key_type& a,
+ const internal_key_type& b) {
+ return (a.second == b.second) ? memcmp(a.first, b.first, a.second) == 0
+ : false;
+ }
+
+ static unsigned ComputeHash(const internal_key_type& a) {
+ return llvm::HashString(llvm::StringRef(a.first, a.second));
+ }
+
+ // This hopefully will just get inlined and removed by the optimizer.
+ static const internal_key_type&
+ GetInternalKey(const external_key_type& x) { return x; }
+
+ static std::pair<unsigned, unsigned>
+ ReadKeyDataLength(const unsigned char*& d) {
+ using namespace clang::io;
+ unsigned DataLen = ReadUnalignedLE16(d);
+ unsigned KeyLen = ReadUnalignedLE16(d);
+ return std::make_pair(KeyLen, DataLen);
+ }
+
+ static std::pair<const char*, unsigned>
+ ReadKey(const unsigned char* d, unsigned n) {
+ assert(n >= 2 && d[n-1] == '\0');
+ return std::make_pair((const char*) d, n-1);
+ }
+
+ IdentifierInfo *ReadData(const internal_key_type& k,
+ const unsigned char* d,
+ unsigned DataLen) {
+ using namespace clang::io;
+ pch::IdentID ID = ReadUnalignedLE32(d);
+ bool IsInteresting = ID & 0x01;
+
+ // Wipe out the "is interesting" bit.
+ ID = ID >> 1;
+
+ if (!IsInteresting) {
+ // For unintersting identifiers, just build the IdentifierInfo
+ // and associate it with the persistent ID.
+ IdentifierInfo *II = KnownII;
+ if (!II)
+ II = &Reader.getIdentifierTable().CreateIdentifierInfo(
+ k.first, k.first + k.second);
+ Reader.SetIdentifierInfo(ID, II);
+ return II;
+ }
+
+ unsigned Bits = ReadUnalignedLE16(d);
+ bool CPlusPlusOperatorKeyword = Bits & 0x01;
+ Bits >>= 1;
+ bool Poisoned = Bits & 0x01;
+ Bits >>= 1;
+ bool ExtensionToken = Bits & 0x01;
+ Bits >>= 1;
+ bool hasMacroDefinition = Bits & 0x01;
+ Bits >>= 1;
+ unsigned ObjCOrBuiltinID = Bits & 0x3FF;
+ Bits >>= 10;
+
+ assert(Bits == 0 && "Extra bits in the identifier?");
+ DataLen -= 6;
+
+ // Build the IdentifierInfo itself and link the identifier ID with
+ // the new IdentifierInfo.
+ IdentifierInfo *II = KnownII;
+ if (!II)
+ II = &Reader.getIdentifierTable().CreateIdentifierInfo(
+ k.first, k.first + k.second);
+ Reader.SetIdentifierInfo(ID, II);
+
+ // Set or check the various bits in the IdentifierInfo structure.
+ // FIXME: Load token IDs lazily, too?
+ II->setObjCOrBuiltinID(ObjCOrBuiltinID);
+ assert(II->isExtensionToken() == ExtensionToken &&
+ "Incorrect extension token flag");
+ (void)ExtensionToken;
+ II->setIsPoisoned(Poisoned);
+ assert(II->isCPlusPlusOperatorKeyword() == CPlusPlusOperatorKeyword &&
+ "Incorrect C++ operator keyword flag");
+ (void)CPlusPlusOperatorKeyword;
+
+ // If this identifier is a macro, deserialize the macro
+ // definition.
+ if (hasMacroDefinition) {
+ uint32_t Offset = ReadUnalignedLE32(d);
+ Reader.ReadMacroRecord(Offset);
+ DataLen -= 4;
+ }
+
+ // Read all of the declarations visible at global scope with this
+ // name.
+ if (Reader.getContext() == 0) return II;
+ if (DataLen > 0) {
+ llvm::SmallVector<uint32_t, 4> DeclIDs;
+ for (; DataLen > 0; DataLen -= 4)
+ DeclIDs.push_back(ReadUnalignedLE32(d));
+ Reader.SetGloballyVisibleDecls(II, DeclIDs);
+ }
+
+ return II;
+ }
+};
+
+} // end anonymous namespace
+
+/// \brief The on-disk hash table used to contain information about
+/// all of the identifiers in the program.
+typedef OnDiskChainedHashTable<PCHIdentifierLookupTrait>
+ PCHIdentifierLookupTable;
+
+void PCHReader::Error(const char *Msg) {
+ Diag(diag::err_fe_pch_malformed) << Msg;
+}
+
+/// \brief Check the contents of the concatenation of all predefines buffers in
+/// the PCH chain against the contents of the predefines buffer of the current
+/// compiler invocation.
+///
+/// The contents should be the same. If not, then some command-line option
+/// changed the preprocessor state and we must probably reject the PCH file.
+///
+/// \returns true if there was a mismatch (in which case the PCH file
+/// should be ignored), or false otherwise.
+bool PCHReader::CheckPredefinesBuffers() {
+ if (Listener)
+ return Listener->ReadPredefinesBuffer(PCHPredefinesBuffers,
+ ActualOriginalFileName,
+ SuggestedPredefines);
+ return false;
+}
+
+//===----------------------------------------------------------------------===//
+// Source Manager Deserialization
+//===----------------------------------------------------------------------===//
+
+/// \brief Read the line table in the source manager block.
+/// \returns true if ther was an error.
+bool PCHReader::ParseLineTable(llvm::SmallVectorImpl<uint64_t> &Record) {
+ unsigned Idx = 0;
+ LineTableInfo &LineTable = SourceMgr.getLineTable();
+
+ // Parse the file names
+ std::map<int, int> FileIDs;
+ for (int I = 0, N = Record[Idx++]; I != N; ++I) {
+ // Extract the file name
+ unsigned FilenameLen = Record[Idx++];
+ std::string Filename(&Record[Idx], &Record[Idx] + FilenameLen);
+ Idx += FilenameLen;
+ MaybeAddSystemRootToFilename(Filename);
+ FileIDs[I] = LineTable.getLineTableFilenameID(Filename.c_str(),
+ Filename.size());
+ }
+
+ // Parse the line entries
+ std::vector<LineEntry> Entries;
+ while (Idx < Record.size()) {
+ int FID = Record[Idx++];
+
+ // Extract the line entries
+ unsigned NumEntries = Record[Idx++];
+ assert(NumEntries && "Numentries is 00000");
+ Entries.clear();
+ Entries.reserve(NumEntries);
+ for (unsigned I = 0; I != NumEntries; ++I) {
+ unsigned FileOffset = Record[Idx++];
+ unsigned LineNo = Record[Idx++];
+ int FilenameID = FileIDs[Record[Idx++]];
+ SrcMgr::CharacteristicKind FileKind
+ = (SrcMgr::CharacteristicKind)Record[Idx++];
+ unsigned IncludeOffset = Record[Idx++];
+ Entries.push_back(LineEntry::get(FileOffset, LineNo, FilenameID,
+ FileKind, IncludeOffset));
+ }
+ LineTable.AddEntry(FID, Entries);
+ }
+
+ return false;
+}
+
+namespace {
+
+class PCHStatData {
+public:
+ const bool hasStat;
+ const ino_t ino;
+ const dev_t dev;
+ const mode_t mode;
+ const time_t mtime;
+ const off_t size;
+
+ PCHStatData(ino_t i, dev_t d, mode_t mo, time_t m, off_t s)
+ : hasStat(true), ino(i), dev(d), mode(mo), mtime(m), size(s) {}
+
+ PCHStatData()
+ : hasStat(false), ino(0), dev(0), mode(0), mtime(0), size(0) {}
+};
+
+class PCHStatLookupTrait {
+ public:
+ typedef const char *external_key_type;
+ typedef const char *internal_key_type;
+
+ typedef PCHStatData data_type;
+
+ static unsigned ComputeHash(const char *path) {
+ return llvm::HashString(path);
+ }
+
+ static internal_key_type GetInternalKey(const char *path) { return path; }
+
+ static bool EqualKey(internal_key_type a, internal_key_type b) {
+ return strcmp(a, b) == 0;
+ }
+
+ static std::pair<unsigned, unsigned>
+ ReadKeyDataLength(const unsigned char*& d) {
+ unsigned KeyLen = (unsigned) clang::io::ReadUnalignedLE16(d);
+ unsigned DataLen = (unsigned) *d++;
+ return std::make_pair(KeyLen + 1, DataLen);
+ }
+
+ static internal_key_type ReadKey(const unsigned char *d, unsigned) {
+ return (const char *)d;
+ }
+
+ static data_type ReadData(const internal_key_type, const unsigned char *d,
+ unsigned /*DataLen*/) {
+ using namespace clang::io;
+
+ if (*d++ == 1)
+ return data_type();
+
+ ino_t ino = (ino_t) ReadUnalignedLE32(d);
+ dev_t dev = (dev_t) ReadUnalignedLE32(d);
+ mode_t mode = (mode_t) ReadUnalignedLE16(d);
+ time_t mtime = (time_t) ReadUnalignedLE64(d);
+ off_t size = (off_t) ReadUnalignedLE64(d);
+ return data_type(ino, dev, mode, mtime, size);
+ }
+};
+
+/// \brief stat() cache for precompiled headers.
+///
+/// This cache is very similar to the stat cache used by pretokenized
+/// headers.
+class PCHStatCache : public StatSysCallCache {
+ typedef OnDiskChainedHashTable<PCHStatLookupTrait> CacheTy;
+ CacheTy *Cache;
+
+ unsigned &NumStatHits, &NumStatMisses;
+public:
+ PCHStatCache(const unsigned char *Buckets,
+ const unsigned char *Base,
+ unsigned &NumStatHits,
+ unsigned &NumStatMisses)
+ : Cache(0), NumStatHits(NumStatHits), NumStatMisses(NumStatMisses) {
+ Cache = CacheTy::Create(Buckets, Base);
+ }
+
+ ~PCHStatCache() { delete Cache; }
+
+ int stat(const char *path, struct stat *buf) {
+ // Do the lookup for the file's data in the PCH file.
+ CacheTy::iterator I = Cache->find(path);
+
+ // If we don't get a hit in the PCH file just forward to 'stat'.
+ if (I == Cache->end()) {
+ ++NumStatMisses;
+ return StatSysCallCache::stat(path, buf);
+ }
+
+ ++NumStatHits;
+ PCHStatData Data = *I;
+
+ if (!Data.hasStat)
+ return 1;
+
+ buf->st_ino = Data.ino;
+ buf->st_dev = Data.dev;
+ buf->st_mtime = Data.mtime;
+ buf->st_mode = Data.mode;
+ buf->st_size = Data.size;
+ return 0;
+ }
+};
+} // end anonymous namespace
+
+
+/// \brief Read the source manager block
+PCHReader::PCHReadResult PCHReader::ReadSourceManagerBlock() {
+ using namespace SrcMgr;
+
+ // Set the source-location entry cursor to the current position in
+ // the stream. This cursor will be used to read the contents of the
+ // source manager block initially, and then lazily read
+ // source-location entries as needed.
+ SLocEntryCursor = Stream;
+
+ // The stream itself is going to skip over the source manager block.
+ if (Stream.SkipBlock()) {
+ Error("malformed block record in PCH file");
+ return Failure;
+ }
+
+ // Enter the source manager block.
+ if (SLocEntryCursor.EnterSubBlock(pch::SOURCE_MANAGER_BLOCK_ID)) {
+ Error("malformed source manager block record in PCH file");
+ return Failure;
+ }
+
+ RecordData Record;
+ while (true) {
+ unsigned Code = SLocEntryCursor.ReadCode();
+ if (Code == llvm::bitc::END_BLOCK) {
+ if (SLocEntryCursor.ReadBlockEnd()) {
+ Error("error at end of Source Manager block in PCH file");
+ return Failure;
+ }
+ return Success;
+ }
+
+ if (Code == llvm::bitc::ENTER_SUBBLOCK) {
+ // No known subblocks, always skip them.
+ SLocEntryCursor.ReadSubBlockID();
+ if (SLocEntryCursor.SkipBlock()) {
+ Error("malformed block record in PCH file");
+ return Failure;
+ }
+ continue;
+ }
+
+ if (Code == llvm::bitc::DEFINE_ABBREV) {
+ SLocEntryCursor.ReadAbbrevRecord();
+ continue;
+ }
+
+ // Read a record.
+ const char *BlobStart;
+ unsigned BlobLen;
+ Record.clear();
+ switch (SLocEntryCursor.ReadRecord(Code, Record, &BlobStart, &BlobLen)) {
+ default: // Default behavior: ignore.
+ break;
+
+ case pch::SM_LINE_TABLE:
+ if (ParseLineTable(Record))
+ return Failure;
+ break;
+
+ case pch::SM_SLOC_FILE_ENTRY:
+ case pch::SM_SLOC_BUFFER_ENTRY:
+ case pch::SM_SLOC_INSTANTIATION_ENTRY:
+ // Once we hit one of the source location entries, we're done.
+ return Success;
+ }
+ }
+}
+
+/// \brief Read in the source location entry with the given ID.
+PCHReader::PCHReadResult PCHReader::ReadSLocEntryRecord(unsigned ID) {
+ if (ID == 0)
+ return Success;
+
+ if (ID > TotalNumSLocEntries) {
+ Error("source location entry ID out-of-range for PCH file");
+ return Failure;
+ }
+
+ ++NumSLocEntriesRead;
+ SLocEntryCursor.JumpToBit(SLocOffsets[ID - 1]);
+ unsigned Code = SLocEntryCursor.ReadCode();
+ if (Code == llvm::bitc::END_BLOCK ||
+ Code == llvm::bitc::ENTER_SUBBLOCK ||
+ Code == llvm::bitc::DEFINE_ABBREV) {
+ Error("incorrectly-formatted source location entry in PCH file");
+ return Failure;
+ }
+
+ RecordData Record;
+ const char *BlobStart;
+ unsigned BlobLen;
+ switch (SLocEntryCursor.ReadRecord(Code, Record, &BlobStart, &BlobLen)) {
+ default:
+ Error("incorrectly-formatted source location entry in PCH file");
+ return Failure;
+
+ case pch::SM_SLOC_FILE_ENTRY: {
+ std::string Filename(BlobStart, BlobStart + BlobLen);
+ MaybeAddSystemRootToFilename(Filename);
+ const FileEntry *File = FileMgr.getFile(Filename);
+ if (File == 0) {
+ std::string ErrorStr = "could not find file '";
+ ErrorStr += Filename;
+ ErrorStr += "' referenced by PCH file";
+ Error(ErrorStr.c_str());
+ return Failure;
+ }
+
+ if (Record.size() < 10) {
+ Error("source location entry is incorrect");
+ return Failure;
+ }
+
+ if ((off_t)Record[4] != File->getSize()
+#if !defined(LLVM_ON_WIN32)
+ // In our regression testing, the Windows file system seems to
+ // have inconsistent modification times that sometimes
+ // erroneously trigger this error-handling path.
+ || (time_t)Record[5] != File->getModificationTime()
+#endif
+ ) {
+ Diag(diag::err_fe_pch_file_modified)
+ << Filename;
+ return Failure;
+ }
+
+ FileID FID = SourceMgr.createFileID(File,
+ SourceLocation::getFromRawEncoding(Record[1]),
+ (SrcMgr::CharacteristicKind)Record[2],
+ ID, Record[0]);
+ if (Record[3])
+ const_cast<SrcMgr::FileInfo&>(SourceMgr.getSLocEntry(FID).getFile())
+ .setHasLineDirectives();
+
+ // Reconstruct header-search information for this file.
+ HeaderFileInfo HFI;
+ HFI.isImport = Record[6];
+ HFI.DirInfo = Record[7];
+ HFI.NumIncludes = Record[8];
+ HFI.ControllingMacroID = Record[9];
+ if (Listener)
+ Listener->ReadHeaderFileInfo(HFI, File->getUID());
+ break;
+ }
+
+ case pch::SM_SLOC_BUFFER_ENTRY: {
+ const char *Name = BlobStart;
+ unsigned Offset = Record[0];
+ unsigned Code = SLocEntryCursor.ReadCode();
+ Record.clear();
+ unsigned RecCode
+ = SLocEntryCursor.ReadRecord(Code, Record, &BlobStart, &BlobLen);
+
+ if (RecCode != pch::SM_SLOC_BUFFER_BLOB) {
+ Error("PCH record has invalid code");
+ return Failure;
+ }
+
+ llvm::MemoryBuffer *Buffer
+ = llvm::MemoryBuffer::getMemBuffer(llvm::StringRef(BlobStart, BlobLen - 1),
+ Name);
+ FileID BufferID = SourceMgr.createFileIDForMemBuffer(Buffer, ID, Offset);
+
+ if (strcmp(Name, "<built-in>") == 0) {
+ PCHPredefinesBlock Block = {
+ BufferID,
+ llvm::StringRef(BlobStart, BlobLen - 1)
+ };
+ PCHPredefinesBuffers.push_back(Block);
+ }
+
+ break;
+ }
+
+ case pch::SM_SLOC_INSTANTIATION_ENTRY: {
+ SourceLocation SpellingLoc
+ = SourceLocation::getFromRawEncoding(Record[1]);
+ SourceMgr.createInstantiationLoc(SpellingLoc,
+ SourceLocation::getFromRawEncoding(Record[2]),
+ SourceLocation::getFromRawEncoding(Record[3]),
+ Record[4],
+ ID,
+ Record[0]);
+ break;
+ }
+ }
+
+ return Success;
+}
+
+/// ReadBlockAbbrevs - Enter a subblock of the specified BlockID with the
+/// specified cursor. Read the abbreviations that are at the top of the block
+/// and then leave the cursor pointing into the block.
+bool PCHReader::ReadBlockAbbrevs(llvm::BitstreamCursor &Cursor,
+ unsigned BlockID) {
+ if (Cursor.EnterSubBlock(BlockID)) {
+ Error("malformed block record in PCH file");
+ return Failure;
+ }
+
+ while (true) {
+ unsigned Code = Cursor.ReadCode();
+
+ // We expect all abbrevs to be at the start of the block.
+ if (Code != llvm::bitc::DEFINE_ABBREV)
+ return false;
+ Cursor.ReadAbbrevRecord();
+ }
+}
+
+void PCHReader::ReadMacroRecord(uint64_t Offset) {
+ assert(PP && "Forgot to set Preprocessor ?");
+
+ // Keep track of where we are in the stream, then jump back there
+ // after reading this macro.
+ SavedStreamPosition SavedPosition(Stream);
+
+ Stream.JumpToBit(Offset);
+ RecordData Record;
+ llvm::SmallVector<IdentifierInfo*, 16> MacroArgs;
+ MacroInfo *Macro = 0;
+
+ while (true) {
+ unsigned Code = Stream.ReadCode();
+ switch (Code) {
+ case llvm::bitc::END_BLOCK:
+ return;
+
+ case llvm::bitc::ENTER_SUBBLOCK:
+ // No known subblocks, always skip them.
+ Stream.ReadSubBlockID();
+ if (Stream.SkipBlock()) {
+ Error("malformed block record in PCH file");
+ return;
+ }
+ continue;
+
+ case llvm::bitc::DEFINE_ABBREV:
+ Stream.ReadAbbrevRecord();
+ continue;
+ default: break;
+ }
+
+ // Read a record.
+ Record.clear();
+ pch::PreprocessorRecordTypes RecType =
+ (pch::PreprocessorRecordTypes)Stream.ReadRecord(Code, Record);
+ switch (RecType) {
+ case pch::PP_MACRO_OBJECT_LIKE:
+ case pch::PP_MACRO_FUNCTION_LIKE: {
+ // If we already have a macro, that means that we've hit the end
+ // of the definition of the macro we were looking for. We're
+ // done.
+ if (Macro)
+ return;
+
+ IdentifierInfo *II = DecodeIdentifierInfo(Record[0]);
+ if (II == 0) {
+ Error("macro must have a name in PCH file");
+ return;
+ }
+ SourceLocation Loc = SourceLocation::getFromRawEncoding(Record[1]);
+ bool isUsed = Record[2];
+
+ MacroInfo *MI = PP->AllocateMacroInfo(Loc);
+ MI->setIsUsed(isUsed);
+
+ unsigned NextIndex = 3;
+ if (RecType == pch::PP_MACRO_FUNCTION_LIKE) {
+ // Decode function-like macro info.
+ bool isC99VarArgs = Record[3];
+ bool isGNUVarArgs = Record[4];
+ MacroArgs.clear();
+ unsigned NumArgs = Record[5];
+ NextIndex = 6 + NumArgs;
+ for (unsigned i = 0; i != NumArgs; ++i)
+ MacroArgs.push_back(DecodeIdentifierInfo(Record[6+i]));
+
+ // Install function-like macro info.
+ MI->setIsFunctionLike();
+ if (isC99VarArgs) MI->setIsC99Varargs();
+ if (isGNUVarArgs) MI->setIsGNUVarargs();
+ MI->setArgumentList(MacroArgs.data(), MacroArgs.size(),
+ PP->getPreprocessorAllocator());
+ }
+
+ // Finally, install the macro.
+ PP->setMacroInfo(II, MI);
+
+ // Remember that we saw this macro last so that we add the tokens that
+ // form its body to it.
+ Macro = MI;
+
+ if (NextIndex + 1 == Record.size() && PP->getPreprocessingRecord()) {
+ // We have a macro definition. Load it now.
+ PP->getPreprocessingRecord()->RegisterMacroDefinition(Macro,
+ getMacroDefinition(Record[NextIndex]));
+ }
+
+ ++NumMacrosRead;
+ break;
+ }
+
+ case pch::PP_TOKEN: {
+ // If we see a TOKEN before a PP_MACRO_*, then the file is
+ // erroneous, just pretend we didn't see this.
+ if (Macro == 0) break;
+
+ Token Tok;
+ Tok.startToken();
+ Tok.setLocation(SourceLocation::getFromRawEncoding(Record[0]));
+ Tok.setLength(Record[1]);
+ if (IdentifierInfo *II = DecodeIdentifierInfo(Record[2]))
+ Tok.setIdentifierInfo(II);
+ Tok.setKind((tok::TokenKind)Record[3]);
+ Tok.setFlag((Token::TokenFlags)Record[4]);
+ Macro->AddTokenToBody(Tok);
+ break;
+ }
+
+ case pch::PP_MACRO_INSTANTIATION: {
+ // If we already have a macro, that means that we've hit the end
+ // of the definition of the macro we were looking for. We're
+ // done.
+ if (Macro)
+ return;
+
+ if (!PP->getPreprocessingRecord()) {
+ Error("missing preprocessing record in PCH file");
+ return;
+ }
+
+ PreprocessingRecord &PPRec = *PP->getPreprocessingRecord();
+ if (PPRec.getPreprocessedEntity(Record[0]))
+ return;
+
+ MacroInstantiation *MI
+ = new (PPRec) MacroInstantiation(DecodeIdentifierInfo(Record[3]),
+ SourceRange(
+ SourceLocation::getFromRawEncoding(Record[1]),
+ SourceLocation::getFromRawEncoding(Record[2])),
+ getMacroDefinition(Record[4]));
+ PPRec.SetPreallocatedEntity(Record[0], MI);
+ return;
+ }
+
+ case pch::PP_MACRO_DEFINITION: {
+ // If we already have a macro, that means that we've hit the end
+ // of the definition of the macro we were looking for. We're
+ // done.
+ if (Macro)
+ return;
+
+ if (!PP->getPreprocessingRecord()) {
+ Error("missing preprocessing record in PCH file");
+ return;
+ }
+
+ PreprocessingRecord &PPRec = *PP->getPreprocessingRecord();
+ if (PPRec.getPreprocessedEntity(Record[0]))
+ return;
+
+ if (Record[1] >= MacroDefinitionsLoaded.size()) {
+ Error("out-of-bounds macro definition record");
+ return;
+ }
+
+ MacroDefinition *MD
+ = new (PPRec) MacroDefinition(DecodeIdentifierInfo(Record[4]),
+ SourceLocation::getFromRawEncoding(Record[5]),
+ SourceRange(
+ SourceLocation::getFromRawEncoding(Record[2]),
+ SourceLocation::getFromRawEncoding(Record[3])));
+ PPRec.SetPreallocatedEntity(Record[0], MD);
+ MacroDefinitionsLoaded[Record[1]] = MD;
+ return;
+ }
+ }
+ }
+}
+
+void PCHReader::ReadDefinedMacros() {
+ // If there was no preprocessor block, do nothing.
+ if (!MacroCursor.getBitStreamReader())
+ return;
+
+ llvm::BitstreamCursor Cursor = MacroCursor;
+ if (Cursor.EnterSubBlock(pch::PREPROCESSOR_BLOCK_ID)) {
+ Error("malformed preprocessor block record in PCH file");
+ return;
+ }
+
+ RecordData Record;
+ while (true) {
+ unsigned Code = Cursor.ReadCode();
+ if (Code == llvm::bitc::END_BLOCK) {
+ if (Cursor.ReadBlockEnd())
+ Error("error at end of preprocessor block in PCH file");
+ return;
+ }
+
+ if (Code == llvm::bitc::ENTER_SUBBLOCK) {
+ // No known subblocks, always skip them.
+ Cursor.ReadSubBlockID();
+ if (Cursor.SkipBlock()) {
+ Error("malformed block record in PCH file");
+ return;
+ }
+ continue;
+ }
+
+ if (Code == llvm::bitc::DEFINE_ABBREV) {
+ Cursor.ReadAbbrevRecord();
+ continue;
+ }
+
+ // Read a record.
+ const char *BlobStart;
+ unsigned BlobLen;
+ Record.clear();
+ switch (Cursor.ReadRecord(Code, Record, &BlobStart, &BlobLen)) {
+ default: // Default behavior: ignore.
+ break;
+
+ case pch::PP_MACRO_OBJECT_LIKE:
+ case pch::PP_MACRO_FUNCTION_LIKE:
+ DecodeIdentifierInfo(Record[0]);
+ break;
+
+ case pch::PP_TOKEN:
+ // Ignore tokens.
+ break;
+
+ case pch::PP_MACRO_INSTANTIATION:
+ case pch::PP_MACRO_DEFINITION:
+ // Read the macro record.
+ ReadMacroRecord(Cursor.GetCurrentBitNo());
+ break;
+ }
+ }
+}
+
+MacroDefinition *PCHReader::getMacroDefinition(pch::IdentID ID) {
+ if (ID == 0 || ID >= MacroDefinitionsLoaded.size())
+ return 0;
+
+ if (!MacroDefinitionsLoaded[ID])
+ ReadMacroRecord(MacroDefinitionOffsets[ID]);
+
+ return MacroDefinitionsLoaded[ID];
+}
+
+/// \brief If we are loading a relocatable PCH file, and the filename is
+/// not an absolute path, add the system root to the beginning of the file
+/// name.
+void PCHReader::MaybeAddSystemRootToFilename(std::string &Filename) {
+ // If this is not a relocatable PCH file, there's nothing to do.
+ if (!RelocatablePCH)
+ return;
+
+ if (Filename.empty() || llvm::sys::Path(Filename).isAbsolute())
+ return;
+
+ if (isysroot == 0) {
+ // If no system root was given, default to '/'
+ Filename.insert(Filename.begin(), '/');
+ return;
+ }
+
+ unsigned Length = strlen(isysroot);
+ if (isysroot[Length - 1] != '/')
+ Filename.insert(Filename.begin(), '/');
+
+ Filename.insert(Filename.begin(), isysroot, isysroot + Length);
+}
+
+PCHReader::PCHReadResult
+PCHReader::ReadPCHBlock() {
+ if (Stream.EnterSubBlock(pch::PCH_BLOCK_ID)) {
+ Error("malformed block record in PCH file");
+ return Failure;
+ }
+
+ // Read all of the records and blocks for the PCH file.
+ RecordData Record;
+ while (!Stream.AtEndOfStream()) {
+ unsigned Code = Stream.ReadCode();
+ if (Code == llvm::bitc::END_BLOCK) {
+ if (Stream.ReadBlockEnd()) {
+ Error("error at end of module block in PCH file");
+ return Failure;
+ }
+
+ return Success;
+ }
+
+ if (Code == llvm::bitc::ENTER_SUBBLOCK) {
+ switch (Stream.ReadSubBlockID()) {
+ case pch::DECLTYPES_BLOCK_ID:
+ // We lazily load the decls block, but we want to set up the
+ // DeclsCursor cursor to point into it. Clone our current bitcode
+ // cursor to it, enter the block and read the abbrevs in that block.
+ // With the main cursor, we just skip over it.
+ DeclsCursor = Stream;
+ if (Stream.SkipBlock() || // Skip with the main cursor.
+ // Read the abbrevs.
+ ReadBlockAbbrevs(DeclsCursor, pch::DECLTYPES_BLOCK_ID)) {
+ Error("malformed block record in PCH file");
+ return Failure;
+ }
+ break;
+
+ case pch::PREPROCESSOR_BLOCK_ID:
+ MacroCursor = Stream;
+ if (PP)
+ PP->setExternalSource(this);
+
+ if (Stream.SkipBlock()) {
+ Error("malformed block record in PCH file");
+ return Failure;
+ }
+ break;
+
+ case pch::SOURCE_MANAGER_BLOCK_ID:
+ switch (ReadSourceManagerBlock()) {
+ case Success:
+ break;
+
+ case Failure:
+ Error("malformed source manager block in PCH file");
+ return Failure;
+
+ case IgnorePCH:
+ return IgnorePCH;
+ }
+ break;
+ }
+ continue;
+ }
+
+ if (Code == llvm::bitc::DEFINE_ABBREV) {
+ Stream.ReadAbbrevRecord();
+ continue;
+ }
+
+ // Read and process a record.
+ Record.clear();
+ const char *BlobStart = 0;
+ unsigned BlobLen = 0;
+ switch ((pch::PCHRecordTypes)Stream.ReadRecord(Code, Record,
+ &BlobStart, &BlobLen)) {
+ default: // Default behavior: ignore.
+ break;
+
+ case pch::TYPE_OFFSET:
+ if (!TypesLoaded.empty()) {
+ Error("duplicate TYPE_OFFSET record in PCH file");
+ return Failure;
+ }
+ TypeOffsets = (const uint32_t *)BlobStart;
+ TypesLoaded.resize(Record[0]);
+ break;
+
+ case pch::DECL_OFFSET:
+ if (!DeclsLoaded.empty()) {
+ Error("duplicate DECL_OFFSET record in PCH file");
+ return Failure;
+ }
+ DeclOffsets = (const uint32_t *)BlobStart;
+ DeclsLoaded.resize(Record[0]);
+ break;
+
+ case pch::LANGUAGE_OPTIONS:
+ if (ParseLanguageOptions(Record))
+ return IgnorePCH;
+ break;
+
+ case pch::METADATA: {
+ if (Record[0] != pch::VERSION_MAJOR) {
+ Diag(Record[0] < pch::VERSION_MAJOR? diag::warn_pch_version_too_old
+ : diag::warn_pch_version_too_new);
+ return IgnorePCH;
+ }
+
+ RelocatablePCH = Record[4];
+ if (Listener) {
+ std::string TargetTriple(BlobStart, BlobLen);
+ if (Listener->ReadTargetTriple(TargetTriple))
+ return IgnorePCH;
+ }
+ break;
+ }
+
+ case pch::IDENTIFIER_TABLE:
+ IdentifierTableData = BlobStart;
+ if (Record[0]) {
+ IdentifierLookupTable
+ = PCHIdentifierLookupTable::Create(
+ (const unsigned char *)IdentifierTableData + Record[0],
+ (const unsigned char *)IdentifierTableData,
+ PCHIdentifierLookupTrait(*this));
+ if (PP)
+ PP->getIdentifierTable().setExternalIdentifierLookup(this);
+ }
+ break;
+
+ case pch::IDENTIFIER_OFFSET:
+ if (!IdentifiersLoaded.empty()) {
+ Error("duplicate IDENTIFIER_OFFSET record in PCH file");
+ return Failure;
+ }
+ IdentifierOffsets = (const uint32_t *)BlobStart;
+ IdentifiersLoaded.resize(Record[0]);
+ if (PP)
+ PP->getHeaderSearchInfo().SetExternalLookup(this);
+ break;
+
+ case pch::EXTERNAL_DEFINITIONS:
+ if (!ExternalDefinitions.empty()) {
+ Error("duplicate EXTERNAL_DEFINITIONS record in PCH file");
+ return Failure;
+ }
+ ExternalDefinitions.swap(Record);
+ break;
+
+ case pch::SPECIAL_TYPES:
+ SpecialTypes.swap(Record);
+ break;
+
+ case pch::STATISTICS:
+ TotalNumStatements = Record[0];
+ TotalNumMacros = Record[1];
+ TotalLexicalDeclContexts = Record[2];
+ TotalVisibleDeclContexts = Record[3];
+ break;
+
+ case pch::TENTATIVE_DEFINITIONS:
+ if (!TentativeDefinitions.empty()) {
+ Error("duplicate TENTATIVE_DEFINITIONS record in PCH file");
+ return Failure;
+ }
+ TentativeDefinitions.swap(Record);
+ break;
+
+ case pch::UNUSED_STATIC_FUNCS:
+ if (!UnusedStaticFuncs.empty()) {
+ Error("duplicate UNUSED_STATIC_FUNCS record in PCH file");
+ return Failure;
+ }
+ UnusedStaticFuncs.swap(Record);
+ break;
+
+ case pch::LOCALLY_SCOPED_EXTERNAL_DECLS:
+ if (!LocallyScopedExternalDecls.empty()) {
+ Error("duplicate LOCALLY_SCOPED_EXTERNAL_DECLS record in PCH file");
+ return Failure;
+ }
+ LocallyScopedExternalDecls.swap(Record);
+ break;
+
+ case pch::SELECTOR_OFFSETS:
+ SelectorOffsets = (const uint32_t *)BlobStart;
+ TotalNumSelectors = Record[0];
+ SelectorsLoaded.resize(TotalNumSelectors);
+ break;
+
+ case pch::METHOD_POOL:
+ MethodPoolLookupTableData = (const unsigned char *)BlobStart;
+ if (Record[0])
+ MethodPoolLookupTable
+ = PCHMethodPoolLookupTable::Create(
+ MethodPoolLookupTableData + Record[0],
+ MethodPoolLookupTableData,
+ PCHMethodPoolLookupTrait(*this));
+ TotalSelectorsInMethodPool = Record[1];
+ break;
+
+ case pch::PP_COUNTER_VALUE:
+ if (!Record.empty() && Listener)
+ Listener->ReadCounter(Record[0]);
+ break;
+
+ case pch::SOURCE_LOCATION_OFFSETS:
+ SLocOffsets = (const uint32_t *)BlobStart;
+ TotalNumSLocEntries = Record[0];
+ SourceMgr.PreallocateSLocEntries(this, TotalNumSLocEntries, Record[1]);
+ break;
+
+ case pch::SOURCE_LOCATION_PRELOADS:
+ for (unsigned I = 0, N = Record.size(); I != N; ++I) {
+ PCHReadResult Result = ReadSLocEntryRecord(Record[I]);
+ if (Result != Success)
+ return Result;
+ }
+ break;
+
+ case pch::STAT_CACHE: {
+ PCHStatCache *MyStatCache =
+ new PCHStatCache((const unsigned char *)BlobStart + Record[0],
+ (const unsigned char *)BlobStart,
+ NumStatHits, NumStatMisses);
+ FileMgr.addStatCache(MyStatCache);
+ StatCache = MyStatCache;
+ break;
+ }
+
+ case pch::EXT_VECTOR_DECLS:
+ if (!ExtVectorDecls.empty()) {
+ Error("duplicate EXT_VECTOR_DECLS record in PCH file");
+ return Failure;
+ }
+ ExtVectorDecls.swap(Record);
+ break;
+
+ case pch::VTABLE_USES:
+ if (!VTableUses.empty()) {
+ Error("duplicate VTABLE_USES record in PCH file");
+ return Failure;
+ }
+ VTableUses.swap(Record);
+ break;
+
+ case pch::DYNAMIC_CLASSES:
+ if (!DynamicClasses.empty()) {
+ Error("duplicate DYNAMIC_CLASSES record in PCH file");
+ return Failure;
+ }
+ DynamicClasses.swap(Record);
+ break;
+
+ case pch::ORIGINAL_FILE_NAME:
+ ActualOriginalFileName.assign(BlobStart, BlobLen);
+ OriginalFileName = ActualOriginalFileName;
+ MaybeAddSystemRootToFilename(OriginalFileName);
+ break;
+
+ case pch::VERSION_CONTROL_BRANCH_REVISION: {
+ const std::string &CurBranch = getClangFullRepositoryVersion();
+ llvm::StringRef PCHBranch(BlobStart, BlobLen);
+ if (llvm::StringRef(CurBranch) != PCHBranch) {
+ Diag(diag::warn_pch_different_branch) << PCHBranch << CurBranch;
+ return IgnorePCH;
+ }
+ break;
+ }
+
+ case pch::MACRO_DEFINITION_OFFSETS:
+ MacroDefinitionOffsets = (const uint32_t *)BlobStart;
+ if (PP) {
+ if (!PP->getPreprocessingRecord())
+ PP->createPreprocessingRecord();
+ PP->getPreprocessingRecord()->SetExternalSource(*this, Record[0]);
+ } else {
+ NumPreallocatedPreprocessingEntities = Record[0];
+ }
+
+ MacroDefinitionsLoaded.resize(Record[1]);
+ break;
+ }
+ }
+ Error("premature end of bitstream in PCH file");
+ return Failure;
+}
+
+PCHReader::PCHReadResult PCHReader::ReadPCH(const std::string &FileName) {
+ // Set the PCH file name.
+ this->FileName = FileName;
+
+ // Open the PCH file.
+ //
+ // FIXME: This shouldn't be here, we should just take a raw_ostream.
+ std::string ErrStr;
+ Buffer.reset(llvm::MemoryBuffer::getFileOrSTDIN(FileName, &ErrStr));
+ if (!Buffer) {
+ Error(ErrStr.c_str());
+ return IgnorePCH;
+ }
+
+ // Initialize the stream
+ StreamFile.init((const unsigned char *)Buffer->getBufferStart(),
+ (const unsigned char *)Buffer->getBufferEnd());
+ Stream.init(StreamFile);
+
+ // Sniff for the signature.
+ if (Stream.Read(8) != 'C' ||
+ Stream.Read(8) != 'P' ||
+ Stream.Read(8) != 'C' ||
+ Stream.Read(8) != 'H') {
+ Diag(diag::err_not_a_pch_file) << FileName;
+ return Failure;
+ }
+
+ while (!Stream.AtEndOfStream()) {
+ unsigned Code = Stream.ReadCode();
+
+ if (Code != llvm::bitc::ENTER_SUBBLOCK) {
+ Error("invalid record at top-level of PCH file");
+ return Failure;
+ }
+
+ unsigned BlockID = Stream.ReadSubBlockID();
+
+ // We only know the PCH subblock ID.
+ switch (BlockID) {
+ case llvm::bitc::BLOCKINFO_BLOCK_ID:
+ if (Stream.ReadBlockInfoBlock()) {
+ Error("malformed BlockInfoBlock in PCH file");
+ return Failure;
+ }
+ break;
+ case pch::PCH_BLOCK_ID:
+ switch (ReadPCHBlock()) {
+ case Success:
+ break;
+
+ case Failure:
+ return Failure;
+
+ case IgnorePCH:
+ // FIXME: We could consider reading through to the end of this
+ // PCH block, skipping subblocks, to see if there are other
+ // PCH blocks elsewhere.
+
+ // Clear out any preallocated source location entries, so that
+ // the source manager does not try to resolve them later.
+ SourceMgr.ClearPreallocatedSLocEntries();
+
+ // Remove the stat cache.
+ if (StatCache)
+ FileMgr.removeStatCache((PCHStatCache*)StatCache);
+
+ return IgnorePCH;
+ }
+ break;
+ default:
+ if (Stream.SkipBlock()) {
+ Error("malformed block record in PCH file");
+ return Failure;
+ }
+ break;
+ }
+ }
+
+ // Check the predefines buffer.
+ if (CheckPredefinesBuffers())
+ return IgnorePCH;
+
+ if (PP) {
+ // Initialization of keywords and pragmas occurs before the
+ // PCH file is read, so there may be some identifiers that were
+ // loaded into the IdentifierTable before we intercepted the
+ // creation of identifiers. Iterate through the list of known
+ // identifiers and determine whether we have to establish
+ // preprocessor definitions or top-level identifier declaration
+ // chains for those identifiers.
+ //
+ // We copy the IdentifierInfo pointers to a small vector first,
+ // since de-serializing declarations or macro definitions can add
+ // new entries into the identifier table, invalidating the
+ // iterators.
+ llvm::SmallVector<IdentifierInfo *, 128> Identifiers;
+ for (IdentifierTable::iterator Id = PP->getIdentifierTable().begin(),
+ IdEnd = PP->getIdentifierTable().end();
+ Id != IdEnd; ++Id)
+ Identifiers.push_back(Id->second);
+ PCHIdentifierLookupTable *IdTable
+ = (PCHIdentifierLookupTable *)IdentifierLookupTable;
+ for (unsigned I = 0, N = Identifiers.size(); I != N; ++I) {
+ IdentifierInfo *II = Identifiers[I];
+ // Look in the on-disk hash table for an entry for
+ PCHIdentifierLookupTrait Info(*this, II);
+ std::pair<const char*, unsigned> Key(II->getNameStart(), II->getLength());
+ PCHIdentifierLookupTable::iterator Pos = IdTable->find(Key, &Info);
+ if (Pos == IdTable->end())
+ continue;
+
+ // Dereferencing the iterator has the effect of populating the
+ // IdentifierInfo node with the various declarations it needs.
+ (void)*Pos;
+ }
+ }
+
+ if (Context)
+ InitializeContext(*Context);
+
+ return Success;
+}
+
+void PCHReader::setPreprocessor(Preprocessor &pp) {
+ PP = &pp;
+
+ if (NumPreallocatedPreprocessingEntities) {
+ if (!PP->getPreprocessingRecord())
+ PP->createPreprocessingRecord();
+ PP->getPreprocessingRecord()->SetExternalSource(*this,
+ NumPreallocatedPreprocessingEntities);
+ NumPreallocatedPreprocessingEntities = 0;
+ }
+}
+
+void PCHReader::InitializeContext(ASTContext &Ctx) {
+ Context = &Ctx;
+ assert(Context && "Passed null context!");
+
+ assert(PP && "Forgot to set Preprocessor ?");
+ PP->getIdentifierTable().setExternalIdentifierLookup(this);
+ PP->getHeaderSearchInfo().SetExternalLookup(this);
+ PP->setExternalSource(this);
+
+ // Load the translation unit declaration
+ GetTranslationUnitDecl();
+
+ // Load the special types.
+ Context->setBuiltinVaListType(
+ GetType(SpecialTypes[pch::SPECIAL_TYPE_BUILTIN_VA_LIST]));
+ if (unsigned Id = SpecialTypes[pch::SPECIAL_TYPE_OBJC_ID])
+ Context->setObjCIdType(GetType(Id));
+ if (unsigned Sel = SpecialTypes[pch::SPECIAL_TYPE_OBJC_SELECTOR])
+ Context->setObjCSelType(GetType(Sel));
+ if (unsigned Proto = SpecialTypes[pch::SPECIAL_TYPE_OBJC_PROTOCOL])
+ Context->setObjCProtoType(GetType(Proto));
+ if (unsigned Class = SpecialTypes[pch::SPECIAL_TYPE_OBJC_CLASS])
+ Context->setObjCClassType(GetType(Class));
+
+ if (unsigned String = SpecialTypes[pch::SPECIAL_TYPE_CF_CONSTANT_STRING])
+ Context->setCFConstantStringType(GetType(String));
+ if (unsigned FastEnum
+ = SpecialTypes[pch::SPECIAL_TYPE_OBJC_FAST_ENUMERATION_STATE])
+ Context->setObjCFastEnumerationStateType(GetType(FastEnum));
+ if (unsigned File = SpecialTypes[pch::SPECIAL_TYPE_FILE]) {
+ QualType FileType = GetType(File);
+ if (FileType.isNull()) {
+ Error("FILE type is NULL");
+ return;
+ }
+ if (const TypedefType *Typedef = FileType->getAs<TypedefType>())
+ Context->setFILEDecl(Typedef->getDecl());
+ else {
+ const TagType *Tag = FileType->getAs<TagType>();
+ if (!Tag) {
+ Error("Invalid FILE type in PCH file");
+ return;
+ }
+ Context->setFILEDecl(Tag->getDecl());
+ }
+ }
+ if (unsigned Jmp_buf = SpecialTypes[pch::SPECIAL_TYPE_jmp_buf]) {
+ QualType Jmp_bufType = GetType(Jmp_buf);
+ if (Jmp_bufType.isNull()) {
+ Error("jmp_bug type is NULL");
+ return;
+ }
+ if (const TypedefType *Typedef = Jmp_bufType->getAs<TypedefType>())
+ Context->setjmp_bufDecl(Typedef->getDecl());
+ else {
+ const TagType *Tag = Jmp_bufType->getAs<TagType>();
+ if (!Tag) {
+ Error("Invalid jmp_bug type in PCH file");
+ return;
+ }
+ Context->setjmp_bufDecl(Tag->getDecl());
+ }
+ }
+ if (unsigned Sigjmp_buf = SpecialTypes[pch::SPECIAL_TYPE_sigjmp_buf]) {
+ QualType Sigjmp_bufType = GetType(Sigjmp_buf);
+ if (Sigjmp_bufType.isNull()) {
+ Error("sigjmp_buf type is NULL");
+ return;
+ }
+ if (const TypedefType *Typedef = Sigjmp_bufType->getAs<TypedefType>())
+ Context->setsigjmp_bufDecl(Typedef->getDecl());
+ else {
+ const TagType *Tag = Sigjmp_bufType->getAs<TagType>();
+ assert(Tag && "Invalid sigjmp_buf type in PCH file");
+ Context->setsigjmp_bufDecl(Tag->getDecl());
+ }
+ }
+ if (unsigned ObjCIdRedef
+ = SpecialTypes[pch::SPECIAL_TYPE_OBJC_ID_REDEFINITION])
+ Context->ObjCIdRedefinitionType = GetType(ObjCIdRedef);
+ if (unsigned ObjCClassRedef
+ = SpecialTypes[pch::SPECIAL_TYPE_OBJC_CLASS_REDEFINITION])
+ Context->ObjCClassRedefinitionType = GetType(ObjCClassRedef);
+ if (unsigned String = SpecialTypes[pch::SPECIAL_TYPE_BLOCK_DESCRIPTOR])
+ Context->setBlockDescriptorType(GetType(String));
+ if (unsigned String
+ = SpecialTypes[pch::SPECIAL_TYPE_BLOCK_EXTENDED_DESCRIPTOR])
+ Context->setBlockDescriptorExtendedType(GetType(String));
+ if (unsigned ObjCSelRedef
+ = SpecialTypes[pch::SPECIAL_TYPE_OBJC_SEL_REDEFINITION])
+ Context->ObjCSelRedefinitionType = GetType(ObjCSelRedef);
+ if (unsigned String = SpecialTypes[pch::SPECIAL_TYPE_NS_CONSTANT_STRING])
+ Context->setNSConstantStringType(GetType(String));
+
+ if (SpecialTypes[pch::SPECIAL_TYPE_INT128_INSTALLED])
+ Context->setInt128Installed();
+}
+
+/// \brief Retrieve the name of the original source file name
+/// directly from the PCH file, without actually loading the PCH
+/// file.
+std::string PCHReader::getOriginalSourceFile(const std::string &PCHFileName,
+ Diagnostic &Diags) {
+ // Open the PCH file.
+ std::string ErrStr;
+ llvm::OwningPtr<llvm::MemoryBuffer> Buffer;
+ Buffer.reset(llvm::MemoryBuffer::getFile(PCHFileName.c_str(), &ErrStr));
+ if (!Buffer) {
+ Diags.Report(diag::err_fe_unable_to_read_pch_file) << ErrStr;
+ return std::string();
+ }
+
+ // Initialize the stream
+ llvm::BitstreamReader StreamFile;
+ llvm::BitstreamCursor Stream;
+ StreamFile.init((const unsigned char *)Buffer->getBufferStart(),
+ (const unsigned char *)Buffer->getBufferEnd());
+ Stream.init(StreamFile);
+
+ // Sniff for the signature.
+ if (Stream.Read(8) != 'C' ||
+ Stream.Read(8) != 'P' ||
+ Stream.Read(8) != 'C' ||
+ Stream.Read(8) != 'H') {
+ Diags.Report(diag::err_fe_not_a_pch_file) << PCHFileName;
+ return std::string();
+ }
+
+ RecordData Record;
+ while (!Stream.AtEndOfStream()) {
+ unsigned Code = Stream.ReadCode();
+
+ if (Code == llvm::bitc::ENTER_SUBBLOCK) {
+ unsigned BlockID = Stream.ReadSubBlockID();
+
+ // We only know the PCH subblock ID.
+ switch (BlockID) {
+ case pch::PCH_BLOCK_ID:
+ if (Stream.EnterSubBlock(pch::PCH_BLOCK_ID)) {
+ Diags.Report(diag::err_fe_pch_malformed_block) << PCHFileName;
+ return std::string();
+ }
+ break;
+
+ default:
+ if (Stream.SkipBlock()) {
+ Diags.Report(diag::err_fe_pch_malformed_block) << PCHFileName;
+ return std::string();
+ }
+ break;
+ }
+ continue;
+ }
+
+ if (Code == llvm::bitc::END_BLOCK) {
+ if (Stream.ReadBlockEnd()) {
+ Diags.Report(diag::err_fe_pch_error_at_end_block) << PCHFileName;
+ return std::string();
+ }
+ continue;
+ }
+
+ if (Code == llvm::bitc::DEFINE_ABBREV) {
+ Stream.ReadAbbrevRecord();
+ continue;
+ }
+
+ Record.clear();
+ const char *BlobStart = 0;
+ unsigned BlobLen = 0;
+ if (Stream.ReadRecord(Code, Record, &BlobStart, &BlobLen)
+ == pch::ORIGINAL_FILE_NAME)
+ return std::string(BlobStart, BlobLen);
+ }
+
+ return std::string();
+}
+
+/// \brief Parse the record that corresponds to a LangOptions data
+/// structure.
+///
+/// This routine compares the language options used to generate the
+/// PCH file against the language options set for the current
+/// compilation. For each option, we classify differences between the
+/// two compiler states as either "benign" or "important". Benign
+/// differences don't matter, and we accept them without complaint
+/// (and without modifying the language options). Differences between
+/// the states for important options cause the PCH file to be
+/// unusable, so we emit a warning and return true to indicate that
+/// there was an error.
+///
+/// \returns true if the PCH file is unacceptable, false otherwise.
+bool PCHReader::ParseLanguageOptions(
+ const llvm::SmallVectorImpl<uint64_t> &Record) {
+ if (Listener) {
+ LangOptions LangOpts;
+
+ #define PARSE_LANGOPT(Option) \
+ LangOpts.Option = Record[Idx]; \
+ ++Idx
+
+ unsigned Idx = 0;
+ PARSE_LANGOPT(Trigraphs);
+ PARSE_LANGOPT(BCPLComment);
+ PARSE_LANGOPT(DollarIdents);
+ PARSE_LANGOPT(AsmPreprocessor);
+ PARSE_LANGOPT(GNUMode);
+ PARSE_LANGOPT(GNUKeywords);
+ PARSE_LANGOPT(ImplicitInt);
+ PARSE_LANGOPT(Digraphs);
+ PARSE_LANGOPT(HexFloats);
+ PARSE_LANGOPT(C99);
+ PARSE_LANGOPT(Microsoft);
+ PARSE_LANGOPT(CPlusPlus);
+ PARSE_LANGOPT(CPlusPlus0x);
+ PARSE_LANGOPT(CXXOperatorNames);
+ PARSE_LANGOPT(ObjC1);
+ PARSE_LANGOPT(ObjC2);
+ PARSE_LANGOPT(ObjCNonFragileABI);
+ PARSE_LANGOPT(ObjCNonFragileABI2);
+ PARSE_LANGOPT(NoConstantCFStrings);
+ PARSE_LANGOPT(PascalStrings);
+ PARSE_LANGOPT(WritableStrings);
+ PARSE_LANGOPT(LaxVectorConversions);
+ PARSE_LANGOPT(AltiVec);
+ PARSE_LANGOPT(Exceptions);
+ PARSE_LANGOPT(SjLjExceptions);
+ PARSE_LANGOPT(NeXTRuntime);
+ PARSE_LANGOPT(Freestanding);
+ PARSE_LANGOPT(NoBuiltin);
+ PARSE_LANGOPT(ThreadsafeStatics);
+ PARSE_LANGOPT(POSIXThreads);
+ PARSE_LANGOPT(Blocks);
+ PARSE_LANGOPT(EmitAllDecls);
+ PARSE_LANGOPT(MathErrno);
+ LangOpts.setSignedOverflowBehavior((LangOptions::SignedOverflowBehaviorTy)
+ Record[Idx++]);
+ PARSE_LANGOPT(HeinousExtensions);
+ PARSE_LANGOPT(Optimize);
+ PARSE_LANGOPT(OptimizeSize);
+ PARSE_LANGOPT(Static);
+ PARSE_LANGOPT(PICLevel);
+ PARSE_LANGOPT(GNUInline);
+ PARSE_LANGOPT(NoInline);
+ PARSE_LANGOPT(AccessControl);
+ PARSE_LANGOPT(CharIsSigned);
+ PARSE_LANGOPT(ShortWChar);
+ LangOpts.setGCMode((LangOptions::GCMode)Record[Idx++]);
+ LangOpts.setVisibilityMode((LangOptions::VisibilityMode)Record[Idx++]);
+ LangOpts.setStackProtectorMode((LangOptions::StackProtectorMode)
+ Record[Idx++]);
+ PARSE_LANGOPT(InstantiationDepth);
+ PARSE_LANGOPT(OpenCL);
+ PARSE_LANGOPT(CatchUndefined);
+ // FIXME: Missing ElideConstructors?!
+ #undef PARSE_LANGOPT
+
+ return Listener->ReadLanguageOptions(LangOpts);
+ }
+
+ return false;
+}
+
+void PCHReader::ReadPreprocessedEntities() {
+ ReadDefinedMacros();
+}
+
+/// \brief Read and return the type at the given offset.
+///
+/// This routine actually reads the record corresponding to the type
+/// at the given offset in the bitstream. It is a helper routine for
+/// GetType, which deals with reading type IDs.
+QualType PCHReader::ReadTypeRecord(uint64_t Offset) {
+ // Keep track of where we are in the stream, then jump back there
+ // after reading this type.
+ SavedStreamPosition SavedPosition(DeclsCursor);
+
+ ReadingKindTracker ReadingKind(Read_Type, *this);
+
+ // Note that we are loading a type record.
+ LoadingTypeOrDecl Loading(*this);
+
+ DeclsCursor.JumpToBit(Offset);
+ RecordData Record;
+ unsigned Code = DeclsCursor.ReadCode();
+ switch ((pch::TypeCode)DeclsCursor.ReadRecord(Code, Record)) {
+ case pch::TYPE_EXT_QUAL: {
+ if (Record.size() != 2) {
+ Error("Incorrect encoding of extended qualifier type");
+ return QualType();
+ }
+ QualType Base = GetType(Record[0]);
+ Qualifiers Quals = Qualifiers::fromOpaqueValue(Record[1]);
+ return Context->getQualifiedType(Base, Quals);
+ }
+
+ case pch::TYPE_COMPLEX: {
+ if (Record.size() != 1) {
+ Error("Incorrect encoding of complex type");
+ return QualType();
+ }
+ QualType ElemType = GetType(Record[0]);
+ return Context->getComplexType(ElemType);
+ }
+
+ case pch::TYPE_POINTER: {
+ if (Record.size() != 1) {
+ Error("Incorrect encoding of pointer type");
+ return QualType();
+ }
+ QualType PointeeType = GetType(Record[0]);
+ return Context->getPointerType(PointeeType);
+ }
+
+ case pch::TYPE_BLOCK_POINTER: {
+ if (Record.size() != 1) {
+ Error("Incorrect encoding of block pointer type");
+ return QualType();
+ }
+ QualType PointeeType = GetType(Record[0]);
+ return Context->getBlockPointerType(PointeeType);
+ }
+
+ case pch::TYPE_LVALUE_REFERENCE: {
+ if (Record.size() != 1) {
+ Error("Incorrect encoding of lvalue reference type");
+ return QualType();
+ }
+ QualType PointeeType = GetType(Record[0]);
+ return Context->getLValueReferenceType(PointeeType);
+ }
+
+ case pch::TYPE_RVALUE_REFERENCE: {
+ if (Record.size() != 1) {
+ Error("Incorrect encoding of rvalue reference type");
+ return QualType();
+ }
+ QualType PointeeType = GetType(Record[0]);
+ return Context->getRValueReferenceType(PointeeType);
+ }
+
+ case pch::TYPE_MEMBER_POINTER: {
+ if (Record.size() != 2) {
+ Error("Incorrect encoding of member pointer type");
+ return QualType();
+ }
+ QualType PointeeType = GetType(Record[0]);
+ QualType ClassType = GetType(Record[1]);
+ return Context->getMemberPointerType(PointeeType, ClassType.getTypePtr());
+ }
+
+ case pch::TYPE_CONSTANT_ARRAY: {
+ QualType ElementType = GetType(Record[0]);
+ ArrayType::ArraySizeModifier ASM = (ArrayType::ArraySizeModifier)Record[1];
+ unsigned IndexTypeQuals = Record[2];
+ unsigned Idx = 3;
+ llvm::APInt Size = ReadAPInt(Record, Idx);
+ return Context->getConstantArrayType(ElementType, Size,
+ ASM, IndexTypeQuals);
+ }
+
+ case pch::TYPE_INCOMPLETE_ARRAY: {
+ QualType ElementType = GetType(Record[0]);
+ ArrayType::ArraySizeModifier ASM = (ArrayType::ArraySizeModifier)Record[1];
+ unsigned IndexTypeQuals = Record[2];
+ return Context->getIncompleteArrayType(ElementType, ASM, IndexTypeQuals);
+ }
+
+ case pch::TYPE_VARIABLE_ARRAY: {
+ QualType ElementType = GetType(Record[0]);
+ ArrayType::ArraySizeModifier ASM = (ArrayType::ArraySizeModifier)Record[1];
+ unsigned IndexTypeQuals = Record[2];
+ SourceLocation LBLoc = SourceLocation::getFromRawEncoding(Record[3]);
+ SourceLocation RBLoc = SourceLocation::getFromRawEncoding(Record[4]);
+ return Context->getVariableArrayType(ElementType, ReadExpr(),
+ ASM, IndexTypeQuals,
+ SourceRange(LBLoc, RBLoc));
+ }
+
+ case pch::TYPE_VECTOR: {
+ if (Record.size() != 3) {
+ Error("incorrect encoding of vector type in PCH file");
+ return QualType();
+ }
+
+ QualType ElementType = GetType(Record[0]);
+ unsigned NumElements = Record[1];
+ unsigned AltiVecSpec = Record[2];
+ return Context->getVectorType(ElementType, NumElements,
+ (VectorType::AltiVecSpecific)AltiVecSpec);
+ }
+
+ case pch::TYPE_EXT_VECTOR: {
+ if (Record.size() != 3) {
+ Error("incorrect encoding of extended vector type in PCH file");
+ return QualType();
+ }
+
+ QualType ElementType = GetType(Record[0]);
+ unsigned NumElements = Record[1];
+ return Context->getExtVectorType(ElementType, NumElements);
+ }
+
+ case pch::TYPE_FUNCTION_NO_PROTO: {
+ if (Record.size() != 4) {
+ Error("incorrect encoding of no-proto function type");
+ return QualType();
+ }
+ QualType ResultType = GetType(Record[0]);
+ FunctionType::ExtInfo Info(Record[1], Record[2], (CallingConv)Record[3]);
+ return Context->getFunctionNoProtoType(ResultType, Info);
+ }
+
+ case pch::TYPE_FUNCTION_PROTO: {
+ QualType ResultType = GetType(Record[0]);
+ bool NoReturn = Record[1];
+ unsigned RegParm = Record[2];
+ CallingConv CallConv = (CallingConv)Record[3];
+ unsigned Idx = 4;
+ unsigned NumParams = Record[Idx++];
+ llvm::SmallVector<QualType, 16> ParamTypes;
+ for (unsigned I = 0; I != NumParams; ++I)
+ ParamTypes.push_back(GetType(Record[Idx++]));
+ bool isVariadic = Record[Idx++];
+ unsigned Quals = Record[Idx++];
+ bool hasExceptionSpec = Record[Idx++];
+ bool hasAnyExceptionSpec = Record[Idx++];
+ unsigned NumExceptions = Record[Idx++];
+ llvm::SmallVector<QualType, 2> Exceptions;
+ for (unsigned I = 0; I != NumExceptions; ++I)
+ Exceptions.push_back(GetType(Record[Idx++]));
+ return Context->getFunctionType(ResultType, ParamTypes.data(), NumParams,
+ isVariadic, Quals, hasExceptionSpec,
+ hasAnyExceptionSpec, NumExceptions,
+ Exceptions.data(),
+ FunctionType::ExtInfo(NoReturn, RegParm,
+ CallConv));
+ }
+
+ case pch::TYPE_UNRESOLVED_USING:
+ return Context->getTypeDeclType(
+ cast<UnresolvedUsingTypenameDecl>(GetDecl(Record[0])));
+
+ case pch::TYPE_TYPEDEF: {
+ if (Record.size() != 2) {
+ Error("incorrect encoding of typedef type");
+ return QualType();
+ }
+ TypedefDecl *Decl = cast<TypedefDecl>(GetDecl(Record[0]));
+ QualType Canonical = GetType(Record[1]);
+ return Context->getTypedefType(Decl, Canonical);
+ }
+
+ case pch::TYPE_TYPEOF_EXPR:
+ return Context->getTypeOfExprType(ReadExpr());
+
+ case pch::TYPE_TYPEOF: {
+ if (Record.size() != 1) {
+ Error("incorrect encoding of typeof(type) in PCH file");
+ return QualType();
+ }
+ QualType UnderlyingType = GetType(Record[0]);
+ return Context->getTypeOfType(UnderlyingType);
+ }
+
+ case pch::TYPE_DECLTYPE:
+ return Context->getDecltypeType(ReadExpr());
+
+ case pch::TYPE_RECORD: {
+ if (Record.size() != 2) {
+ Error("incorrect encoding of record type");
+ return QualType();
+ }
+ bool IsDependent = Record[0];
+ QualType T = Context->getRecordType(cast<RecordDecl>(GetDecl(Record[1])));
+ T->Dependent = IsDependent;
+ return T;
+ }
+
+ case pch::TYPE_ENUM: {
+ if (Record.size() != 2) {
+ Error("incorrect encoding of enum type");
+ return QualType();
+ }
+ bool IsDependent = Record[0];
+ QualType T = Context->getEnumType(cast<EnumDecl>(GetDecl(Record[1])));
+ T->Dependent = IsDependent;
+ return T;
+ }
+
+ case pch::TYPE_ELABORATED: {
+ unsigned Idx = 0;
+ ElaboratedTypeKeyword Keyword = (ElaboratedTypeKeyword)Record[Idx++];
+ NestedNameSpecifier *NNS = ReadNestedNameSpecifier(Record, Idx);
+ QualType NamedType = GetType(Record[Idx++]);
+ return Context->getElaboratedType(Keyword, NNS, NamedType);
+ }
+
+ case pch::TYPE_OBJC_INTERFACE: {
+ unsigned Idx = 0;
+ ObjCInterfaceDecl *ItfD = cast<ObjCInterfaceDecl>(GetDecl(Record[Idx++]));
+ return Context->getObjCInterfaceType(ItfD);
+ }
+
+ case pch::TYPE_OBJC_OBJECT: {
+ unsigned Idx = 0;
+ QualType Base = GetType(Record[Idx++]);
+ unsigned NumProtos = Record[Idx++];
+ llvm::SmallVector<ObjCProtocolDecl*, 4> Protos;
+ for (unsigned I = 0; I != NumProtos; ++I)
+ Protos.push_back(cast<ObjCProtocolDecl>(GetDecl(Record[Idx++])));
+ return Context->getObjCObjectType(Base, Protos.data(), NumProtos);
+ }
+
+ case pch::TYPE_OBJC_OBJECT_POINTER: {
+ unsigned Idx = 0;
+ QualType Pointee = GetType(Record[Idx++]);
+ return Context->getObjCObjectPointerType(Pointee);
+ }
+
+ case pch::TYPE_SUBST_TEMPLATE_TYPE_PARM: {
+ unsigned Idx = 0;
+ QualType Parm = GetType(Record[Idx++]);
+ QualType Replacement = GetType(Record[Idx++]);
+ return
+ Context->getSubstTemplateTypeParmType(cast<TemplateTypeParmType>(Parm),
+ Replacement);
+ }
+
+ case pch::TYPE_INJECTED_CLASS_NAME: {
+ CXXRecordDecl *D = cast<CXXRecordDecl>(GetDecl(Record[0]));
+ QualType TST = GetType(Record[1]); // probably derivable
+ // FIXME: ASTContext::getInjectedClassNameType is not currently suitable
+ // for PCH reading, too much interdependencies.
+ return
+ QualType(new (*Context, TypeAlignment) InjectedClassNameType(D, TST), 0);
+ }
+
+ case pch::TYPE_TEMPLATE_TYPE_PARM: {
+ unsigned Idx = 0;
+ unsigned Depth = Record[Idx++];
+ unsigned Index = Record[Idx++];
+ bool Pack = Record[Idx++];
+ IdentifierInfo *Name = GetIdentifierInfo(Record, Idx);
+ return Context->getTemplateTypeParmType(Depth, Index, Pack, Name);
+ }
+
+ case pch::TYPE_DEPENDENT_NAME: {
+ unsigned Idx = 0;
+ ElaboratedTypeKeyword Keyword = (ElaboratedTypeKeyword)Record[Idx++];
+ NestedNameSpecifier *NNS = ReadNestedNameSpecifier(Record, Idx);
+ const IdentifierInfo *Name = this->GetIdentifierInfo(Record, Idx);
+ QualType Canon = GetType(Record[Idx++]);
+ return Context->getDependentNameType(Keyword, NNS, Name, Canon);
+ }
+
+ case pch::TYPE_DEPENDENT_TEMPLATE_SPECIALIZATION: {
+ unsigned Idx = 0;
+ ElaboratedTypeKeyword Keyword = (ElaboratedTypeKeyword)Record[Idx++];
+ NestedNameSpecifier *NNS = ReadNestedNameSpecifier(Record, Idx);
+ const IdentifierInfo *Name = this->GetIdentifierInfo(Record, Idx);
+ unsigned NumArgs = Record[Idx++];
+ llvm::SmallVector<TemplateArgument, 8> Args;
+ Args.reserve(NumArgs);
+ while (NumArgs--)
+ Args.push_back(ReadTemplateArgument(Record, Idx));
+ return Context->getDependentTemplateSpecializationType(Keyword, NNS, Name,
+ Args.size(), Args.data());
+ }
+
+ case pch::TYPE_DEPENDENT_SIZED_ARRAY: {
+ unsigned Idx = 0;
+
+ // ArrayType
+ QualType ElementType = GetType(Record[Idx++]);
+ ArrayType::ArraySizeModifier ASM
+ = (ArrayType::ArraySizeModifier)Record[Idx++];
+ unsigned IndexTypeQuals = Record[Idx++];
+
+ // DependentSizedArrayType
+ Expr *NumElts = ReadExpr();
+ SourceRange Brackets = ReadSourceRange(Record, Idx);
+
+ return Context->getDependentSizedArrayType(ElementType, NumElts, ASM,
+ IndexTypeQuals, Brackets);
+ }
+
+ case pch::TYPE_TEMPLATE_SPECIALIZATION: {
+ unsigned Idx = 0;
+ bool IsDependent = Record[Idx++];
+ TemplateName Name = ReadTemplateName(Record, Idx);
+ llvm::SmallVector<TemplateArgument, 8> Args;
+ ReadTemplateArgumentList(Args, Record, Idx);
+ QualType Canon = GetType(Record[Idx++]);
+ QualType T;
+ if (Canon.isNull())
+ T = Context->getCanonicalTemplateSpecializationType(Name, Args.data(),
+ Args.size());
+ else
+ T = Context->getTemplateSpecializationType(Name, Args.data(),
+ Args.size(), Canon);
+ T->Dependent = IsDependent;
+ return T;
+ }
+ }
+ // Suppress a GCC warning
+ return QualType();
+}
+
+namespace {
+
+class TypeLocReader : public TypeLocVisitor<TypeLocReader> {
+ PCHReader &Reader;
+ const PCHReader::RecordData &Record;
+ unsigned &Idx;
+
+public:
+ TypeLocReader(PCHReader &Reader, const PCHReader::RecordData &Record,
+ unsigned &Idx)
+ : Reader(Reader), Record(Record), Idx(Idx) { }
+
+ // We want compile-time assurance that we've enumerated all of
+ // these, so unfortunately we have to declare them first, then
+ // define them out-of-line.
+#define ABSTRACT_TYPELOC(CLASS, PARENT)
+#define TYPELOC(CLASS, PARENT) \
+ void Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc);
+#include "clang/AST/TypeLocNodes.def"
+
+ void VisitFunctionTypeLoc(FunctionTypeLoc);
+ void VisitArrayTypeLoc(ArrayTypeLoc);
+};
+
+}
+
+void TypeLocReader::VisitQualifiedTypeLoc(QualifiedTypeLoc TL) {
+ // nothing to do
+}
+void TypeLocReader::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) {
+ TL.setBuiltinLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ if (TL.needsExtraLocalData()) {
+ TL.setWrittenTypeSpec(static_cast<DeclSpec::TST>(Record[Idx++]));
+ TL.setWrittenSignSpec(static_cast<DeclSpec::TSS>(Record[Idx++]));
+ TL.setWrittenWidthSpec(static_cast<DeclSpec::TSW>(Record[Idx++]));
+ TL.setModeAttr(Record[Idx++]);
+ }
+}
+void TypeLocReader::VisitComplexTypeLoc(ComplexTypeLoc TL) {
+ TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+void TypeLocReader::VisitPointerTypeLoc(PointerTypeLoc TL) {
+ TL.setStarLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+void TypeLocReader::VisitBlockPointerTypeLoc(BlockPointerTypeLoc TL) {
+ TL.setCaretLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+void TypeLocReader::VisitLValueReferenceTypeLoc(LValueReferenceTypeLoc TL) {
+ TL.setAmpLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+void TypeLocReader::VisitRValueReferenceTypeLoc(RValueReferenceTypeLoc TL) {
+ TL.setAmpAmpLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+void TypeLocReader::VisitMemberPointerTypeLoc(MemberPointerTypeLoc TL) {
+ TL.setStarLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+void TypeLocReader::VisitArrayTypeLoc(ArrayTypeLoc TL) {
+ TL.setLBracketLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ TL.setRBracketLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ if (Record[Idx++])
+ TL.setSizeExpr(Reader.ReadExpr());
+ else
+ TL.setSizeExpr(0);
+}
+void TypeLocReader::VisitConstantArrayTypeLoc(ConstantArrayTypeLoc TL) {
+ VisitArrayTypeLoc(TL);
+}
+void TypeLocReader::VisitIncompleteArrayTypeLoc(IncompleteArrayTypeLoc TL) {
+ VisitArrayTypeLoc(TL);
+}
+void TypeLocReader::VisitVariableArrayTypeLoc(VariableArrayTypeLoc TL) {
+ VisitArrayTypeLoc(TL);
+}
+void TypeLocReader::VisitDependentSizedArrayTypeLoc(
+ DependentSizedArrayTypeLoc TL) {
+ VisitArrayTypeLoc(TL);
+}
+void TypeLocReader::VisitDependentSizedExtVectorTypeLoc(
+ DependentSizedExtVectorTypeLoc TL) {
+ TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+void TypeLocReader::VisitVectorTypeLoc(VectorTypeLoc TL) {
+ TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+void TypeLocReader::VisitExtVectorTypeLoc(ExtVectorTypeLoc TL) {
+ TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+void TypeLocReader::VisitFunctionTypeLoc(FunctionTypeLoc TL) {
+ TL.setLParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ TL.setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) {
+ TL.setArg(i, cast_or_null<ParmVarDecl>(Reader.GetDecl(Record[Idx++])));
+ }
+}
+void TypeLocReader::VisitFunctionProtoTypeLoc(FunctionProtoTypeLoc TL) {
+ VisitFunctionTypeLoc(TL);
+}
+void TypeLocReader::VisitFunctionNoProtoTypeLoc(FunctionNoProtoTypeLoc TL) {
+ VisitFunctionTypeLoc(TL);
+}
+void TypeLocReader::VisitUnresolvedUsingTypeLoc(UnresolvedUsingTypeLoc TL) {
+ TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+void TypeLocReader::VisitTypedefTypeLoc(TypedefTypeLoc TL) {
+ TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+void TypeLocReader::VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL) {
+ TL.setTypeofLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ TL.setLParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ TL.setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+void TypeLocReader::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) {
+ TL.setTypeofLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ TL.setLParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ TL.setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ TL.setUnderlyingTInfo(Reader.GetTypeSourceInfo(Record, Idx));
+}
+void TypeLocReader::VisitDecltypeTypeLoc(DecltypeTypeLoc TL) {
+ TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+void TypeLocReader::VisitRecordTypeLoc(RecordTypeLoc TL) {
+ TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+void TypeLocReader::VisitEnumTypeLoc(EnumTypeLoc TL) {
+ TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+void TypeLocReader::VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) {
+ TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+void TypeLocReader::VisitSubstTemplateTypeParmTypeLoc(
+ SubstTemplateTypeParmTypeLoc TL) {
+ TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+void TypeLocReader::VisitTemplateSpecializationTypeLoc(
+ TemplateSpecializationTypeLoc TL) {
+ TL.setTemplateNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ TL.setLAngleLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ TL.setRAngleLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i)
+ TL.setArgLocInfo(i,
+ Reader.GetTemplateArgumentLocInfo(TL.getTypePtr()->getArg(i).getKind(),
+ Record, Idx));
+}
+void TypeLocReader::VisitElaboratedTypeLoc(ElaboratedTypeLoc TL) {
+ TL.setKeywordLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ TL.setQualifierRange(Reader.ReadSourceRange(Record, Idx));
+}
+void TypeLocReader::VisitInjectedClassNameTypeLoc(InjectedClassNameTypeLoc TL) {
+ TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+void TypeLocReader::VisitDependentNameTypeLoc(DependentNameTypeLoc TL) {
+ TL.setKeywordLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ TL.setQualifierRange(Reader.ReadSourceRange(Record, Idx));
+ TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+void TypeLocReader::VisitDependentTemplateSpecializationTypeLoc(
+ DependentTemplateSpecializationTypeLoc TL) {
+ TL.setKeywordLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ TL.setQualifierRange(Reader.ReadSourceRange(Record, Idx));
+ TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ TL.setLAngleLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ TL.setRAngleLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I)
+ TL.setArgLocInfo(I,
+ Reader.GetTemplateArgumentLocInfo(TL.getTypePtr()->getArg(I).getKind(),
+ Record, Idx));
+}
+void TypeLocReader::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) {
+ TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+void TypeLocReader::VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) {
+ TL.setHasBaseTypeAsWritten(Record[Idx++]);
+ TL.setLAngleLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ TL.setRAngleLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i)
+ TL.setProtocolLoc(i, SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+void TypeLocReader::VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) {
+ TL.setStarLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+
+TypeSourceInfo *PCHReader::GetTypeSourceInfo(const RecordData &Record,
+ unsigned &Idx) {
+ QualType InfoTy = GetType(Record[Idx++]);
+ if (InfoTy.isNull())
+ return 0;
+
+ TypeSourceInfo *TInfo = getContext()->CreateTypeSourceInfo(InfoTy);
+ TypeLocReader TLR(*this, Record, Idx);
+ for (TypeLoc TL = TInfo->getTypeLoc(); !TL.isNull(); TL = TL.getNextTypeLoc())
+ TLR.Visit(TL);
+ return TInfo;
+}
+
+QualType PCHReader::GetType(pch::TypeID ID) {
+ unsigned FastQuals = ID & Qualifiers::FastMask;
+ unsigned Index = ID >> Qualifiers::FastWidth;
+
+ if (Index < pch::NUM_PREDEF_TYPE_IDS) {
+ QualType T;
+ switch ((pch::PredefinedTypeIDs)Index) {
+ case pch::PREDEF_TYPE_NULL_ID: return QualType();
+ case pch::PREDEF_TYPE_VOID_ID: T = Context->VoidTy; break;
+ case pch::PREDEF_TYPE_BOOL_ID: T = Context->BoolTy; break;
+
+ case pch::PREDEF_TYPE_CHAR_U_ID:
+ case pch::PREDEF_TYPE_CHAR_S_ID:
+ // FIXME: Check that the signedness of CharTy is correct!
+ T = Context->CharTy;
+ break;
+
+ case pch::PREDEF_TYPE_UCHAR_ID: T = Context->UnsignedCharTy; break;
+ case pch::PREDEF_TYPE_USHORT_ID: T = Context->UnsignedShortTy; break;
+ case pch::PREDEF_TYPE_UINT_ID: T = Context->UnsignedIntTy; break;
+ case pch::PREDEF_TYPE_ULONG_ID: T = Context->UnsignedLongTy; break;
+ case pch::PREDEF_TYPE_ULONGLONG_ID: T = Context->UnsignedLongLongTy; break;
+ case pch::PREDEF_TYPE_UINT128_ID: T = Context->UnsignedInt128Ty; break;
+ case pch::PREDEF_TYPE_SCHAR_ID: T = Context->SignedCharTy; break;
+ case pch::PREDEF_TYPE_WCHAR_ID: T = Context->WCharTy; break;
+ case pch::PREDEF_TYPE_SHORT_ID: T = Context->ShortTy; break;
+ case pch::PREDEF_TYPE_INT_ID: T = Context->IntTy; break;
+ case pch::PREDEF_TYPE_LONG_ID: T = Context->LongTy; break;
+ case pch::PREDEF_TYPE_LONGLONG_ID: T = Context->LongLongTy; break;
+ case pch::PREDEF_TYPE_INT128_ID: T = Context->Int128Ty; break;
+ case pch::PREDEF_TYPE_FLOAT_ID: T = Context->FloatTy; break;
+ case pch::PREDEF_TYPE_DOUBLE_ID: T = Context->DoubleTy; break;
+ case pch::PREDEF_TYPE_LONGDOUBLE_ID: T = Context->LongDoubleTy; break;
+ case pch::PREDEF_TYPE_OVERLOAD_ID: T = Context->OverloadTy; break;
+ case pch::PREDEF_TYPE_DEPENDENT_ID: T = Context->DependentTy; break;
+ case pch::PREDEF_TYPE_NULLPTR_ID: T = Context->NullPtrTy; break;
+ case pch::PREDEF_TYPE_CHAR16_ID: T = Context->Char16Ty; break;
+ case pch::PREDEF_TYPE_CHAR32_ID: T = Context->Char32Ty; break;
+ case pch::PREDEF_TYPE_OBJC_ID: T = Context->ObjCBuiltinIdTy; break;
+ case pch::PREDEF_TYPE_OBJC_CLASS: T = Context->ObjCBuiltinClassTy; break;
+ case pch::PREDEF_TYPE_OBJC_SEL: T = Context->ObjCBuiltinSelTy; break;
+ }
+
+ assert(!T.isNull() && "Unknown predefined type");
+ return T.withFastQualifiers(FastQuals);
+ }
+
+ Index -= pch::NUM_PREDEF_TYPE_IDS;
+ //assert(Index < TypesLoaded.size() && "Type index out-of-range");
+ if (TypesLoaded[Index].isNull()) {
+ TypesLoaded[Index] = ReadTypeRecord(TypeOffsets[Index]);
+ TypesLoaded[Index]->setFromPCH();
+ if (DeserializationListener)
+ DeserializationListener->TypeRead(ID, TypesLoaded[Index]);
+ }
+
+ return TypesLoaded[Index].withFastQualifiers(FastQuals);
+}
+
+TemplateArgumentLocInfo
+PCHReader::GetTemplateArgumentLocInfo(TemplateArgument::ArgKind Kind,
+ const RecordData &Record,
+ unsigned &Index) {
+ switch (Kind) {
+ case TemplateArgument::Expression:
+ return ReadExpr();
+ case TemplateArgument::Type:
+ return GetTypeSourceInfo(Record, Index);
+ case TemplateArgument::Template: {
+ SourceRange QualifierRange = ReadSourceRange(Record, Index);
+ SourceLocation TemplateNameLoc = ReadSourceLocation(Record, Index);
+ return TemplateArgumentLocInfo(QualifierRange, TemplateNameLoc);
+ }
+ case TemplateArgument::Null:
+ case TemplateArgument::Integral:
+ case TemplateArgument::Declaration:
+ case TemplateArgument::Pack:
+ return TemplateArgumentLocInfo();
+ }
+ llvm_unreachable("unexpected template argument loc");
+ return TemplateArgumentLocInfo();
+}
+
+TemplateArgumentLoc
+PCHReader::ReadTemplateArgumentLoc(const RecordData &Record, unsigned &Index) {
+ TemplateArgument Arg = ReadTemplateArgument(Record, Index);
+
+ if (Arg.getKind() == TemplateArgument::Expression) {
+ if (Record[Index++]) // bool InfoHasSameExpr.
+ return TemplateArgumentLoc(Arg, TemplateArgumentLocInfo(Arg.getAsExpr()));
+ }
+ return TemplateArgumentLoc(Arg, GetTemplateArgumentLocInfo(Arg.getKind(),
+ Record, Index));
+}
+
+Decl *PCHReader::GetExternalDecl(uint32_t ID) {
+ return GetDecl(ID);
+}
+
+TranslationUnitDecl *PCHReader::GetTranslationUnitDecl() {
+ if (!DeclsLoaded[0]) {
+ ReadDeclRecord(DeclOffsets[0], 0);
+ if (DeserializationListener)
+ DeserializationListener->DeclRead(0, DeclsLoaded[0]);
+ }
+
+ return cast<TranslationUnitDecl>(DeclsLoaded[0]);
+}
+
+Decl *PCHReader::GetDecl(pch::DeclID ID) {
+ if (ID == 0)
+ return 0;
+
+ if (ID > DeclsLoaded.size()) {
+ Error("declaration ID out-of-range for PCH file");
+ return 0;
+ }
+
+ unsigned Index = ID - 1;
+ if (!DeclsLoaded[Index]) {
+ ReadDeclRecord(DeclOffsets[Index], Index);
+ if (DeserializationListener)
+ DeserializationListener->DeclRead(ID, DeclsLoaded[Index]);
+ }
+
+ return DeclsLoaded[Index];
+}
+
+/// \brief Resolve the offset of a statement into a statement.
+///
+/// This operation will read a new statement from the external
+/// source each time it is called, and is meant to be used via a
+/// LazyOffsetPtr (which is used by Decls for the body of functions, etc).
+Stmt *PCHReader::GetExternalDeclStmt(uint64_t Offset) {
+ // Since we know tha this statement is part of a decl, make sure to use the
+ // decl cursor to read it.
+ DeclsCursor.JumpToBit(Offset);
+ return ReadStmtFromStream(DeclsCursor);
+}
+
+bool PCHReader::FindExternalLexicalDecls(const DeclContext *DC,
+ llvm::SmallVectorImpl<Decl*> &Decls) {
+ assert(DC->hasExternalLexicalStorage() &&
+ "DeclContext has no lexical decls in storage");
+
+ uint64_t Offset = DeclContextOffsets[DC].first;
+ if (Offset == 0) {
+ Error("DeclContext has no lexical decls in storage");
+ return true;
+ }
+
+ // Keep track of where we are in the stream, then jump back there
+ // after reading this context.
+ SavedStreamPosition SavedPosition(DeclsCursor);
+
+ // Load the record containing all of the declarations lexically in
+ // this context.
+ DeclsCursor.JumpToBit(Offset);
+ RecordData Record;
+ unsigned Code = DeclsCursor.ReadCode();
+ unsigned RecCode = DeclsCursor.ReadRecord(Code, Record);
+ if (RecCode != pch::DECL_CONTEXT_LEXICAL) {
+ Error("Expected lexical block");
+ return true;
+ }
+
+ // Load all of the declaration IDs
+ for (RecordData::iterator I = Record.begin(), E = Record.end(); I != E; ++I)
+ Decls.push_back(GetDecl(*I));
+ ++NumLexicalDeclContextsRead;
+ return false;
+}
+
+DeclContext::lookup_result
+PCHReader::FindExternalVisibleDeclsByName(const DeclContext *DC,
+ DeclarationName Name) {
+ assert(DC->hasExternalVisibleStorage() &&
+ "DeclContext has no visible decls in storage");
+ uint64_t Offset = DeclContextOffsets[DC].second;
+ if (Offset == 0) {
+ Error("DeclContext has no visible decls in storage");
+ return DeclContext::lookup_result(DeclContext::lookup_iterator(),
+ DeclContext::lookup_iterator());
+ }
+
+ // Keep track of where we are in the stream, then jump back there
+ // after reading this context.
+ SavedStreamPosition SavedPosition(DeclsCursor);
+
+ // Load the record containing all of the declarations visible in
+ // this context.
+ DeclsCursor.JumpToBit(Offset);
+ RecordData Record;
+ unsigned Code = DeclsCursor.ReadCode();
+ unsigned RecCode = DeclsCursor.ReadRecord(Code, Record);
+ if (RecCode != pch::DECL_CONTEXT_VISIBLE) {
+ Error("Expected visible block");
+ return DeclContext::lookup_result(DeclContext::lookup_iterator(),
+ DeclContext::lookup_iterator());
+ }
+
+ llvm::SmallVector<VisibleDeclaration, 64> Decls;
+ if (Record.empty()) {
+ SetExternalVisibleDecls(DC, Decls);
+ return DeclContext::lookup_result(DeclContext::lookup_iterator(),
+ DeclContext::lookup_iterator());
+ }
+
+ unsigned Idx = 0;
+ while (Idx < Record.size()) {
+ Decls.push_back(VisibleDeclaration());
+ Decls.back().Name = ReadDeclarationName(Record, Idx);
+
+ unsigned Size = Record[Idx++];
+ llvm::SmallVector<unsigned, 4> &LoadedDecls = Decls.back().Declarations;
+ LoadedDecls.reserve(Size);
+ for (unsigned I = 0; I < Size; ++I)
+ LoadedDecls.push_back(Record[Idx++]);
+ }
+
+ ++NumVisibleDeclContextsRead;
+
+ SetExternalVisibleDecls(DC, Decls);
+ return const_cast<DeclContext*>(DC)->lookup(Name);
+}
+
+void PCHReader::PassInterestingDeclsToConsumer() {
+ assert(Consumer);
+ while (!InterestingDecls.empty()) {
+ DeclGroupRef DG(InterestingDecls.front());
+ InterestingDecls.pop_front();
+ Consumer->HandleTopLevelDecl(DG);
+ }
+}
+
+void PCHReader::StartTranslationUnit(ASTConsumer *Consumer) {
+ this->Consumer = Consumer;
+
+ if (!Consumer)
+ return;
+
+ for (unsigned I = 0, N = ExternalDefinitions.size(); I != N; ++I) {
+ // Force deserialization of this decl, which will cause it to be queued for
+ // passing to the consumer.
+ GetDecl(ExternalDefinitions[I]);
+ }
+
+ PassInterestingDeclsToConsumer();
+}
+
+void PCHReader::PrintStats() {
+ std::fprintf(stderr, "*** PCH Statistics:\n");
+
+ unsigned NumTypesLoaded
+ = TypesLoaded.size() - std::count(TypesLoaded.begin(), TypesLoaded.end(),
+ QualType());
+ unsigned NumDeclsLoaded
+ = DeclsLoaded.size() - std::count(DeclsLoaded.begin(), DeclsLoaded.end(),
+ (Decl *)0);
+ unsigned NumIdentifiersLoaded
+ = IdentifiersLoaded.size() - std::count(IdentifiersLoaded.begin(),
+ IdentifiersLoaded.end(),
+ (IdentifierInfo *)0);
+ unsigned NumSelectorsLoaded
+ = SelectorsLoaded.size() - std::count(SelectorsLoaded.begin(),
+ SelectorsLoaded.end(),
+ Selector());
+
+ std::fprintf(stderr, " %u stat cache hits\n", NumStatHits);
+ std::fprintf(stderr, " %u stat cache misses\n", NumStatMisses);
+ if (TotalNumSLocEntries)
+ std::fprintf(stderr, " %u/%u source location entries read (%f%%)\n",
+ NumSLocEntriesRead, TotalNumSLocEntries,
+ ((float)NumSLocEntriesRead/TotalNumSLocEntries * 100));
+ if (!TypesLoaded.empty())
+ std::fprintf(stderr, " %u/%u types read (%f%%)\n",
+ NumTypesLoaded, (unsigned)TypesLoaded.size(),
+ ((float)NumTypesLoaded/TypesLoaded.size() * 100));
+ if (!DeclsLoaded.empty())
+ std::fprintf(stderr, " %u/%u declarations read (%f%%)\n",
+ NumDeclsLoaded, (unsigned)DeclsLoaded.size(),
+ ((float)NumDeclsLoaded/DeclsLoaded.size() * 100));
+ if (!IdentifiersLoaded.empty())
+ std::fprintf(stderr, " %u/%u identifiers read (%f%%)\n",
+ NumIdentifiersLoaded, (unsigned)IdentifiersLoaded.size(),
+ ((float)NumIdentifiersLoaded/IdentifiersLoaded.size() * 100));
+ if (TotalNumSelectors)
+ std::fprintf(stderr, " %u/%u selectors read (%f%%)\n",
+ NumSelectorsLoaded, TotalNumSelectors,
+ ((float)NumSelectorsLoaded/TotalNumSelectors * 100));
+ if (TotalNumStatements)
+ std::fprintf(stderr, " %u/%u statements read (%f%%)\n",
+ NumStatementsRead, TotalNumStatements,
+ ((float)NumStatementsRead/TotalNumStatements * 100));
+ if (TotalNumMacros)
+ std::fprintf(stderr, " %u/%u macros read (%f%%)\n",
+ NumMacrosRead, TotalNumMacros,
+ ((float)NumMacrosRead/TotalNumMacros * 100));
+ if (TotalLexicalDeclContexts)
+ std::fprintf(stderr, " %u/%u lexical declcontexts read (%f%%)\n",
+ NumLexicalDeclContextsRead, TotalLexicalDeclContexts,
+ ((float)NumLexicalDeclContextsRead/TotalLexicalDeclContexts
+ * 100));
+ if (TotalVisibleDeclContexts)
+ std::fprintf(stderr, " %u/%u visible declcontexts read (%f%%)\n",
+ NumVisibleDeclContextsRead, TotalVisibleDeclContexts,
+ ((float)NumVisibleDeclContextsRead/TotalVisibleDeclContexts
+ * 100));
+ if (TotalSelectorsInMethodPool) {
+ std::fprintf(stderr, " %u/%u method pool entries read (%f%%)\n",
+ NumMethodPoolSelectorsRead, TotalSelectorsInMethodPool,
+ ((float)NumMethodPoolSelectorsRead/TotalSelectorsInMethodPool
+ * 100));
+ std::fprintf(stderr, " %u method pool misses\n", NumMethodPoolMisses);
+ }
+ std::fprintf(stderr, "\n");
+}
+
+void PCHReader::InitializeSema(Sema &S) {
+ SemaObj = &S;
+ S.ExternalSource = this;
+
+ // Makes sure any declarations that were deserialized "too early"
+ // still get added to the identifier's declaration chains.
+ for (unsigned I = 0, N = PreloadedDecls.size(); I != N; ++I) {
+ SemaObj->TUScope->AddDecl(Action::DeclPtrTy::make(PreloadedDecls[I]));
+ SemaObj->IdResolver.AddDecl(PreloadedDecls[I]);
+ }
+ PreloadedDecls.clear();
+
+ // If there were any tentative definitions, deserialize them and add
+ // them to Sema's list of tentative definitions.
+ for (unsigned I = 0, N = TentativeDefinitions.size(); I != N; ++I) {
+ VarDecl *Var = cast<VarDecl>(GetDecl(TentativeDefinitions[I]));
+ SemaObj->TentativeDefinitions.push_back(Var);
+ }
+
+ // If there were any unused static functions, deserialize them and add to
+ // Sema's list of unused static functions.
+ for (unsigned I = 0, N = UnusedStaticFuncs.size(); I != N; ++I) {
+ FunctionDecl *FD = cast<FunctionDecl>(GetDecl(UnusedStaticFuncs[I]));
+ SemaObj->UnusedStaticFuncs.push_back(FD);
+ }
+
+ // If there were any locally-scoped external declarations,
+ // deserialize them and add them to Sema's table of locally-scoped
+ // external declarations.
+ for (unsigned I = 0, N = LocallyScopedExternalDecls.size(); I != N; ++I) {
+ NamedDecl *D = cast<NamedDecl>(GetDecl(LocallyScopedExternalDecls[I]));
+ SemaObj->LocallyScopedExternalDecls[D->getDeclName()] = D;
+ }
+
+ // If there were any ext_vector type declarations, deserialize them
+ // and add them to Sema's vector of such declarations.
+ for (unsigned I = 0, N = ExtVectorDecls.size(); I != N; ++I)
+ SemaObj->ExtVectorDecls.push_back(
+ cast<TypedefDecl>(GetDecl(ExtVectorDecls[I])));
+
+ // FIXME: Do VTable uses and dynamic classes deserialize too much ?
+ // Can we cut them down before writing them ?
+
+ // If there were any VTable uses, deserialize the information and add it
+ // to Sema's vector and map of VTable uses.
+ unsigned Idx = 0;
+ for (unsigned I = 0, N = VTableUses[Idx++]; I != N; ++I) {
+ CXXRecordDecl *Class = cast<CXXRecordDecl>(GetDecl(VTableUses[Idx++]));
+ SourceLocation Loc = ReadSourceLocation(VTableUses, Idx);
+ bool DefinitionRequired = VTableUses[Idx++];
+ SemaObj->VTableUses.push_back(std::make_pair(Class, Loc));
+ SemaObj->VTablesUsed[Class] = DefinitionRequired;
+ }
+
+ // If there were any dynamic classes declarations, deserialize them
+ // and add them to Sema's vector of such declarations.
+ for (unsigned I = 0, N = DynamicClasses.size(); I != N; ++I)
+ SemaObj->DynamicClasses.push_back(
+ cast<CXXRecordDecl>(GetDecl(DynamicClasses[I])));
+}
+
+IdentifierInfo* PCHReader::get(const char *NameStart, const char *NameEnd) {
+ // Try to find this name within our on-disk hash table
+ PCHIdentifierLookupTable *IdTable
+ = (PCHIdentifierLookupTable *)IdentifierLookupTable;
+ std::pair<const char*, unsigned> Key(NameStart, NameEnd - NameStart);
+ PCHIdentifierLookupTable::iterator Pos = IdTable->find(Key);
+ if (Pos == IdTable->end())
+ return 0;
+
+ // Dereferencing the iterator has the effect of building the
+ // IdentifierInfo node and populating it with the various
+ // declarations it needs.
+ return *Pos;
+}
+
+std::pair<ObjCMethodList, ObjCMethodList>
+PCHReader::ReadMethodPool(Selector Sel) {
+ if (!MethodPoolLookupTable)
+ return std::pair<ObjCMethodList, ObjCMethodList>();
+
+ // Try to find this selector within our on-disk hash table.
+ PCHMethodPoolLookupTable *PoolTable
+ = (PCHMethodPoolLookupTable*)MethodPoolLookupTable;
+ PCHMethodPoolLookupTable::iterator Pos = PoolTable->find(Sel);
+ if (Pos == PoolTable->end()) {
+ ++NumMethodPoolMisses;
+ return std::pair<ObjCMethodList, ObjCMethodList>();;
+ }
+
+ ++NumMethodPoolSelectorsRead;
+ return *Pos;
+}
+
+void PCHReader::SetIdentifierInfo(unsigned ID, IdentifierInfo *II) {
+ assert(ID && "Non-zero identifier ID required");
+ assert(ID <= IdentifiersLoaded.size() && "identifier ID out of range");
+ IdentifiersLoaded[ID - 1] = II;
+}
+
+/// \brief Set the globally-visible declarations associated with the given
+/// identifier.
+///
+/// If the PCH reader is currently in a state where the given declaration IDs
+/// cannot safely be resolved, they are queued until it is safe to resolve
+/// them.
+///
+/// \param II an IdentifierInfo that refers to one or more globally-visible
+/// declarations.
+///
+/// \param DeclIDs the set of declaration IDs with the name @p II that are
+/// visible at global scope.
+///
+/// \param Nonrecursive should be true to indicate that the caller knows that
+/// this call is non-recursive, and therefore the globally-visible declarations
+/// will not be placed onto the pending queue.
+void
+PCHReader::SetGloballyVisibleDecls(IdentifierInfo *II,
+ const llvm::SmallVectorImpl<uint32_t> &DeclIDs,
+ bool Nonrecursive) {
+ if (CurrentlyLoadingTypeOrDecl && !Nonrecursive) {
+ PendingIdentifierInfos.push_back(PendingIdentifierInfo());
+ PendingIdentifierInfo &PII = PendingIdentifierInfos.back();
+ PII.II = II;
+ for (unsigned I = 0, N = DeclIDs.size(); I != N; ++I)
+ PII.DeclIDs.push_back(DeclIDs[I]);
+ return;
+ }
+
+ for (unsigned I = 0, N = DeclIDs.size(); I != N; ++I) {
+ NamedDecl *D = cast<NamedDecl>(GetDecl(DeclIDs[I]));
+ if (SemaObj) {
+ // Introduce this declaration into the translation-unit scope
+ // and add it to the declaration chain for this identifier, so
+ // that (unqualified) name lookup will find it.
+ SemaObj->TUScope->AddDecl(Action::DeclPtrTy::make(D));
+ SemaObj->IdResolver.AddDeclToIdentifierChain(II, D);
+ } else {
+ // Queue this declaration so that it will be added to the
+ // translation unit scope and identifier's declaration chain
+ // once a Sema object is known.
+ PreloadedDecls.push_back(D);
+ }
+ }
+}
+
+IdentifierInfo *PCHReader::DecodeIdentifierInfo(unsigned ID) {
+ if (ID == 0)
+ return 0;
+
+ if (!IdentifierTableData || IdentifiersLoaded.empty()) {
+ Error("no identifier table in PCH file");
+ return 0;
+ }
+
+ assert(PP && "Forgot to set Preprocessor ?");
+ if (!IdentifiersLoaded[ID - 1]) {
+ uint32_t Offset = IdentifierOffsets[ID - 1];
+ const char *Str = IdentifierTableData + Offset;
+
+ // All of the strings in the PCH file are preceded by a 16-bit
+ // length. Extract that 16-bit length to avoid having to execute
+ // strlen().
+ // NOTE: 'StrLenPtr' is an 'unsigned char*' so that we load bytes as
+ // unsigned integers. This is important to avoid integer overflow when
+ // we cast them to 'unsigned'.
+ const unsigned char *StrLenPtr = (const unsigned char*) Str - 2;
+ unsigned StrLen = (((unsigned) StrLenPtr[0])
+ | (((unsigned) StrLenPtr[1]) << 8)) - 1;
+ IdentifiersLoaded[ID - 1]
+ = &PP->getIdentifierTable().get(Str, StrLen);
+ }
+
+ return IdentifiersLoaded[ID - 1];
+}
+
+void PCHReader::ReadSLocEntry(unsigned ID) {
+ ReadSLocEntryRecord(ID);
+}
+
+Selector PCHReader::DecodeSelector(unsigned ID) {
+ if (ID == 0)
+ return Selector();
+
+ if (!MethodPoolLookupTableData)
+ return Selector();
+
+ if (ID > TotalNumSelectors) {
+ Error("selector ID out of range in PCH file");
+ return Selector();
+ }
+
+ unsigned Index = ID - 1;
+ if (SelectorsLoaded[Index].getAsOpaquePtr() == 0) {
+ // Load this selector from the selector table.
+ // FIXME: endianness portability issues with SelectorOffsets table
+ PCHMethodPoolLookupTrait Trait(*this);
+ SelectorsLoaded[Index]
+ = Trait.ReadKey(MethodPoolLookupTableData + SelectorOffsets[Index], 0);
+ }
+
+ return SelectorsLoaded[Index];
+}
+
+Selector PCHReader::GetExternalSelector(uint32_t ID) {
+ return DecodeSelector(ID);
+}
+
+uint32_t PCHReader::GetNumExternalSelectors() {
+ return TotalNumSelectors + 1;
+}
+
+DeclarationName
+PCHReader::ReadDeclarationName(const RecordData &Record, unsigned &Idx) {
+ DeclarationName::NameKind Kind = (DeclarationName::NameKind)Record[Idx++];
+ switch (Kind) {
+ case DeclarationName::Identifier:
+ return DeclarationName(GetIdentifierInfo(Record, Idx));
+
+ case DeclarationName::ObjCZeroArgSelector:
+ case DeclarationName::ObjCOneArgSelector:
+ case DeclarationName::ObjCMultiArgSelector:
+ return DeclarationName(GetSelector(Record, Idx));
+
+ case DeclarationName::CXXConstructorName:
+ return Context->DeclarationNames.getCXXConstructorName(
+ Context->getCanonicalType(GetType(Record[Idx++])));
+
+ case DeclarationName::CXXDestructorName:
+ return Context->DeclarationNames.getCXXDestructorName(
+ Context->getCanonicalType(GetType(Record[Idx++])));
+
+ case DeclarationName::CXXConversionFunctionName:
+ return Context->DeclarationNames.getCXXConversionFunctionName(
+ Context->getCanonicalType(GetType(Record[Idx++])));
+
+ case DeclarationName::CXXOperatorName:
+ return Context->DeclarationNames.getCXXOperatorName(
+ (OverloadedOperatorKind)Record[Idx++]);
+
+ case DeclarationName::CXXLiteralOperatorName:
+ return Context->DeclarationNames.getCXXLiteralOperatorName(
+ GetIdentifierInfo(Record, Idx));
+
+ case DeclarationName::CXXUsingDirective:
+ return DeclarationName::getUsingDirectiveName();
+ }
+
+ // Required to silence GCC warning
+ return DeclarationName();
+}
+
+TemplateName
+PCHReader::ReadTemplateName(const RecordData &Record, unsigned &Idx) {
+ TemplateName::NameKind Kind = (TemplateName::NameKind)Record[Idx++];
+ switch (Kind) {
+ case TemplateName::Template:
+ return TemplateName(cast_or_null<TemplateDecl>(GetDecl(Record[Idx++])));
+
+ case TemplateName::OverloadedTemplate: {
+ unsigned size = Record[Idx++];
+ UnresolvedSet<8> Decls;
+ while (size--)
+ Decls.addDecl(cast<NamedDecl>(GetDecl(Record[Idx++])));
+
+ return Context->getOverloadedTemplateName(Decls.begin(), Decls.end());
+ }
+
+ case TemplateName::QualifiedTemplate: {
+ NestedNameSpecifier *NNS = ReadNestedNameSpecifier(Record, Idx);
+ bool hasTemplKeyword = Record[Idx++];
+ TemplateDecl *Template = cast<TemplateDecl>(GetDecl(Record[Idx++]));
+ return Context->getQualifiedTemplateName(NNS, hasTemplKeyword, Template);
+ }
+
+ case TemplateName::DependentTemplate: {
+ NestedNameSpecifier *NNS = ReadNestedNameSpecifier(Record, Idx);
+ if (Record[Idx++]) // isIdentifier
+ return Context->getDependentTemplateName(NNS,
+ GetIdentifierInfo(Record, Idx));
+ return Context->getDependentTemplateName(NNS,
+ (OverloadedOperatorKind)Record[Idx++]);
+ }
+ }
+
+ assert(0 && "Unhandled template name kind!");
+ return TemplateName();
+}
+
+TemplateArgument
+PCHReader::ReadTemplateArgument(const RecordData &Record, unsigned &Idx) {
+ switch ((TemplateArgument::ArgKind)Record[Idx++]) {
+ case TemplateArgument::Null:
+ return TemplateArgument();
+ case TemplateArgument::Type:
+ return TemplateArgument(GetType(Record[Idx++]));
+ case TemplateArgument::Declaration:
+ return TemplateArgument(GetDecl(Record[Idx++]));
+ case TemplateArgument::Integral: {
+ llvm::APSInt Value = ReadAPSInt(Record, Idx);
+ QualType T = GetType(Record[Idx++]);
+ return TemplateArgument(Value, T);
+ }
+ case TemplateArgument::Template:
+ return TemplateArgument(ReadTemplateName(Record, Idx));
+ case TemplateArgument::Expression:
+ return TemplateArgument(ReadExpr());
+ case TemplateArgument::Pack: {
+ unsigned NumArgs = Record[Idx++];
+ llvm::SmallVector<TemplateArgument, 8> Args;
+ Args.reserve(NumArgs);
+ while (NumArgs--)
+ Args.push_back(ReadTemplateArgument(Record, Idx));
+ TemplateArgument TemplArg;
+ TemplArg.setArgumentPack(Args.data(), Args.size(), /*CopyArgs=*/true);
+ return TemplArg;
+ }
+ }
+
+ assert(0 && "Unhandled template argument kind!");
+ return TemplateArgument();
+}
+
+TemplateParameterList *
+PCHReader::ReadTemplateParameterList(const RecordData &Record, unsigned &Idx) {
+ SourceLocation TemplateLoc = ReadSourceLocation(Record, Idx);
+ SourceLocation LAngleLoc = ReadSourceLocation(Record, Idx);
+ SourceLocation RAngleLoc = ReadSourceLocation(Record, Idx);
+
+ unsigned NumParams = Record[Idx++];
+ llvm::SmallVector<NamedDecl *, 16> Params;
+ Params.reserve(NumParams);
+ while (NumParams--)
+ Params.push_back(cast<NamedDecl>(GetDecl(Record[Idx++])));
+
+ TemplateParameterList* TemplateParams =
+ TemplateParameterList::Create(*Context, TemplateLoc, LAngleLoc,
+ Params.data(), Params.size(), RAngleLoc);
+ return TemplateParams;
+}
+
+void
+PCHReader::
+ReadTemplateArgumentList(llvm::SmallVector<TemplateArgument, 8> &TemplArgs,
+ const RecordData &Record, unsigned &Idx) {
+ unsigned NumTemplateArgs = Record[Idx++];
+ TemplArgs.reserve(NumTemplateArgs);
+ while (NumTemplateArgs--)
+ TemplArgs.push_back(ReadTemplateArgument(Record, Idx));
+}
+
+/// \brief Read a UnresolvedSet structure.
+void PCHReader::ReadUnresolvedSet(UnresolvedSetImpl &Set,
+ const RecordData &Record, unsigned &Idx) {
+ unsigned NumDecls = Record[Idx++];
+ while (NumDecls--) {
+ NamedDecl *D = cast<NamedDecl>(GetDecl(Record[Idx++]));
+ AccessSpecifier AS = (AccessSpecifier)Record[Idx++];
+ Set.addDecl(D, AS);
+ }
+}
+
+CXXBaseSpecifier
+PCHReader::ReadCXXBaseSpecifier(const RecordData &Record, unsigned &Idx) {
+ bool isVirtual = static_cast<bool>(Record[Idx++]);
+ bool isBaseOfClass = static_cast<bool>(Record[Idx++]);
+ AccessSpecifier AS = static_cast<AccessSpecifier>(Record[Idx++]);
+ QualType T = GetType(Record[Idx++]);
+ SourceRange Range = ReadSourceRange(Record, Idx);
+ return CXXBaseSpecifier(Range, isVirtual, isBaseOfClass, AS, T);
+}
+
+NestedNameSpecifier *
+PCHReader::ReadNestedNameSpecifier(const RecordData &Record, unsigned &Idx) {
+ unsigned N = Record[Idx++];
+ NestedNameSpecifier *NNS = 0, *Prev = 0;
+ for (unsigned I = 0; I != N; ++I) {
+ NestedNameSpecifier::SpecifierKind Kind
+ = (NestedNameSpecifier::SpecifierKind)Record[Idx++];
+ switch (Kind) {
+ case NestedNameSpecifier::Identifier: {
+ IdentifierInfo *II = GetIdentifierInfo(Record, Idx);
+ NNS = NestedNameSpecifier::Create(*Context, Prev, II);
+ break;
+ }
+
+ case NestedNameSpecifier::Namespace: {
+ NamespaceDecl *NS = cast<NamespaceDecl>(GetDecl(Record[Idx++]));
+ NNS = NestedNameSpecifier::Create(*Context, Prev, NS);
+ break;
+ }
+
+ case NestedNameSpecifier::TypeSpec:
+ case NestedNameSpecifier::TypeSpecWithTemplate: {
+ Type *T = GetType(Record[Idx++]).getTypePtr();
+ bool Template = Record[Idx++];
+ NNS = NestedNameSpecifier::Create(*Context, Prev, Template, T);
+ break;
+ }
+
+ case NestedNameSpecifier::Global: {
+ NNS = NestedNameSpecifier::GlobalSpecifier(*Context);
+ // No associated value, and there can't be a prefix.
+ break;
+ }
+ }
+ Prev = NNS;
+ }
+ return NNS;
+}
+
+SourceRange
+PCHReader::ReadSourceRange(const RecordData &Record, unsigned &Idx) {
+ SourceLocation beg = SourceLocation::getFromRawEncoding(Record[Idx++]);
+ SourceLocation end = SourceLocation::getFromRawEncoding(Record[Idx++]);
+ return SourceRange(beg, end);
+}
+
+/// \brief Read an integral value
+llvm::APInt PCHReader::ReadAPInt(const RecordData &Record, unsigned &Idx) {
+ unsigned BitWidth = Record[Idx++];
+ unsigned NumWords = llvm::APInt::getNumWords(BitWidth);
+ llvm::APInt Result(BitWidth, NumWords, &Record[Idx]);
+ Idx += NumWords;
+ return Result;
+}
+
+/// \brief Read a signed integral value
+llvm::APSInt PCHReader::ReadAPSInt(const RecordData &Record, unsigned &Idx) {
+ bool isUnsigned = Record[Idx++];
+ return llvm::APSInt(ReadAPInt(Record, Idx), isUnsigned);
+}
+
+/// \brief Read a floating-point value
+llvm::APFloat PCHReader::ReadAPFloat(const RecordData &Record, unsigned &Idx) {
+ return llvm::APFloat(ReadAPInt(Record, Idx));
+}
+
+// \brief Read a string
+std::string PCHReader::ReadString(const RecordData &Record, unsigned &Idx) {
+ unsigned Len = Record[Idx++];
+ std::string Result(Record.data() + Idx, Record.data() + Idx + Len);
+ Idx += Len;
+ return Result;
+}
+
+CXXTemporary *PCHReader::ReadCXXTemporary(const RecordData &Record,
+ unsigned &Idx) {
+ CXXDestructorDecl *Decl = cast<CXXDestructorDecl>(GetDecl(Record[Idx++]));
+ return CXXTemporary::Create(*Context, Decl);
+}
+
+DiagnosticBuilder PCHReader::Diag(unsigned DiagID) {
+ return Diag(SourceLocation(), DiagID);
+}
+
+DiagnosticBuilder PCHReader::Diag(SourceLocation Loc, unsigned DiagID) {
+ return Diags.Report(FullSourceLoc(Loc, SourceMgr), DiagID);
+}
+
+/// \brief Retrieve the identifier table associated with the
+/// preprocessor.
+IdentifierTable &PCHReader::getIdentifierTable() {
+ assert(PP && "Forgot to set Preprocessor ?");
+ return PP->getIdentifierTable();
+}
+
+/// \brief Record that the given ID maps to the given switch-case
+/// statement.
+void PCHReader::RecordSwitchCaseID(SwitchCase *SC, unsigned ID) {
+ assert(SwitchCaseStmts[ID] == 0 && "Already have a SwitchCase with this ID");
+ SwitchCaseStmts[ID] = SC;
+}
+
+/// \brief Retrieve the switch-case statement with the given ID.
+SwitchCase *PCHReader::getSwitchCaseWithID(unsigned ID) {
+ assert(SwitchCaseStmts[ID] != 0 && "No SwitchCase with this ID");
+ return SwitchCaseStmts[ID];
+}
+
+/// \brief Record that the given label statement has been
+/// deserialized and has the given ID.
+void PCHReader::RecordLabelStmt(LabelStmt *S, unsigned ID) {
+ assert(LabelStmts.find(ID) == LabelStmts.end() &&
+ "Deserialized label twice");
+ LabelStmts[ID] = S;
+
+ // If we've already seen any goto statements that point to this
+ // label, resolve them now.
+ typedef std::multimap<unsigned, GotoStmt *>::iterator GotoIter;
+ std::pair<GotoIter, GotoIter> Gotos = UnresolvedGotoStmts.equal_range(ID);
+ for (GotoIter Goto = Gotos.first; Goto != Gotos.second; ++Goto)
+ Goto->second->setLabel(S);
+ UnresolvedGotoStmts.erase(Gotos.first, Gotos.second);
+
+ // If we've already seen any address-label statements that point to
+ // this label, resolve them now.
+ typedef std::multimap<unsigned, AddrLabelExpr *>::iterator AddrLabelIter;
+ std::pair<AddrLabelIter, AddrLabelIter> AddrLabels
+ = UnresolvedAddrLabelExprs.equal_range(ID);
+ for (AddrLabelIter AddrLabel = AddrLabels.first;
+ AddrLabel != AddrLabels.second; ++AddrLabel)
+ AddrLabel->second->setLabel(S);
+ UnresolvedAddrLabelExprs.erase(AddrLabels.first, AddrLabels.second);
+}
+
+/// \brief Set the label of the given statement to the label
+/// identified by ID.
+///
+/// Depending on the order in which the label and other statements
+/// referencing that label occur, this operation may complete
+/// immediately (updating the statement) or it may queue the
+/// statement to be back-patched later.
+void PCHReader::SetLabelOf(GotoStmt *S, unsigned ID) {
+ std::map<unsigned, LabelStmt *>::iterator Label = LabelStmts.find(ID);
+ if (Label != LabelStmts.end()) {
+ // We've already seen this label, so set the label of the goto and
+ // we're done.
+ S->setLabel(Label->second);
+ } else {
+ // We haven't seen this label yet, so add this goto to the set of
+ // unresolved goto statements.
+ UnresolvedGotoStmts.insert(std::make_pair(ID, S));
+ }
+}
+
+/// \brief Set the label of the given expression to the label
+/// identified by ID.
+///
+/// Depending on the order in which the label and other statements
+/// referencing that label occur, this operation may complete
+/// immediately (updating the statement) or it may queue the
+/// statement to be back-patched later.
+void PCHReader::SetLabelOf(AddrLabelExpr *S, unsigned ID) {
+ std::map<unsigned, LabelStmt *>::iterator Label = LabelStmts.find(ID);
+ if (Label != LabelStmts.end()) {
+ // We've already seen this label, so set the label of the
+ // label-address expression and we're done.
+ S->setLabel(Label->second);
+ } else {
+ // We haven't seen this label yet, so add this label-address
+ // expression to the set of unresolved label-address expressions.
+ UnresolvedAddrLabelExprs.insert(std::make_pair(ID, S));
+ }
+}
+
+
+PCHReader::LoadingTypeOrDecl::LoadingTypeOrDecl(PCHReader &Reader)
+ : Reader(Reader), Parent(Reader.CurrentlyLoadingTypeOrDecl) {
+ Reader.CurrentlyLoadingTypeOrDecl = this;
+}
+
+PCHReader::LoadingTypeOrDecl::~LoadingTypeOrDecl() {
+ if (!Parent) {
+ // If any identifiers with corresponding top-level declarations have
+ // been loaded, load those declarations now.
+ while (!Reader.PendingIdentifierInfos.empty()) {
+ Reader.SetGloballyVisibleDecls(Reader.PendingIdentifierInfos.front().II,
+ Reader.PendingIdentifierInfos.front().DeclIDs,
+ true);
+ Reader.PendingIdentifierInfos.pop_front();
+ }
+
+ // We are not in recursive loading, so it's safe to pass the "interesting"
+ // decls to the consumer.
+ if (Reader.Consumer)
+ Reader.PassInterestingDeclsToConsumer();
+ }
+
+ Reader.CurrentlyLoadingTypeOrDecl = Parent;
+}
diff --git a/contrib/llvm/tools/clang/lib/Frontend/PCHReaderDecl.cpp b/contrib/llvm/tools/clang/lib/Frontend/PCHReaderDecl.cpp
new file mode 100644
index 0000000..742f0e4
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Frontend/PCHReaderDecl.cpp
@@ -0,0 +1,1484 @@
+//===--- PCHReaderDecl.cpp - Decl Deserialization ---------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the PCHReader::ReadDeclRecord method, which is the
+// entrypoint for loading a decl.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/PCHReader.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclVisitor.h"
+#include "clang/AST/DeclGroup.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/Expr.h"
+using namespace clang;
+
+
+//===----------------------------------------------------------------------===//
+// Declaration deserialization
+//===----------------------------------------------------------------------===//
+
+namespace clang {
+ class PCHDeclReader : public DeclVisitor<PCHDeclReader, void> {
+ PCHReader &Reader;
+ const PCHReader::RecordData &Record;
+ unsigned &Idx;
+ pch::TypeID TypeIDForTypeDecl;
+
+ public:
+ PCHDeclReader(PCHReader &Reader, const PCHReader::RecordData &Record,
+ unsigned &Idx)
+ : Reader(Reader), Record(Record), Idx(Idx), TypeIDForTypeDecl(0) { }
+
+ void Visit(Decl *D);
+
+ void VisitDecl(Decl *D);
+ void VisitTranslationUnitDecl(TranslationUnitDecl *TU);
+ void VisitNamedDecl(NamedDecl *ND);
+ void VisitNamespaceDecl(NamespaceDecl *D);
+ void VisitUsingDirectiveDecl(UsingDirectiveDecl *D);
+ void VisitNamespaceAliasDecl(NamespaceAliasDecl *D);
+ void VisitTypeDecl(TypeDecl *TD);
+ void VisitTypedefDecl(TypedefDecl *TD);
+ void VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D);
+ void VisitTagDecl(TagDecl *TD);
+ void VisitEnumDecl(EnumDecl *ED);
+ void VisitRecordDecl(RecordDecl *RD);
+ void VisitCXXRecordDecl(CXXRecordDecl *D);
+ void VisitClassTemplateSpecializationDecl(
+ ClassTemplateSpecializationDecl *D);
+ void VisitClassTemplatePartialSpecializationDecl(
+ ClassTemplatePartialSpecializationDecl *D);
+ void VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D);
+ void VisitValueDecl(ValueDecl *VD);
+ void VisitEnumConstantDecl(EnumConstantDecl *ECD);
+ void VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D);
+ void VisitDeclaratorDecl(DeclaratorDecl *DD);
+ void VisitFunctionDecl(FunctionDecl *FD);
+ void VisitCXXMethodDecl(CXXMethodDecl *D);
+ void VisitCXXConstructorDecl(CXXConstructorDecl *D);
+ void VisitCXXDestructorDecl(CXXDestructorDecl *D);
+ void VisitCXXConversionDecl(CXXConversionDecl *D);
+ void VisitFieldDecl(FieldDecl *FD);
+ void VisitVarDecl(VarDecl *VD);
+ void VisitImplicitParamDecl(ImplicitParamDecl *PD);
+ void VisitParmVarDecl(ParmVarDecl *PD);
+ void VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D);
+ void VisitTemplateDecl(TemplateDecl *D);
+ void VisitClassTemplateDecl(ClassTemplateDecl *D);
+ void VisitFunctionTemplateDecl(FunctionTemplateDecl *D);
+ void VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D);
+ void VisitUsingDecl(UsingDecl *D);
+ void VisitUsingShadowDecl(UsingShadowDecl *D);
+ void VisitLinkageSpecDecl(LinkageSpecDecl *D);
+ void VisitFileScopeAsmDecl(FileScopeAsmDecl *AD);
+ void VisitAccessSpecDecl(AccessSpecDecl *D);
+ void VisitFriendDecl(FriendDecl *D);
+ void VisitFriendTemplateDecl(FriendTemplateDecl *D);
+ void VisitStaticAssertDecl(StaticAssertDecl *D);
+ void VisitBlockDecl(BlockDecl *BD);
+
+ std::pair<uint64_t, uint64_t> VisitDeclContext(DeclContext *DC);
+
+ // FIXME: Reorder according to DeclNodes.td?
+ void VisitObjCMethodDecl(ObjCMethodDecl *D);
+ void VisitObjCContainerDecl(ObjCContainerDecl *D);
+ void VisitObjCInterfaceDecl(ObjCInterfaceDecl *D);
+ void VisitObjCIvarDecl(ObjCIvarDecl *D);
+ void VisitObjCProtocolDecl(ObjCProtocolDecl *D);
+ void VisitObjCAtDefsFieldDecl(ObjCAtDefsFieldDecl *D);
+ void VisitObjCClassDecl(ObjCClassDecl *D);
+ void VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D);
+ void VisitObjCCategoryDecl(ObjCCategoryDecl *D);
+ void VisitObjCImplDecl(ObjCImplDecl *D);
+ void VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D);
+ void VisitObjCImplementationDecl(ObjCImplementationDecl *D);
+ void VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *D);
+ void VisitObjCPropertyDecl(ObjCPropertyDecl *D);
+ void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D);
+ };
+}
+
+void PCHDeclReader::Visit(Decl *D) {
+ DeclVisitor<PCHDeclReader, void>::Visit(D);
+
+ if (TypeDecl *TD = dyn_cast<TypeDecl>(D)) {
+ // if we have a fully initialized TypeDecl, we can safely read its type now.
+ TD->setTypeForDecl(Reader.GetType(TypeIDForTypeDecl).getTypePtr());
+ } else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ // FunctionDecl's body was written last after all other Stmts/Exprs.
+ if (Record[Idx++])
+ FD->setLazyBody(Reader.getDeclsCursor().GetCurrentBitNo());
+ }
+}
+
+void PCHDeclReader::VisitDecl(Decl *D) {
+ D->setDeclContext(cast_or_null<DeclContext>(Reader.GetDecl(Record[Idx++])));
+ D->setLexicalDeclContext(
+ cast_or_null<DeclContext>(Reader.GetDecl(Record[Idx++])));
+ D->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ D->setInvalidDecl(Record[Idx++]);
+ if (Record[Idx++])
+ D->initAttrs(Reader.ReadAttributes());
+ D->setImplicit(Record[Idx++]);
+ D->setUsed(Record[Idx++]);
+ D->setAccess((AccessSpecifier)Record[Idx++]);
+ D->setPCHLevel(Record[Idx++] + 1);
+}
+
+void PCHDeclReader::VisitTranslationUnitDecl(TranslationUnitDecl *TU) {
+ VisitDecl(TU);
+ TU->setAnonymousNamespace(
+ cast_or_null<NamespaceDecl>(Reader.GetDecl(Record[Idx++])));
+}
+
+void PCHDeclReader::VisitNamedDecl(NamedDecl *ND) {
+ VisitDecl(ND);
+ ND->setDeclName(Reader.ReadDeclarationName(Record, Idx));
+}
+
+void PCHDeclReader::VisitTypeDecl(TypeDecl *TD) {
+ VisitNamedDecl(TD);
+ // Delay type reading until after we have fully initialized the decl.
+ TypeIDForTypeDecl = Record[Idx++];
+}
+
+void PCHDeclReader::VisitTypedefDecl(TypedefDecl *TD) {
+ VisitTypeDecl(TD);
+ TD->setTypeSourceInfo(Reader.GetTypeSourceInfo(Record, Idx));
+}
+
+void PCHDeclReader::VisitTagDecl(TagDecl *TD) {
+ VisitTypeDecl(TD);
+ TD->IdentifierNamespace = Record[Idx++];
+ TD->setPreviousDeclaration(
+ cast_or_null<TagDecl>(Reader.GetDecl(Record[Idx++])));
+ TD->setTagKind((TagDecl::TagKind)Record[Idx++]);
+ TD->setDefinition(Record[Idx++]);
+ TD->setEmbeddedInDeclarator(Record[Idx++]);
+ TD->setRBraceLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ TD->setTagKeywordLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ // FIXME: maybe read optional qualifier and its range.
+ TD->setTypedefForAnonDecl(
+ cast_or_null<TypedefDecl>(Reader.GetDecl(Record[Idx++])));
+}
+
+void PCHDeclReader::VisitEnumDecl(EnumDecl *ED) {
+ VisitTagDecl(ED);
+ ED->setIntegerType(Reader.GetType(Record[Idx++]));
+ ED->setPromotionType(Reader.GetType(Record[Idx++]));
+ ED->setNumPositiveBits(Record[Idx++]);
+ ED->setNumNegativeBits(Record[Idx++]);
+ ED->setInstantiationOfMemberEnum(
+ cast_or_null<EnumDecl>(Reader.GetDecl(Record[Idx++])));
+}
+
+void PCHDeclReader::VisitRecordDecl(RecordDecl *RD) {
+ VisitTagDecl(RD);
+ RD->setHasFlexibleArrayMember(Record[Idx++]);
+ RD->setAnonymousStructOrUnion(Record[Idx++]);
+ RD->setHasObjectMember(Record[Idx++]);
+}
+
+void PCHDeclReader::VisitValueDecl(ValueDecl *VD) {
+ VisitNamedDecl(VD);
+ VD->setType(Reader.GetType(Record[Idx++]));
+}
+
+void PCHDeclReader::VisitEnumConstantDecl(EnumConstantDecl *ECD) {
+ VisitValueDecl(ECD);
+ if (Record[Idx++])
+ ECD->setInitExpr(Reader.ReadExpr());
+ ECD->setInitVal(Reader.ReadAPSInt(Record, Idx));
+}
+
+void PCHDeclReader::VisitDeclaratorDecl(DeclaratorDecl *DD) {
+ VisitValueDecl(DD);
+ TypeSourceInfo *TInfo = Reader.GetTypeSourceInfo(Record, Idx);
+ if (TInfo)
+ DD->setTypeSourceInfo(TInfo);
+ // FIXME: read optional qualifier and its range.
+}
+
+void PCHDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
+ VisitDeclaratorDecl(FD);
+
+ FD->IdentifierNamespace = Record[Idx++];
+ switch ((FunctionDecl::TemplatedKind)Record[Idx++]) {
+ default: assert(false && "Unhandled TemplatedKind!");
+ break;
+ case FunctionDecl::TK_NonTemplate:
+ break;
+ case FunctionDecl::TK_FunctionTemplate:
+ FD->setDescribedFunctionTemplate(
+ cast<FunctionTemplateDecl>(Reader.GetDecl(Record[Idx++])));
+ break;
+ case FunctionDecl::TK_MemberSpecialization: {
+ FunctionDecl *InstFD = cast<FunctionDecl>(Reader.GetDecl(Record[Idx++]));
+ TemplateSpecializationKind TSK = (TemplateSpecializationKind)Record[Idx++];
+ SourceLocation POI = Reader.ReadSourceLocation(Record, Idx);
+ FD->setInstantiationOfMemberFunction(InstFD, TSK);
+ FD->getMemberSpecializationInfo()->setPointOfInstantiation(POI);
+ break;
+ }
+ case FunctionDecl::TK_FunctionTemplateSpecialization: {
+ FunctionTemplateDecl *Template
+ = cast<FunctionTemplateDecl>(Reader.GetDecl(Record[Idx++]));
+ TemplateSpecializationKind TSK = (TemplateSpecializationKind)Record[Idx++];
+
+ // Template arguments.
+ llvm::SmallVector<TemplateArgument, 8> TemplArgs;
+ Reader.ReadTemplateArgumentList(TemplArgs, Record, Idx);
+
+ // Template args as written.
+ llvm::SmallVector<TemplateArgumentLoc, 8> TemplArgLocs;
+ SourceLocation LAngleLoc, RAngleLoc;
+ if (Record[Idx++]) { // TemplateArgumentsAsWritten != 0
+ unsigned NumTemplateArgLocs = Record[Idx++];
+ TemplArgLocs.reserve(NumTemplateArgLocs);
+ for (unsigned i=0; i != NumTemplateArgLocs; ++i)
+ TemplArgLocs.push_back(Reader.ReadTemplateArgumentLoc(Record, Idx));
+
+ LAngleLoc = Reader.ReadSourceLocation(Record, Idx);
+ RAngleLoc = Reader.ReadSourceLocation(Record, Idx);
+ }
+
+ SourceLocation POI = Reader.ReadSourceLocation(Record, Idx);
+
+ FD->setFunctionTemplateSpecialization(Template, TemplArgs.size(),
+ TemplArgs.data(), TSK,
+ TemplArgLocs.size(),
+ TemplArgLocs.data(),
+ LAngleLoc, RAngleLoc, POI);
+ break;
+ }
+ case FunctionDecl::TK_DependentFunctionTemplateSpecialization: {
+ // Templates.
+ UnresolvedSet<8> TemplDecls;
+ unsigned NumTemplates = Record[Idx++];
+ while (NumTemplates--)
+ TemplDecls.addDecl(cast<NamedDecl>(Reader.GetDecl(Record[Idx++])));
+
+ // Templates args.
+ TemplateArgumentListInfo TemplArgs;
+ unsigned NumArgs = Record[Idx++];
+ while (NumArgs--)
+ TemplArgs.addArgument(Reader.ReadTemplateArgumentLoc(Record, Idx));
+ TemplArgs.setLAngleLoc(Reader.ReadSourceLocation(Record, Idx));
+ TemplArgs.setRAngleLoc(Reader.ReadSourceLocation(Record, Idx));
+
+ FD->setDependentTemplateSpecialization(*Reader.getContext(),
+ TemplDecls, TemplArgs);
+ break;
+ }
+ }
+
+ // FunctionDecl's body is handled last at PCHReaderDecl::Visit,
+ // after everything else is read.
+
+ // Avoid side effects and invariant checking of FunctionDecl's
+ // setPreviousDeclaration.
+ FD->redeclarable_base::setPreviousDeclaration(
+ cast_or_null<FunctionDecl>(Reader.GetDecl(Record[Idx++])));
+ FD->setStorageClass((FunctionDecl::StorageClass)Record[Idx++]);
+ FD->setStorageClassAsWritten((FunctionDecl::StorageClass)Record[Idx++]);
+ FD->setInlineSpecified(Record[Idx++]);
+ FD->setVirtualAsWritten(Record[Idx++]);
+ FD->setPure(Record[Idx++]);
+ FD->setHasInheritedPrototype(Record[Idx++]);
+ FD->setHasWrittenPrototype(Record[Idx++]);
+ FD->setDeleted(Record[Idx++]);
+ FD->setTrivial(Record[Idx++]);
+ FD->setCopyAssignment(Record[Idx++]);
+ FD->setHasImplicitReturnZero(Record[Idx++]);
+ FD->setLocEnd(SourceLocation::getFromRawEncoding(Record[Idx++]));
+
+ // Read in the parameters.
+ unsigned NumParams = Record[Idx++];
+ llvm::SmallVector<ParmVarDecl *, 16> Params;
+ Params.reserve(NumParams);
+ for (unsigned I = 0; I != NumParams; ++I)
+ Params.push_back(cast<ParmVarDecl>(Reader.GetDecl(Record[Idx++])));
+ FD->setParams(Params.data(), NumParams);
+}
+
+void PCHDeclReader::VisitObjCMethodDecl(ObjCMethodDecl *MD) {
+ VisitNamedDecl(MD);
+ if (Record[Idx++]) {
+ // In practice, this won't be executed (since method definitions
+ // don't occur in header files).
+ MD->setBody(Reader.ReadStmt());
+ MD->setSelfDecl(cast<ImplicitParamDecl>(Reader.GetDecl(Record[Idx++])));
+ MD->setCmdDecl(cast<ImplicitParamDecl>(Reader.GetDecl(Record[Idx++])));
+ }
+ MD->setInstanceMethod(Record[Idx++]);
+ MD->setVariadic(Record[Idx++]);
+ MD->setSynthesized(Record[Idx++]);
+ MD->setDeclImplementation((ObjCMethodDecl::ImplementationControl)Record[Idx++]);
+ MD->setObjCDeclQualifier((Decl::ObjCDeclQualifier)Record[Idx++]);
+ MD->setNumSelectorArgs(unsigned(Record[Idx++]));
+ MD->setResultType(Reader.GetType(Record[Idx++]));
+ MD->setResultTypeSourceInfo(Reader.GetTypeSourceInfo(Record, Idx));
+ MD->setEndLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ unsigned NumParams = Record[Idx++];
+ llvm::SmallVector<ParmVarDecl *, 16> Params;
+ Params.reserve(NumParams);
+ for (unsigned I = 0; I != NumParams; ++I)
+ Params.push_back(cast<ParmVarDecl>(Reader.GetDecl(Record[Idx++])));
+ MD->setMethodParams(*Reader.getContext(), Params.data(), NumParams,
+ NumParams);
+}
+
+void PCHDeclReader::VisitObjCContainerDecl(ObjCContainerDecl *CD) {
+ VisitNamedDecl(CD);
+ SourceLocation A = SourceLocation::getFromRawEncoding(Record[Idx++]);
+ SourceLocation B = SourceLocation::getFromRawEncoding(Record[Idx++]);
+ CD->setAtEndRange(SourceRange(A, B));
+}
+
+void PCHDeclReader::VisitObjCInterfaceDecl(ObjCInterfaceDecl *ID) {
+ VisitObjCContainerDecl(ID);
+ ID->setTypeForDecl(Reader.GetType(Record[Idx++]).getTypePtr());
+ ID->setSuperClass(cast_or_null<ObjCInterfaceDecl>
+ (Reader.GetDecl(Record[Idx++])));
+ unsigned NumProtocols = Record[Idx++];
+ llvm::SmallVector<ObjCProtocolDecl *, 16> Protocols;
+ Protocols.reserve(NumProtocols);
+ for (unsigned I = 0; I != NumProtocols; ++I)
+ Protocols.push_back(cast<ObjCProtocolDecl>(Reader.GetDecl(Record[Idx++])));
+ llvm::SmallVector<SourceLocation, 16> ProtoLocs;
+ ProtoLocs.reserve(NumProtocols);
+ for (unsigned I = 0; I != NumProtocols; ++I)
+ ProtoLocs.push_back(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ ID->setProtocolList(Protocols.data(), NumProtocols, ProtoLocs.data(),
+ *Reader.getContext());
+ unsigned NumIvars = Record[Idx++];
+ llvm::SmallVector<ObjCIvarDecl *, 16> IVars;
+ IVars.reserve(NumIvars);
+ for (unsigned I = 0; I != NumIvars; ++I)
+ IVars.push_back(cast<ObjCIvarDecl>(Reader.GetDecl(Record[Idx++])));
+ ID->setCategoryList(
+ cast_or_null<ObjCCategoryDecl>(Reader.GetDecl(Record[Idx++])));
+ ID->setForwardDecl(Record[Idx++]);
+ ID->setImplicitInterfaceDecl(Record[Idx++]);
+ ID->setClassLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ ID->setSuperClassLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ ID->setLocEnd(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+
+void PCHDeclReader::VisitObjCIvarDecl(ObjCIvarDecl *IVD) {
+ VisitFieldDecl(IVD);
+ IVD->setAccessControl((ObjCIvarDecl::AccessControl)Record[Idx++]);
+}
+
+void PCHDeclReader::VisitObjCProtocolDecl(ObjCProtocolDecl *PD) {
+ VisitObjCContainerDecl(PD);
+ PD->setForwardDecl(Record[Idx++]);
+ PD->setLocEnd(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ unsigned NumProtoRefs = Record[Idx++];
+ llvm::SmallVector<ObjCProtocolDecl *, 16> ProtoRefs;
+ ProtoRefs.reserve(NumProtoRefs);
+ for (unsigned I = 0; I != NumProtoRefs; ++I)
+ ProtoRefs.push_back(cast<ObjCProtocolDecl>(Reader.GetDecl(Record[Idx++])));
+ llvm::SmallVector<SourceLocation, 16> ProtoLocs;
+ ProtoLocs.reserve(NumProtoRefs);
+ for (unsigned I = 0; I != NumProtoRefs; ++I)
+ ProtoLocs.push_back(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ PD->setProtocolList(ProtoRefs.data(), NumProtoRefs, ProtoLocs.data(),
+ *Reader.getContext());
+}
+
+void PCHDeclReader::VisitObjCAtDefsFieldDecl(ObjCAtDefsFieldDecl *FD) {
+ VisitFieldDecl(FD);
+}
+
+void PCHDeclReader::VisitObjCClassDecl(ObjCClassDecl *CD) {
+ VisitDecl(CD);
+ unsigned NumClassRefs = Record[Idx++];
+ llvm::SmallVector<ObjCInterfaceDecl *, 16> ClassRefs;
+ ClassRefs.reserve(NumClassRefs);
+ for (unsigned I = 0; I != NumClassRefs; ++I)
+ ClassRefs.push_back(cast<ObjCInterfaceDecl>(Reader.GetDecl(Record[Idx++])));
+ llvm::SmallVector<SourceLocation, 16> SLocs;
+ SLocs.reserve(NumClassRefs);
+ for (unsigned I = 0; I != NumClassRefs; ++I)
+ SLocs.push_back(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ CD->setClassList(*Reader.getContext(), ClassRefs.data(), SLocs.data(),
+ NumClassRefs);
+}
+
+void PCHDeclReader::VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *FPD) {
+ VisitDecl(FPD);
+ unsigned NumProtoRefs = Record[Idx++];
+ llvm::SmallVector<ObjCProtocolDecl *, 16> ProtoRefs;
+ ProtoRefs.reserve(NumProtoRefs);
+ for (unsigned I = 0; I != NumProtoRefs; ++I)
+ ProtoRefs.push_back(cast<ObjCProtocolDecl>(Reader.GetDecl(Record[Idx++])));
+ llvm::SmallVector<SourceLocation, 16> ProtoLocs;
+ ProtoLocs.reserve(NumProtoRefs);
+ for (unsigned I = 0; I != NumProtoRefs; ++I)
+ ProtoLocs.push_back(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ FPD->setProtocolList(ProtoRefs.data(), NumProtoRefs, ProtoLocs.data(),
+ *Reader.getContext());
+}
+
+void PCHDeclReader::VisitObjCCategoryDecl(ObjCCategoryDecl *CD) {
+ VisitObjCContainerDecl(CD);
+ CD->setClassInterface(cast<ObjCInterfaceDecl>(Reader.GetDecl(Record[Idx++])));
+ unsigned NumProtoRefs = Record[Idx++];
+ llvm::SmallVector<ObjCProtocolDecl *, 16> ProtoRefs;
+ ProtoRefs.reserve(NumProtoRefs);
+ for (unsigned I = 0; I != NumProtoRefs; ++I)
+ ProtoRefs.push_back(cast<ObjCProtocolDecl>(Reader.GetDecl(Record[Idx++])));
+ llvm::SmallVector<SourceLocation, 16> ProtoLocs;
+ ProtoLocs.reserve(NumProtoRefs);
+ for (unsigned I = 0; I != NumProtoRefs; ++I)
+ ProtoLocs.push_back(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ CD->setProtocolList(ProtoRefs.data(), NumProtoRefs, ProtoLocs.data(),
+ *Reader.getContext());
+ CD->setNextClassCategory(cast_or_null<ObjCCategoryDecl>(Reader.GetDecl(Record[Idx++])));
+ CD->setAtLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ CD->setCategoryNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+
+void PCHDeclReader::VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *CAD) {
+ VisitNamedDecl(CAD);
+ CAD->setClassInterface(cast<ObjCInterfaceDecl>(Reader.GetDecl(Record[Idx++])));
+}
+
+void PCHDeclReader::VisitObjCPropertyDecl(ObjCPropertyDecl *D) {
+ VisitNamedDecl(D);
+ D->setAtLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ D->setType(Reader.GetTypeSourceInfo(Record, Idx));
+ // FIXME: stable encoding
+ D->setPropertyAttributes(
+ (ObjCPropertyDecl::PropertyAttributeKind)Record[Idx++]);
+ D->setPropertyAttributesAsWritten(
+ (ObjCPropertyDecl::PropertyAttributeKind)Record[Idx++]);
+ // FIXME: stable encoding
+ D->setPropertyImplementation(
+ (ObjCPropertyDecl::PropertyControl)Record[Idx++]);
+ D->setGetterName(Reader.ReadDeclarationName(Record, Idx).getObjCSelector());
+ D->setSetterName(Reader.ReadDeclarationName(Record, Idx).getObjCSelector());
+ D->setGetterMethodDecl(
+ cast_or_null<ObjCMethodDecl>(Reader.GetDecl(Record[Idx++])));
+ D->setSetterMethodDecl(
+ cast_or_null<ObjCMethodDecl>(Reader.GetDecl(Record[Idx++])));
+ D->setPropertyIvarDecl(
+ cast_or_null<ObjCIvarDecl>(Reader.GetDecl(Record[Idx++])));
+}
+
+void PCHDeclReader::VisitObjCImplDecl(ObjCImplDecl *D) {
+ VisitObjCContainerDecl(D);
+ D->setClassInterface(
+ cast_or_null<ObjCInterfaceDecl>(Reader.GetDecl(Record[Idx++])));
+}
+
+void PCHDeclReader::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) {
+ VisitObjCImplDecl(D);
+ D->setIdentifier(Reader.GetIdentifierInfo(Record, Idx));
+}
+
+void PCHDeclReader::VisitObjCImplementationDecl(ObjCImplementationDecl *D) {
+ VisitObjCImplDecl(D);
+ D->setSuperClass(
+ cast_or_null<ObjCInterfaceDecl>(Reader.GetDecl(Record[Idx++])));
+ // FIXME. Add reading of IvarInitializers and NumIvarInitializers.
+}
+
+
+void PCHDeclReader::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) {
+ VisitDecl(D);
+ D->setAtLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ D->setPropertyDecl(
+ cast_or_null<ObjCPropertyDecl>(Reader.GetDecl(Record[Idx++])));
+ D->setPropertyIvarDecl(
+ cast_or_null<ObjCIvarDecl>(Reader.GetDecl(Record[Idx++])));
+ // FIXME. read GetterCXXConstructor and SetterCXXAssignment
+}
+
+void PCHDeclReader::VisitFieldDecl(FieldDecl *FD) {
+ VisitDeclaratorDecl(FD);
+ FD->setMutable(Record[Idx++]);
+ if (Record[Idx++])
+ FD->setBitWidth(Reader.ReadExpr());
+ if (!FD->getDeclName()) {
+ FieldDecl *Tmpl = cast_or_null<FieldDecl>(Reader.GetDecl(Record[Idx++]));
+ if (Tmpl)
+ Reader.getContext()->setInstantiatedFromUnnamedFieldDecl(FD, Tmpl);
+ }
+}
+
+void PCHDeclReader::VisitVarDecl(VarDecl *VD) {
+ VisitDeclaratorDecl(VD);
+ VD->setStorageClass((VarDecl::StorageClass)Record[Idx++]);
+ VD->setStorageClassAsWritten((VarDecl::StorageClass)Record[Idx++]);
+ VD->setThreadSpecified(Record[Idx++]);
+ VD->setCXXDirectInitializer(Record[Idx++]);
+ VD->setDeclaredInCondition(Record[Idx++]);
+ VD->setExceptionVariable(Record[Idx++]);
+ VD->setNRVOVariable(Record[Idx++]);
+ VD->setPreviousDeclaration(
+ cast_or_null<VarDecl>(Reader.GetDecl(Record[Idx++])));
+ if (Record[Idx++])
+ VD->setInit(Reader.ReadExpr());
+
+ if (Record[Idx++]) { // HasMemberSpecializationInfo.
+ VarDecl *Tmpl = cast<VarDecl>(Reader.GetDecl(Record[Idx++]));
+ TemplateSpecializationKind TSK = (TemplateSpecializationKind)Record[Idx++];
+ SourceLocation POI = Reader.ReadSourceLocation(Record, Idx);
+ Reader.getContext()->setInstantiatedFromStaticDataMember(VD, Tmpl, TSK,POI);
+ }
+}
+
+void PCHDeclReader::VisitImplicitParamDecl(ImplicitParamDecl *PD) {
+ VisitVarDecl(PD);
+}
+
+void PCHDeclReader::VisitParmVarDecl(ParmVarDecl *PD) {
+ VisitVarDecl(PD);
+ PD->setObjCDeclQualifier((Decl::ObjCDeclQualifier)Record[Idx++]);
+ PD->setHasInheritedDefaultArg(Record[Idx++]);
+ if (Record[Idx++]) // hasUninstantiatedDefaultArg.
+ PD->setUninstantiatedDefaultArg(Reader.ReadExpr());
+}
+
+void PCHDeclReader::VisitFileScopeAsmDecl(FileScopeAsmDecl *AD) {
+ VisitDecl(AD);
+ AD->setAsmString(cast<StringLiteral>(Reader.ReadExpr()));
+}
+
+void PCHDeclReader::VisitBlockDecl(BlockDecl *BD) {
+ VisitDecl(BD);
+ BD->setBody(cast_or_null<CompoundStmt>(Reader.ReadStmt()));
+ BD->setSignatureAsWritten(Reader.GetTypeSourceInfo(Record, Idx));
+ unsigned NumParams = Record[Idx++];
+ llvm::SmallVector<ParmVarDecl *, 16> Params;
+ Params.reserve(NumParams);
+ for (unsigned I = 0; I != NumParams; ++I)
+ Params.push_back(cast<ParmVarDecl>(Reader.GetDecl(Record[Idx++])));
+ BD->setParams(Params.data(), NumParams);
+}
+
+void PCHDeclReader::VisitLinkageSpecDecl(LinkageSpecDecl *D) {
+ VisitDecl(D);
+ D->setLanguage((LinkageSpecDecl::LanguageIDs)Record[Idx++]);
+ D->setHasBraces(Record[Idx++]);
+}
+
+void PCHDeclReader::VisitNamespaceDecl(NamespaceDecl *D) {
+ VisitNamedDecl(D);
+ D->setLBracLoc(Reader.ReadSourceLocation(Record, Idx));
+ D->setRBracLoc(Reader.ReadSourceLocation(Record, Idx));
+ D->setNextNamespace(
+ cast_or_null<NamespaceDecl>(Reader.GetDecl(Record[Idx++])));
+
+ bool IsOriginal = Record[Idx++];
+ D->OrigOrAnonNamespace.setInt(IsOriginal);
+ D->OrigOrAnonNamespace.setPointer(
+ cast_or_null<NamespaceDecl>(Reader.GetDecl(Record[Idx++])));
+}
+
+void PCHDeclReader::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) {
+ VisitNamedDecl(D);
+
+ D->setAliasLoc(Reader.ReadSourceLocation(Record, Idx));
+ D->setQualifierRange(Reader.ReadSourceRange(Record, Idx));
+ D->setQualifier(Reader.ReadNestedNameSpecifier(Record, Idx));
+ D->setTargetNameLoc(Reader.ReadSourceLocation(Record, Idx));
+ D->setAliasedNamespace(cast<NamedDecl>(Reader.GetDecl(Record[Idx++])));
+}
+
+void PCHDeclReader::VisitUsingDecl(UsingDecl *D) {
+ VisitNamedDecl(D);
+ D->setUsingLocation(Reader.ReadSourceLocation(Record, Idx));
+ D->setNestedNameRange(Reader.ReadSourceRange(Record, Idx));
+ D->setTargetNestedNameDecl(Reader.ReadNestedNameSpecifier(Record, Idx));
+
+ // FIXME: It would probably be more efficient to read these into a vector
+ // and then re-cosntruct the shadow decl set over that vector since it
+ // would avoid existence checks.
+ unsigned NumShadows = Record[Idx++];
+ for(unsigned I = 0; I != NumShadows; ++I) {
+ // Avoid invariant checking of UsingDecl::addShadowDecl, the decl may still
+ // be initializing.
+ D->Shadows.insert(cast<UsingShadowDecl>(Reader.GetDecl(Record[Idx++])));
+ }
+ D->setTypeName(Record[Idx++]);
+ NamedDecl *Pattern = cast_or_null<NamedDecl>(Reader.GetDecl(Record[Idx++]));
+ if (Pattern)
+ Reader.getContext()->setInstantiatedFromUsingDecl(D, Pattern);
+}
+
+void PCHDeclReader::VisitUsingShadowDecl(UsingShadowDecl *D) {
+ VisitNamedDecl(D);
+ D->setTargetDecl(cast<NamedDecl>(Reader.GetDecl(Record[Idx++])));
+ D->setUsingDecl(cast<UsingDecl>(Reader.GetDecl(Record[Idx++])));
+ UsingShadowDecl *Pattern
+ = cast_or_null<UsingShadowDecl>(Reader.GetDecl(Record[Idx++]));
+ if (Pattern)
+ Reader.getContext()->setInstantiatedFromUsingShadowDecl(D, Pattern);
+}
+
+void PCHDeclReader::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) {
+ VisitNamedDecl(D);
+ D->setNamespaceKeyLocation(Reader.ReadSourceLocation(Record, Idx));
+ D->setQualifierRange(Reader.ReadSourceRange(Record, Idx));
+ D->setQualifier(Reader.ReadNestedNameSpecifier(Record, Idx));
+ D->setIdentLocation(Reader.ReadSourceLocation(Record, Idx));
+ D->setNominatedNamespace(cast<NamedDecl>(Reader.GetDecl(Record[Idx++])));
+ D->setCommonAncestor(cast_or_null<DeclContext>(
+ Reader.GetDecl(Record[Idx++])));
+}
+
+void PCHDeclReader::VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) {
+ VisitValueDecl(D);
+ D->setTargetNestedNameRange(Reader.ReadSourceRange(Record, Idx));
+ D->setUsingLoc(Reader.ReadSourceLocation(Record, Idx));
+ D->setTargetNestedNameSpecifier(Reader.ReadNestedNameSpecifier(Record, Idx));
+}
+
+void PCHDeclReader::VisitUnresolvedUsingTypenameDecl(
+ UnresolvedUsingTypenameDecl *D) {
+ VisitTypeDecl(D);
+ D->setTargetNestedNameRange(Reader.ReadSourceRange(Record, Idx));
+ D->setUsingLoc(Reader.ReadSourceLocation(Record, Idx));
+ D->setTypenameLoc(Reader.ReadSourceLocation(Record, Idx));
+ D->setTargetNestedNameSpecifier(Reader.ReadNestedNameSpecifier(Record, Idx));
+}
+
+void PCHDeclReader::VisitCXXRecordDecl(CXXRecordDecl *D) {
+ ASTContext &C = *Reader.getContext();
+
+ // We need to allocate the DefinitionData struct ahead of VisitRecordDecl
+ // so that the other CXXRecordDecls can get a pointer even when the owner
+ // is still initializing.
+ bool OwnsDefinitionData = false;
+ enum DataOwnership { Data_NoDefData, Data_Owner, Data_NotOwner };
+ switch ((DataOwnership)Record[Idx++]) {
+ default:
+ assert(0 && "Out of sync with PCHDeclWriter or messed up reading");
+ case Data_NoDefData:
+ break;
+ case Data_Owner:
+ OwnsDefinitionData = true;
+ D->DefinitionData = new (C) struct CXXRecordDecl::DefinitionData(D);
+ break;
+ case Data_NotOwner:
+ D->DefinitionData
+ = cast<CXXRecordDecl>(Reader.GetDecl(Record[Idx++]))->DefinitionData;
+ break;
+ }
+
+ VisitRecordDecl(D);
+
+ if (OwnsDefinitionData) {
+ assert(D->DefinitionData);
+ struct CXXRecordDecl::DefinitionData &Data = *D->DefinitionData;
+
+ Data.UserDeclaredConstructor = Record[Idx++];
+ Data.UserDeclaredCopyConstructor = Record[Idx++];
+ Data.UserDeclaredCopyAssignment = Record[Idx++];
+ Data.UserDeclaredDestructor = Record[Idx++];
+ Data.Aggregate = Record[Idx++];
+ Data.PlainOldData = Record[Idx++];
+ Data.Empty = Record[Idx++];
+ Data.Polymorphic = Record[Idx++];
+ Data.Abstract = Record[Idx++];
+ Data.HasTrivialConstructor = Record[Idx++];
+ Data.HasTrivialCopyConstructor = Record[Idx++];
+ Data.HasTrivialCopyAssignment = Record[Idx++];
+ Data.HasTrivialDestructor = Record[Idx++];
+ Data.ComputedVisibleConversions = Record[Idx++];
+ Data.DeclaredDefaultConstructor = Record[Idx++];
+ Data.DeclaredCopyConstructor = Record[Idx++];
+ Data.DeclaredCopyAssignment = Record[Idx++];
+ Data.DeclaredDestructor = Record[Idx++];
+
+ // setBases() is unsuitable since it may try to iterate the bases of an
+ // unitialized base.
+ Data.NumBases = Record[Idx++];
+ Data.Bases = new(C) CXXBaseSpecifier [Data.NumBases];
+ for (unsigned i = 0; i != Data.NumBases; ++i)
+ Data.Bases[i] = Reader.ReadCXXBaseSpecifier(Record, Idx);
+
+ // FIXME: Make VBases lazily computed when needed to avoid storing them.
+ Data.NumVBases = Record[Idx++];
+ Data.VBases = new(C) CXXBaseSpecifier [Data.NumVBases];
+ for (unsigned i = 0; i != Data.NumVBases; ++i)
+ Data.VBases[i] = Reader.ReadCXXBaseSpecifier(Record, Idx);
+
+ Reader.ReadUnresolvedSet(Data.Conversions, Record, Idx);
+ Reader.ReadUnresolvedSet(Data.VisibleConversions, Record, Idx);
+ assert(Data.Definition && "Data.Definition should be already set!");
+ Data.FirstFriend
+ = cast_or_null<FriendDecl>(Reader.GetDecl(Record[Idx++]));
+ }
+
+ enum CXXRecKind {
+ CXXRecNotTemplate = 0, CXXRecTemplate, CXXRecMemberSpecialization
+ };
+ switch ((CXXRecKind)Record[Idx++]) {
+ default:
+ assert(false && "Out of sync with PCHDeclWriter::VisitCXXRecordDecl?");
+ case CXXRecNotTemplate:
+ break;
+ case CXXRecTemplate:
+ D->setDescribedClassTemplate(
+ cast<ClassTemplateDecl>(Reader.GetDecl(Record[Idx++])));
+ break;
+ case CXXRecMemberSpecialization: {
+ CXXRecordDecl *RD = cast<CXXRecordDecl>(Reader.GetDecl(Record[Idx++]));
+ TemplateSpecializationKind TSK = (TemplateSpecializationKind)Record[Idx++];
+ SourceLocation POI = Reader.ReadSourceLocation(Record, Idx);
+ D->setInstantiationOfMemberClass(RD, TSK);
+ D->getMemberSpecializationInfo()->setPointOfInstantiation(POI);
+ break;
+ }
+ }
+}
+
+void PCHDeclReader::VisitCXXMethodDecl(CXXMethodDecl *D) {
+ VisitFunctionDecl(D);
+ unsigned NumOverridenMethods = Record[Idx++];
+ while (NumOverridenMethods--) {
+ CXXMethodDecl *MD = cast<CXXMethodDecl>(Reader.GetDecl(Record[Idx++]));
+ // Avoid invariant checking of CXXMethodDecl::addOverriddenMethod,
+ // MD may be initializing.
+ Reader.getContext()->addOverriddenMethod(D, MD);
+ }
+}
+
+void PCHDeclReader::VisitCXXConstructorDecl(CXXConstructorDecl *D) {
+ VisitCXXMethodDecl(D);
+
+ D->IsExplicitSpecified = Record[Idx++];
+ D->ImplicitlyDefined = Record[Idx++];
+
+ unsigned NumInitializers = Record[Idx++];
+ D->NumBaseOrMemberInitializers = NumInitializers;
+ if (NumInitializers) {
+ ASTContext &C = *Reader.getContext();
+
+ D->BaseOrMemberInitializers
+ = new (C) CXXBaseOrMemberInitializer*[NumInitializers];
+ for (unsigned i=0; i != NumInitializers; ++i) {
+ TypeSourceInfo *BaseClassInfo = 0;
+ bool IsBaseVirtual = false;
+ FieldDecl *Member = 0;
+
+ bool IsBaseInitializer = Record[Idx++];
+ if (IsBaseInitializer) {
+ BaseClassInfo = Reader.GetTypeSourceInfo(Record, Idx);
+ IsBaseVirtual = Record[Idx++];
+ } else {
+ Member = cast<FieldDecl>(Reader.GetDecl(Record[Idx++]));
+ }
+ SourceLocation MemberLoc = Reader.ReadSourceLocation(Record, Idx);
+ Expr *Init = Reader.ReadExpr();
+ FieldDecl *AnonUnionMember
+ = cast_or_null<FieldDecl>(Reader.GetDecl(Record[Idx++]));
+ SourceLocation LParenLoc = Reader.ReadSourceLocation(Record, Idx);
+ SourceLocation RParenLoc = Reader.ReadSourceLocation(Record, Idx);
+ bool IsWritten = Record[Idx++];
+ unsigned SourceOrderOrNumArrayIndices;
+ llvm::SmallVector<VarDecl *, 8> Indices;
+ if (IsWritten) {
+ SourceOrderOrNumArrayIndices = Record[Idx++];
+ } else {
+ SourceOrderOrNumArrayIndices = Record[Idx++];
+ Indices.reserve(SourceOrderOrNumArrayIndices);
+ for (unsigned i=0; i != SourceOrderOrNumArrayIndices; ++i)
+ Indices.push_back(cast<VarDecl>(Reader.GetDecl(Record[Idx++])));
+ }
+
+ CXXBaseOrMemberInitializer *BOMInit;
+ if (IsBaseInitializer) {
+ BOMInit = new (C) CXXBaseOrMemberInitializer(C, BaseClassInfo,
+ IsBaseVirtual, LParenLoc,
+ Init, RParenLoc);
+ } else if (IsWritten) {
+ BOMInit = new (C) CXXBaseOrMemberInitializer(C, Member, MemberLoc,
+ LParenLoc, Init, RParenLoc);
+ } else {
+ BOMInit = CXXBaseOrMemberInitializer::Create(C, Member, MemberLoc,
+ LParenLoc, Init, RParenLoc,
+ Indices.data(),
+ Indices.size());
+ }
+
+ BOMInit->setAnonUnionMember(AnonUnionMember);
+ D->BaseOrMemberInitializers[i] = BOMInit;
+ }
+ }
+}
+
+void PCHDeclReader::VisitCXXDestructorDecl(CXXDestructorDecl *D) {
+ VisitCXXMethodDecl(D);
+
+ D->ImplicitlyDefined = Record[Idx++];
+ D->OperatorDelete = cast_or_null<FunctionDecl>(Reader.GetDecl(Record[Idx++]));
+}
+
+void PCHDeclReader::VisitCXXConversionDecl(CXXConversionDecl *D) {
+ VisitCXXMethodDecl(D);
+ D->IsExplicitSpecified = Record[Idx++];
+}
+
+void PCHDeclReader::VisitAccessSpecDecl(AccessSpecDecl *D) {
+ VisitDecl(D);
+ D->setColonLoc(Reader.ReadSourceLocation(Record, Idx));
+}
+
+void PCHDeclReader::VisitFriendDecl(FriendDecl *D) {
+ VisitDecl(D);
+ if (Record[Idx++])
+ D->Friend = Reader.GetTypeSourceInfo(Record, Idx);
+ else
+ D->Friend = cast<NamedDecl>(Reader.GetDecl(Record[Idx++]));
+ D->NextFriend = cast_or_null<FriendDecl>(Reader.GetDecl(Record[Idx++]));
+ D->FriendLoc = Reader.ReadSourceLocation(Record, Idx);
+}
+
+void PCHDeclReader::VisitFriendTemplateDecl(FriendTemplateDecl *D) {
+ assert(false && "cannot read FriendTemplateDecl");
+}
+
+void PCHDeclReader::VisitTemplateDecl(TemplateDecl *D) {
+ VisitNamedDecl(D);
+
+ NamedDecl *TemplatedDecl
+ = cast_or_null<NamedDecl>(Reader.GetDecl(Record[Idx++]));
+ TemplateParameterList* TemplateParams
+ = Reader.ReadTemplateParameterList(Record, Idx);
+ D->init(TemplatedDecl, TemplateParams);
+}
+
+void PCHDeclReader::VisitClassTemplateDecl(ClassTemplateDecl *D) {
+ VisitTemplateDecl(D);
+
+ D->IdentifierNamespace = Record[Idx++];
+ ClassTemplateDecl *PrevDecl =
+ cast_or_null<ClassTemplateDecl>(Reader.GetDecl(Record[Idx++]));
+ D->setPreviousDeclaration(PrevDecl);
+ if (PrevDecl == 0) {
+ // This ClassTemplateDecl owns a CommonPtr; read it.
+
+ // FoldingSets are filled in VisitClassTemplateSpecializationDecl.
+ unsigned size = Record[Idx++];
+ while (size--)
+ cast<ClassTemplateSpecializationDecl>(Reader.GetDecl(Record[Idx++]));
+
+ size = Record[Idx++];
+ while (size--)
+ cast<ClassTemplatePartialSpecializationDecl>(
+ Reader.GetDecl(Record[Idx++]));
+
+ // InjectedClassNameType is computed.
+
+ if (ClassTemplateDecl *CTD
+ = cast_or_null<ClassTemplateDecl>(Reader.GetDecl(Record[Idx++]))) {
+ D->setInstantiatedFromMemberTemplate(CTD);
+ if (Record[Idx++])
+ D->setMemberSpecialization();
+ }
+ }
+}
+
+void PCHDeclReader::VisitClassTemplateSpecializationDecl(
+ ClassTemplateSpecializationDecl *D) {
+ VisitCXXRecordDecl(D);
+
+ if (Decl *InstD = Reader.GetDecl(Record[Idx++])) {
+ if (ClassTemplateDecl *CTD = dyn_cast<ClassTemplateDecl>(InstD)) {
+ D->setInstantiationOf(CTD);
+ } else {
+ llvm::SmallVector<TemplateArgument, 8> TemplArgs;
+ Reader.ReadTemplateArgumentList(TemplArgs, Record, Idx);
+ D->setInstantiationOf(cast<ClassTemplatePartialSpecializationDecl>(InstD),
+ TemplArgs.data(), TemplArgs.size());
+ }
+ }
+
+ // Explicit info.
+ if (TypeSourceInfo *TyInfo = Reader.GetTypeSourceInfo(Record, Idx)) {
+ D->setTypeAsWritten(TyInfo);
+ D->setExternLoc(Reader.ReadSourceLocation(Record, Idx));
+ D->setTemplateKeywordLoc(Reader.ReadSourceLocation(Record, Idx));
+ }
+
+ llvm::SmallVector<TemplateArgument, 8> TemplArgs;
+ Reader.ReadTemplateArgumentList(TemplArgs, Record, Idx);
+ D->initTemplateArgs(TemplArgs.data(), TemplArgs.size());
+ SourceLocation POI = Reader.ReadSourceLocation(Record, Idx);
+ if (POI.isValid())
+ D->setPointOfInstantiation(POI);
+ D->setSpecializationKind((TemplateSpecializationKind)Record[Idx++]);
+
+ if (Record[Idx++]) { // IsKeptInFoldingSet.
+ ClassTemplateDecl *CanonPattern
+ = cast<ClassTemplateDecl>(Reader.GetDecl(Record[Idx++]));
+ if (ClassTemplatePartialSpecializationDecl *Partial
+ = dyn_cast<ClassTemplatePartialSpecializationDecl>(D)) {
+ CanonPattern->getPartialSpecializations().InsertNode(Partial);
+ } else {
+ CanonPattern->getSpecializations().InsertNode(D);
+ }
+ }
+}
+
+void PCHDeclReader::VisitClassTemplatePartialSpecializationDecl(
+ ClassTemplatePartialSpecializationDecl *D) {
+ VisitClassTemplateSpecializationDecl(D);
+
+ D->initTemplateParameters(Reader.ReadTemplateParameterList(Record, Idx));
+
+ TemplateArgumentListInfo ArgInfos;
+ unsigned NumArgs = Record[Idx++];
+ while (NumArgs--)
+ ArgInfos.addArgument(Reader.ReadTemplateArgumentLoc(Record, Idx));
+ D->initTemplateArgsAsWritten(ArgInfos);
+
+ D->setSequenceNumber(Record[Idx++]);
+
+ // These are read/set from/to the first declaration.
+ if (D->getPreviousDeclaration() == 0) {
+ D->setInstantiatedFromMember(
+ cast_or_null<ClassTemplatePartialSpecializationDecl>(
+ Reader.GetDecl(Record[Idx++])));
+ if (Record[Idx++])
+ D->setMemberSpecialization();
+ }
+}
+
+void PCHDeclReader::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
+ VisitTemplateDecl(D);
+
+ D->IdentifierNamespace = Record[Idx++];
+ FunctionTemplateDecl *PrevDecl =
+ cast_or_null<FunctionTemplateDecl>(Reader.GetDecl(Record[Idx++]));
+ D->setPreviousDeclaration(PrevDecl);
+ if (PrevDecl == 0) {
+ // This FunctionTemplateDecl owns a CommonPtr; read it.
+
+ // Read the function specialization declarations.
+ // FunctionTemplateDecl's FunctionTemplateSpecializationInfos are filled
+ // through the specialized FunctionDecl's setFunctionTemplateSpecialization.
+ unsigned NumSpecs = Record[Idx++];
+ while (NumSpecs--)
+ Reader.GetDecl(Record[Idx++]);
+
+ if (FunctionTemplateDecl *CTD
+ = cast_or_null<FunctionTemplateDecl>(Reader.GetDecl(Record[Idx++]))) {
+ D->setInstantiatedFromMemberTemplate(CTD);
+ if (Record[Idx++])
+ D->setMemberSpecialization();
+ }
+ }
+}
+
+void PCHDeclReader::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) {
+ VisitTypeDecl(D);
+
+ D->setDeclaredWithTypename(Record[Idx++]);
+ D->setParameterPack(Record[Idx++]);
+
+ bool Inherited = Record[Idx++];
+ TypeSourceInfo *DefArg = Reader.GetTypeSourceInfo(Record, Idx);
+ D->setDefaultArgument(DefArg, Inherited);
+}
+
+void PCHDeclReader::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {
+ VisitVarDecl(D);
+ // TemplateParmPosition.
+ D->setDepth(Record[Idx++]);
+ D->setPosition(Record[Idx++]);
+ // Rest of NonTypeTemplateParmDecl.
+ if (Record[Idx++]) {
+ Expr *DefArg = Reader.ReadExpr();
+ bool Inherited = Record[Idx++];
+ D->setDefaultArgument(DefArg, Inherited);
+ }
+}
+
+void PCHDeclReader::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) {
+ VisitTemplateDecl(D);
+ // TemplateParmPosition.
+ D->setDepth(Record[Idx++]);
+ D->setPosition(Record[Idx++]);
+ // Rest of TemplateTemplateParmDecl.
+ TemplateArgumentLoc Arg = Reader.ReadTemplateArgumentLoc(Record, Idx);
+ bool IsInherited = Record[Idx++];
+ D->setDefaultArgument(Arg, IsInherited);
+}
+
+void PCHDeclReader::VisitStaticAssertDecl(StaticAssertDecl *D) {
+ assert(false && "cannot read StaticAssertDecl");
+}
+
+std::pair<uint64_t, uint64_t>
+PCHDeclReader::VisitDeclContext(DeclContext *DC) {
+ uint64_t LexicalOffset = Record[Idx++];
+ uint64_t VisibleOffset = Record[Idx++];
+ return std::make_pair(LexicalOffset, VisibleOffset);
+}
+
+//===----------------------------------------------------------------------===//
+// Attribute Reading
+//===----------------------------------------------------------------------===//
+
+/// \brief Reads attributes from the current stream position.
+Attr *PCHReader::ReadAttributes() {
+ unsigned Code = DeclsCursor.ReadCode();
+ assert(Code == llvm::bitc::UNABBREV_RECORD &&
+ "Expected unabbreviated record"); (void)Code;
+
+ RecordData Record;
+ unsigned Idx = 0;
+ unsigned RecCode = DeclsCursor.ReadRecord(Code, Record);
+ assert(RecCode == pch::DECL_ATTR && "Expected attribute record");
+ (void)RecCode;
+
+#define SIMPLE_ATTR(Name) \
+ case attr::Name: \
+ New = ::new (*Context) Name##Attr(); \
+ break
+
+#define STRING_ATTR(Name) \
+ case attr::Name: \
+ New = ::new (*Context) Name##Attr(*Context, ReadString(Record, Idx)); \
+ break
+
+#define UNSIGNED_ATTR(Name) \
+ case attr::Name: \
+ New = ::new (*Context) Name##Attr(Record[Idx++]); \
+ break
+
+ Attr *Attrs = 0;
+ while (Idx < Record.size()) {
+ Attr *New = 0;
+ attr::Kind Kind = (attr::Kind)Record[Idx++];
+ bool IsInherited = Record[Idx++];
+
+ switch (Kind) {
+ default:
+ assert(0 && "Unknown attribute!");
+ break;
+ STRING_ATTR(Alias);
+ SIMPLE_ATTR(AlignMac68k);
+ UNSIGNED_ATTR(Aligned);
+ SIMPLE_ATTR(AlwaysInline);
+ SIMPLE_ATTR(AnalyzerNoReturn);
+ STRING_ATTR(Annotate);
+ STRING_ATTR(AsmLabel);
+ SIMPLE_ATTR(BaseCheck);
+
+ case attr::Blocks:
+ New = ::new (*Context) BlocksAttr(
+ (BlocksAttr::BlocksAttrTypes)Record[Idx++]);
+ break;
+
+ SIMPLE_ATTR(CDecl);
+
+ case attr::Cleanup:
+ New = ::new (*Context) CleanupAttr(
+ cast<FunctionDecl>(GetDecl(Record[Idx++])));
+ break;
+
+ SIMPLE_ATTR(Const);
+ UNSIGNED_ATTR(Constructor);
+ SIMPLE_ATTR(DLLExport);
+ SIMPLE_ATTR(DLLImport);
+ SIMPLE_ATTR(Deprecated);
+ UNSIGNED_ATTR(Destructor);
+ SIMPLE_ATTR(FastCall);
+ SIMPLE_ATTR(Final);
+
+ case attr::Format: {
+ std::string Type = ReadString(Record, Idx);
+ unsigned FormatIdx = Record[Idx++];
+ unsigned FirstArg = Record[Idx++];
+ New = ::new (*Context) FormatAttr(*Context, Type, FormatIdx, FirstArg);
+ break;
+ }
+
+ case attr::FormatArg: {
+ unsigned FormatIdx = Record[Idx++];
+ New = ::new (*Context) FormatArgAttr(FormatIdx);
+ break;
+ }
+
+ case attr::Sentinel: {
+ int sentinel = Record[Idx++];
+ int nullPos = Record[Idx++];
+ New = ::new (*Context) SentinelAttr(sentinel, nullPos);
+ break;
+ }
+
+ SIMPLE_ATTR(GNUInline);
+ SIMPLE_ATTR(Hiding);
+
+ case attr::IBAction:
+ New = ::new (*Context) IBActionAttr();
+ break;
+
+ case attr::IBOutlet:
+ New = ::new (*Context) IBOutletAttr();
+ break;
+
+ case attr::IBOutletCollection: {
+ ObjCInterfaceDecl *D =
+ cast_or_null<ObjCInterfaceDecl>(GetDecl(Record[Idx++]));
+ New = ::new (*Context) IBOutletCollectionAttr(D);
+ break;
+ }
+
+ SIMPLE_ATTR(Malloc);
+ SIMPLE_ATTR(NoDebug);
+ SIMPLE_ATTR(NoInline);
+ SIMPLE_ATTR(NoReturn);
+ SIMPLE_ATTR(NoThrow);
+
+ case attr::NonNull: {
+ unsigned Size = Record[Idx++];
+ llvm::SmallVector<unsigned, 16> ArgNums;
+ ArgNums.insert(ArgNums.end(), &Record[Idx], &Record[Idx] + Size);
+ Idx += Size;
+ New = ::new (*Context) NonNullAttr(*Context, ArgNums.data(), Size);
+ break;
+ }
+
+ case attr::ReqdWorkGroupSize: {
+ unsigned X = Record[Idx++];
+ unsigned Y = Record[Idx++];
+ unsigned Z = Record[Idx++];
+ New = ::new (*Context) ReqdWorkGroupSizeAttr(X, Y, Z);
+ break;
+ }
+
+ SIMPLE_ATTR(ObjCException);
+ SIMPLE_ATTR(ObjCNSObject);
+ SIMPLE_ATTR(CFReturnsNotRetained);
+ SIMPLE_ATTR(CFReturnsRetained);
+ SIMPLE_ATTR(NSReturnsNotRetained);
+ SIMPLE_ATTR(NSReturnsRetained);
+ SIMPLE_ATTR(Overloadable);
+ SIMPLE_ATTR(Override);
+ SIMPLE_ATTR(Packed);
+ UNSIGNED_ATTR(MaxFieldAlignment);
+ SIMPLE_ATTR(Pure);
+ UNSIGNED_ATTR(Regparm);
+ STRING_ATTR(Section);
+ SIMPLE_ATTR(StdCall);
+ SIMPLE_ATTR(ThisCall);
+ SIMPLE_ATTR(TransparentUnion);
+ SIMPLE_ATTR(Unavailable);
+ SIMPLE_ATTR(Unused);
+ SIMPLE_ATTR(Used);
+
+ case attr::Visibility:
+ New = ::new (*Context) VisibilityAttr(
+ (VisibilityAttr::VisibilityTypes)Record[Idx++]);
+ break;
+
+ SIMPLE_ATTR(WarnUnusedResult);
+ SIMPLE_ATTR(Weak);
+ SIMPLE_ATTR(WeakRef);
+ SIMPLE_ATTR(WeakImport);
+ }
+
+ assert(New && "Unable to decode attribute?");
+ New->setInherited(IsInherited);
+ New->setNext(Attrs);
+ Attrs = New;
+ }
+#undef UNSIGNED_ATTR
+#undef STRING_ATTR
+#undef SIMPLE_ATTR
+
+ // The list of attributes was built backwards. Reverse the list
+ // before returning it.
+ Attr *PrevAttr = 0, *NextAttr = 0;
+ while (Attrs) {
+ NextAttr = Attrs->getNext();
+ Attrs->setNext(PrevAttr);
+ PrevAttr = Attrs;
+ Attrs = NextAttr;
+ }
+
+ return PrevAttr;
+}
+
+//===----------------------------------------------------------------------===//
+// PCHReader Implementation
+//===----------------------------------------------------------------------===//
+
+/// \brief Note that we have loaded the declaration with the given
+/// Index.
+///
+/// This routine notes that this declaration has already been loaded,
+/// so that future GetDecl calls will return this declaration rather
+/// than trying to load a new declaration.
+inline void PCHReader::LoadedDecl(unsigned Index, Decl *D) {
+ assert(!DeclsLoaded[Index] && "Decl loaded twice?");
+ DeclsLoaded[Index] = D;
+}
+
+
+/// \brief Determine whether the consumer will be interested in seeing
+/// this declaration (via HandleTopLevelDecl).
+///
+/// This routine should return true for anything that might affect
+/// code generation, e.g., inline function definitions, Objective-C
+/// declarations with metadata, etc.
+static bool isConsumerInterestedIn(Decl *D) {
+ if (isa<FileScopeAsmDecl>(D))
+ return true;
+ if (VarDecl *Var = dyn_cast<VarDecl>(D))
+ return Var->isFileVarDecl() && Var->getInit();
+ if (FunctionDecl *Func = dyn_cast<FunctionDecl>(D))
+ return Func->isThisDeclarationADefinition();
+ return isa<ObjCProtocolDecl>(D);
+}
+
+/// \brief Read the declaration at the given offset from the PCH file.
+Decl *PCHReader::ReadDeclRecord(uint64_t Offset, unsigned Index) {
+ // Keep track of where we are in the stream, then jump back there
+ // after reading this declaration.
+ SavedStreamPosition SavedPosition(DeclsCursor);
+
+ ReadingKindTracker ReadingKind(Read_Decl, *this);
+
+ // Note that we are loading a declaration record.
+ LoadingTypeOrDecl Loading(*this);
+
+ DeclsCursor.JumpToBit(Offset);
+ RecordData Record;
+ unsigned Code = DeclsCursor.ReadCode();
+ unsigned Idx = 0;
+ PCHDeclReader Reader(*this, Record, Idx);
+
+ Decl *D = 0;
+ switch ((pch::DeclCode)DeclsCursor.ReadRecord(Code, Record)) {
+ case pch::DECL_ATTR:
+ case pch::DECL_CONTEXT_LEXICAL:
+ case pch::DECL_CONTEXT_VISIBLE:
+ assert(false && "Record cannot be de-serialized with ReadDeclRecord");
+ break;
+ case pch::DECL_TRANSLATION_UNIT:
+ assert(Index == 0 && "Translation unit must be at index 0");
+ D = Context->getTranslationUnitDecl();
+ break;
+ case pch::DECL_TYPEDEF:
+ D = TypedefDecl::Create(*Context, 0, SourceLocation(), 0, 0);
+ break;
+ case pch::DECL_ENUM:
+ D = EnumDecl::Create(*Context, Decl::EmptyShell());
+ break;
+ case pch::DECL_RECORD:
+ D = RecordDecl::Create(*Context, Decl::EmptyShell());
+ break;
+ case pch::DECL_ENUM_CONSTANT:
+ D = EnumConstantDecl::Create(*Context, 0, SourceLocation(), 0, QualType(),
+ 0, llvm::APSInt());
+ break;
+ case pch::DECL_FUNCTION:
+ D = FunctionDecl::Create(*Context, 0, SourceLocation(), DeclarationName(),
+ QualType(), 0);
+ break;
+ case pch::DECL_LINKAGE_SPEC:
+ D = LinkageSpecDecl::Create(*Context, 0, SourceLocation(),
+ (LinkageSpecDecl::LanguageIDs)0,
+ false);
+ break;
+ case pch::DECL_NAMESPACE:
+ D = NamespaceDecl::Create(*Context, 0, SourceLocation(), 0);
+ break;
+ case pch::DECL_NAMESPACE_ALIAS:
+ D = NamespaceAliasDecl::Create(*Context, 0, SourceLocation(),
+ SourceLocation(), 0, SourceRange(), 0,
+ SourceLocation(), 0);
+ break;
+ case pch::DECL_USING:
+ D = UsingDecl::Create(*Context, 0, SourceLocation(), SourceRange(),
+ SourceLocation(), 0, DeclarationName(), false);
+ break;
+ case pch::DECL_USING_SHADOW:
+ D = UsingShadowDecl::Create(*Context, 0, SourceLocation(), 0, 0);
+ break;
+ case pch::DECL_USING_DIRECTIVE:
+ D = UsingDirectiveDecl::Create(*Context, 0, SourceLocation(),
+ SourceLocation(), SourceRange(), 0,
+ SourceLocation(), 0, 0);
+ break;
+ case pch::DECL_UNRESOLVED_USING_VALUE:
+ D = UnresolvedUsingValueDecl::Create(*Context, 0, SourceLocation(),
+ SourceRange(), 0, SourceLocation(),
+ DeclarationName());
+ break;
+ case pch::DECL_UNRESOLVED_USING_TYPENAME:
+ D = UnresolvedUsingTypenameDecl::Create(*Context, 0, SourceLocation(),
+ SourceLocation(), SourceRange(),
+ 0, SourceLocation(),
+ DeclarationName());
+ break;
+ case pch::DECL_CXX_RECORD:
+ D = CXXRecordDecl::Create(*Context, Decl::EmptyShell());
+ break;
+ case pch::DECL_CXX_METHOD:
+ D = CXXMethodDecl::Create(*Context, 0, SourceLocation(), DeclarationName(),
+ QualType(), 0);
+ break;
+ case pch::DECL_CXX_CONSTRUCTOR:
+ D = CXXConstructorDecl::Create(*Context, Decl::EmptyShell());
+ break;
+ case pch::DECL_CXX_DESTRUCTOR:
+ D = CXXDestructorDecl::Create(*Context, Decl::EmptyShell());
+ break;
+ case pch::DECL_CXX_CONVERSION:
+ D = CXXConversionDecl::Create(*Context, Decl::EmptyShell());
+ break;
+ case pch::DECL_ACCESS_SPEC:
+ D = AccessSpecDecl::Create(*Context, AS_none, 0, SourceLocation(),
+ SourceLocation());
+ break;
+ case pch::DECL_FRIEND:
+ D = FriendDecl::Create(*Context, Decl::EmptyShell());
+ break;
+ case pch::DECL_FRIEND_TEMPLATE:
+ assert(false && "cannot read FriendTemplateDecl");
+ break;
+ case pch::DECL_CLASS_TEMPLATE:
+ D = ClassTemplateDecl::Create(*Context, 0, SourceLocation(),
+ DeclarationName(), 0, 0, 0);
+ break;
+ case pch::DECL_CLASS_TEMPLATE_SPECIALIZATION:
+ D = ClassTemplateSpecializationDecl::Create(*Context, Decl::EmptyShell());
+ break;
+ case pch::DECL_CLASS_TEMPLATE_PARTIAL_SPECIALIZATION:
+ D = ClassTemplatePartialSpecializationDecl::Create(*Context,
+ Decl::EmptyShell());
+ break;
+ case pch::DECL_FUNCTION_TEMPLATE:
+ D = FunctionTemplateDecl::Create(*Context, 0, SourceLocation(),
+ DeclarationName(), 0, 0);
+ break;
+ case pch::DECL_TEMPLATE_TYPE_PARM:
+ D = TemplateTypeParmDecl::Create(*Context, Decl::EmptyShell());
+ break;
+ case pch::DECL_NON_TYPE_TEMPLATE_PARM:
+ D = NonTypeTemplateParmDecl::Create(*Context, 0, SourceLocation(), 0,0,0,
+ QualType(),0);
+ break;
+ case pch::DECL_TEMPLATE_TEMPLATE_PARM:
+ D = TemplateTemplateParmDecl::Create(*Context, 0, SourceLocation(),0,0,0,0);
+ break;
+ case pch::DECL_STATIC_ASSERT:
+ assert(false && "cannot read StaticAssertDecl");
+ break;
+
+ case pch::DECL_OBJC_METHOD:
+ D = ObjCMethodDecl::Create(*Context, SourceLocation(), SourceLocation(),
+ Selector(), QualType(), 0, 0);
+ break;
+ case pch::DECL_OBJC_INTERFACE:
+ D = ObjCInterfaceDecl::Create(*Context, 0, SourceLocation(), 0);
+ break;
+ case pch::DECL_OBJC_IVAR:
+ D = ObjCIvarDecl::Create(*Context, 0, SourceLocation(), 0, QualType(), 0,
+ ObjCIvarDecl::None);
+ break;
+ case pch::DECL_OBJC_PROTOCOL:
+ D = ObjCProtocolDecl::Create(*Context, 0, SourceLocation(), 0);
+ break;
+ case pch::DECL_OBJC_AT_DEFS_FIELD:
+ D = ObjCAtDefsFieldDecl::Create(*Context, 0, SourceLocation(), 0,
+ QualType(), 0);
+ break;
+ case pch::DECL_OBJC_CLASS:
+ D = ObjCClassDecl::Create(*Context, 0, SourceLocation());
+ break;
+ case pch::DECL_OBJC_FORWARD_PROTOCOL:
+ D = ObjCForwardProtocolDecl::Create(*Context, 0, SourceLocation());
+ break;
+ case pch::DECL_OBJC_CATEGORY:
+ D = ObjCCategoryDecl::Create(*Context, 0, SourceLocation(),
+ SourceLocation(), SourceLocation(), 0);
+ break;
+ case pch::DECL_OBJC_CATEGORY_IMPL:
+ D = ObjCCategoryImplDecl::Create(*Context, 0, SourceLocation(), 0, 0);
+ break;
+ case pch::DECL_OBJC_IMPLEMENTATION:
+ D = ObjCImplementationDecl::Create(*Context, 0, SourceLocation(), 0, 0);
+ break;
+ case pch::DECL_OBJC_COMPATIBLE_ALIAS:
+ D = ObjCCompatibleAliasDecl::Create(*Context, 0, SourceLocation(), 0, 0);
+ break;
+ case pch::DECL_OBJC_PROPERTY:
+ D = ObjCPropertyDecl::Create(*Context, 0, SourceLocation(), 0, SourceLocation(),
+ 0);
+ break;
+ case pch::DECL_OBJC_PROPERTY_IMPL:
+ D = ObjCPropertyImplDecl::Create(*Context, 0, SourceLocation(),
+ SourceLocation(), 0,
+ ObjCPropertyImplDecl::Dynamic, 0);
+ break;
+ case pch::DECL_FIELD:
+ D = FieldDecl::Create(*Context, 0, SourceLocation(), 0, QualType(), 0, 0,
+ false);
+ break;
+ case pch::DECL_VAR:
+ D = VarDecl::Create(*Context, 0, SourceLocation(), 0, QualType(), 0,
+ VarDecl::None, VarDecl::None);
+ break;
+
+ case pch::DECL_IMPLICIT_PARAM:
+ D = ImplicitParamDecl::Create(*Context, 0, SourceLocation(), 0, QualType());
+ break;
+
+ case pch::DECL_PARM_VAR:
+ D = ParmVarDecl::Create(*Context, 0, SourceLocation(), 0, QualType(), 0,
+ VarDecl::None, VarDecl::None, 0);
+ break;
+ case pch::DECL_FILE_SCOPE_ASM:
+ D = FileScopeAsmDecl::Create(*Context, 0, SourceLocation(), 0);
+ break;
+ case pch::DECL_BLOCK:
+ D = BlockDecl::Create(*Context, 0, SourceLocation());
+ break;
+ }
+
+ assert(D && "Unknown declaration reading PCH file");
+ LoadedDecl(Index, D);
+ Reader.Visit(D);
+
+ // If this declaration is also a declaration context, get the
+ // offsets for its tables of lexical and visible declarations.
+ if (DeclContext *DC = dyn_cast<DeclContext>(D)) {
+ std::pair<uint64_t, uint64_t> Offsets = Reader.VisitDeclContext(DC);
+ if (Offsets.first || Offsets.second) {
+ DC->setHasExternalLexicalStorage(Offsets.first != 0);
+ DC->setHasExternalVisibleStorage(Offsets.second != 0);
+ DeclContextOffsets[DC] = Offsets;
+ }
+ }
+ assert(Idx == Record.size());
+
+ // If we have deserialized a declaration that has a definition the
+ // AST consumer might need to know about, queue it.
+ // We don't pass it to the consumer immediately because we may be in recursive
+ // loading, and some declarations may still be initializing.
+ if (isConsumerInterestedIn(D))
+ InterestingDecls.push_back(D);
+
+ return D;
+}
diff --git a/contrib/llvm/tools/clang/lib/Frontend/PCHReaderStmt.cpp b/contrib/llvm/tools/clang/lib/Frontend/PCHReaderStmt.cpp
new file mode 100644
index 0000000..ace62d7
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Frontend/PCHReaderStmt.cpp
@@ -0,0 +1,1727 @@
+//===--- PCHReaderStmt.cpp - Stmt/Expr Deserialization ----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Statement/expression deserialization. This implements the
+// PCHReader::ReadStmt method.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/PCHReader.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/StmtVisitor.h"
+using namespace clang;
+
+namespace clang {
+
+ class PCHStmtReader : public StmtVisitor<PCHStmtReader> {
+ PCHReader &Reader;
+ const PCHReader::RecordData &Record;
+ unsigned &Idx;
+
+ public:
+ PCHStmtReader(PCHReader &Reader, const PCHReader::RecordData &Record,
+ unsigned &Idx)
+ : Reader(Reader), Record(Record), Idx(Idx) { }
+
+ /// \brief The number of record fields required for the Stmt class
+ /// itself.
+ static const unsigned NumStmtFields = 0;
+
+ /// \brief The number of record fields required for the Expr class
+ /// itself.
+ static const unsigned NumExprFields = NumStmtFields + 3;
+
+ /// \brief Read and initialize a ExplicitTemplateArgumentList structure.
+ void ReadExplicitTemplateArgumentList(ExplicitTemplateArgumentList &ArgList,
+ unsigned NumTemplateArgs);
+
+ void VisitStmt(Stmt *S);
+ void VisitNullStmt(NullStmt *S);
+ void VisitCompoundStmt(CompoundStmt *S);
+ void VisitSwitchCase(SwitchCase *S);
+ void VisitCaseStmt(CaseStmt *S);
+ void VisitDefaultStmt(DefaultStmt *S);
+ void VisitLabelStmt(LabelStmt *S);
+ void VisitIfStmt(IfStmt *S);
+ void VisitSwitchStmt(SwitchStmt *S);
+ void VisitWhileStmt(WhileStmt *S);
+ void VisitDoStmt(DoStmt *S);
+ void VisitForStmt(ForStmt *S);
+ void VisitGotoStmt(GotoStmt *S);
+ void VisitIndirectGotoStmt(IndirectGotoStmt *S);
+ void VisitContinueStmt(ContinueStmt *S);
+ void VisitBreakStmt(BreakStmt *S);
+ void VisitReturnStmt(ReturnStmt *S);
+ void VisitDeclStmt(DeclStmt *S);
+ void VisitAsmStmt(AsmStmt *S);
+ void VisitExpr(Expr *E);
+ void VisitPredefinedExpr(PredefinedExpr *E);
+ void VisitDeclRefExpr(DeclRefExpr *E);
+ void VisitIntegerLiteral(IntegerLiteral *E);
+ void VisitFloatingLiteral(FloatingLiteral *E);
+ void VisitImaginaryLiteral(ImaginaryLiteral *E);
+ void VisitStringLiteral(StringLiteral *E);
+ void VisitCharacterLiteral(CharacterLiteral *E);
+ void VisitParenExpr(ParenExpr *E);
+ void VisitParenListExpr(ParenListExpr *E);
+ void VisitUnaryOperator(UnaryOperator *E);
+ void VisitOffsetOfExpr(OffsetOfExpr *E);
+ void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E);
+ void VisitArraySubscriptExpr(ArraySubscriptExpr *E);
+ void VisitCallExpr(CallExpr *E);
+ void VisitMemberExpr(MemberExpr *E);
+ void VisitCastExpr(CastExpr *E);
+ void VisitBinaryOperator(BinaryOperator *E);
+ void VisitCompoundAssignOperator(CompoundAssignOperator *E);
+ void VisitConditionalOperator(ConditionalOperator *E);
+ void VisitImplicitCastExpr(ImplicitCastExpr *E);
+ void VisitExplicitCastExpr(ExplicitCastExpr *E);
+ void VisitCStyleCastExpr(CStyleCastExpr *E);
+ void VisitCompoundLiteralExpr(CompoundLiteralExpr *E);
+ void VisitExtVectorElementExpr(ExtVectorElementExpr *E);
+ void VisitInitListExpr(InitListExpr *E);
+ void VisitDesignatedInitExpr(DesignatedInitExpr *E);
+ void VisitImplicitValueInitExpr(ImplicitValueInitExpr *E);
+ void VisitVAArgExpr(VAArgExpr *E);
+ void VisitAddrLabelExpr(AddrLabelExpr *E);
+ void VisitStmtExpr(StmtExpr *E);
+ void VisitTypesCompatibleExpr(TypesCompatibleExpr *E);
+ void VisitChooseExpr(ChooseExpr *E);
+ void VisitGNUNullExpr(GNUNullExpr *E);
+ void VisitShuffleVectorExpr(ShuffleVectorExpr *E);
+ void VisitBlockExpr(BlockExpr *E);
+ void VisitBlockDeclRefExpr(BlockDeclRefExpr *E);
+ void VisitObjCStringLiteral(ObjCStringLiteral *E);
+ void VisitObjCEncodeExpr(ObjCEncodeExpr *E);
+ void VisitObjCSelectorExpr(ObjCSelectorExpr *E);
+ void VisitObjCProtocolExpr(ObjCProtocolExpr *E);
+ void VisitObjCIvarRefExpr(ObjCIvarRefExpr *E);
+ void VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E);
+ void VisitObjCImplicitSetterGetterRefExpr(
+ ObjCImplicitSetterGetterRefExpr *E);
+ void VisitObjCMessageExpr(ObjCMessageExpr *E);
+ void VisitObjCSuperExpr(ObjCSuperExpr *E);
+ void VisitObjCIsaExpr(ObjCIsaExpr *E);
+
+ void VisitObjCForCollectionStmt(ObjCForCollectionStmt *);
+ void VisitObjCAtCatchStmt(ObjCAtCatchStmt *);
+ void VisitObjCAtFinallyStmt(ObjCAtFinallyStmt *);
+ void VisitObjCAtTryStmt(ObjCAtTryStmt *);
+ void VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *);
+ void VisitObjCAtThrowStmt(ObjCAtThrowStmt *);
+
+ void VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E);
+ void VisitCXXConstructExpr(CXXConstructExpr *E);
+ void VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *E);
+ void VisitCXXNamedCastExpr(CXXNamedCastExpr *E);
+ void VisitCXXStaticCastExpr(CXXStaticCastExpr *E);
+ void VisitCXXDynamicCastExpr(CXXDynamicCastExpr *E);
+ void VisitCXXReinterpretCastExpr(CXXReinterpretCastExpr *E);
+ void VisitCXXConstCastExpr(CXXConstCastExpr *E);
+ void VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E);
+ void VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E);
+ void VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *E);
+ void VisitCXXTypeidExpr(CXXTypeidExpr *E);
+ void VisitCXXThisExpr(CXXThisExpr *E);
+ void VisitCXXThrowExpr(CXXThrowExpr *E);
+ void VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E);
+ void VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E);
+ void VisitCXXBindReferenceExpr(CXXBindReferenceExpr *E);
+
+ void VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E);
+ void VisitCXXNewExpr(CXXNewExpr *E);
+ void VisitCXXDeleteExpr(CXXDeleteExpr *E);
+ void VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E);
+
+ void VisitCXXExprWithTemporaries(CXXExprWithTemporaries *E);
+
+ void VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E);
+ void VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E);
+ void VisitCXXUnresolvedConstructExpr(CXXUnresolvedConstructExpr *E);
+
+ void VisitOverloadExpr(OverloadExpr *E);
+ void VisitUnresolvedMemberExpr(UnresolvedMemberExpr *E);
+ void VisitUnresolvedLookupExpr(UnresolvedLookupExpr *E);
+
+ void VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *E);
+ };
+}
+
+void PCHStmtReader::
+ReadExplicitTemplateArgumentList(ExplicitTemplateArgumentList &ArgList,
+ unsigned NumTemplateArgs) {
+ TemplateArgumentListInfo ArgInfo;
+ ArgInfo.setLAngleLoc(Reader.ReadSourceLocation(Record, Idx));
+ ArgInfo.setRAngleLoc(Reader.ReadSourceLocation(Record, Idx));
+ for (unsigned i = 0; i != NumTemplateArgs; ++i)
+ ArgInfo.addArgument(Reader.ReadTemplateArgumentLoc(Record, Idx));
+ ArgList.initializeFrom(ArgInfo);
+}
+
+void PCHStmtReader::VisitStmt(Stmt *S) {
+ assert(Idx == NumStmtFields && "Incorrect statement field count");
+}
+
+void PCHStmtReader::VisitNullStmt(NullStmt *S) {
+ VisitStmt(S);
+ S->setSemiLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+
+void PCHStmtReader::VisitCompoundStmt(CompoundStmt *S) {
+ VisitStmt(S);
+ llvm::SmallVector<Stmt *, 16> Stmts;
+ unsigned NumStmts = Record[Idx++];
+ while (NumStmts--)
+ Stmts.push_back(Reader.ReadSubStmt());
+ S->setStmts(*Reader.getContext(), Stmts.data(), Stmts.size());
+ S->setLBracLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ S->setRBracLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+
+void PCHStmtReader::VisitSwitchCase(SwitchCase *S) {
+ VisitStmt(S);
+ Reader.RecordSwitchCaseID(S, Record[Idx++]);
+}
+
+void PCHStmtReader::VisitCaseStmt(CaseStmt *S) {
+ VisitSwitchCase(S);
+ S->setLHS(Reader.ReadSubExpr());
+ S->setRHS(Reader.ReadSubExpr());
+ S->setSubStmt(Reader.ReadSubStmt());
+ S->setCaseLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ S->setEllipsisLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ S->setColonLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+
+void PCHStmtReader::VisitDefaultStmt(DefaultStmt *S) {
+ VisitSwitchCase(S);
+ S->setSubStmt(Reader.ReadSubStmt());
+ S->setDefaultLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ S->setColonLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+
+void PCHStmtReader::VisitLabelStmt(LabelStmt *S) {
+ VisitStmt(S);
+ S->setID(Reader.GetIdentifierInfo(Record, Idx));
+ S->setSubStmt(Reader.ReadSubStmt());
+ S->setIdentLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ Reader.RecordLabelStmt(S, Record[Idx++]);
+}
+
+void PCHStmtReader::VisitIfStmt(IfStmt *S) {
+ VisitStmt(S);
+ S->setConditionVariable(*Reader.getContext(),
+ cast_or_null<VarDecl>(Reader.GetDecl(Record[Idx++])));
+ S->setCond(Reader.ReadSubExpr());
+ S->setThen(Reader.ReadSubStmt());
+ S->setElse(Reader.ReadSubStmt());
+ S->setIfLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ S->setElseLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+
+void PCHStmtReader::VisitSwitchStmt(SwitchStmt *S) {
+ VisitStmt(S);
+ S->setConditionVariable(*Reader.getContext(),
+ cast_or_null<VarDecl>(Reader.GetDecl(Record[Idx++])));
+ S->setCond(Reader.ReadSubExpr());
+ S->setBody(Reader.ReadSubStmt());
+ S->setSwitchLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ SwitchCase *PrevSC = 0;
+ for (unsigned N = Record.size(); Idx != N; ++Idx) {
+ SwitchCase *SC = Reader.getSwitchCaseWithID(Record[Idx]);
+ if (PrevSC)
+ PrevSC->setNextSwitchCase(SC);
+ else
+ S->setSwitchCaseList(SC);
+
+ // Retain this SwitchCase, since SwitchStmt::addSwitchCase() would
+ // normally retain it (but we aren't calling addSwitchCase).
+ SC->Retain();
+ PrevSC = SC;
+ }
+}
+
+void PCHStmtReader::VisitWhileStmt(WhileStmt *S) {
+ VisitStmt(S);
+ S->setConditionVariable(*Reader.getContext(),
+ cast_or_null<VarDecl>(Reader.GetDecl(Record[Idx++])));
+ S->setCond(Reader.ReadSubExpr());
+ S->setBody(Reader.ReadSubStmt());
+ S->setWhileLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+
+void PCHStmtReader::VisitDoStmt(DoStmt *S) {
+ VisitStmt(S);
+ S->setCond(Reader.ReadSubExpr());
+ S->setBody(Reader.ReadSubStmt());
+ S->setDoLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ S->setWhileLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ S->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+
+void PCHStmtReader::VisitForStmt(ForStmt *S) {
+ VisitStmt(S);
+ S->setInit(Reader.ReadSubStmt());
+ S->setCond(Reader.ReadSubExpr());
+ S->setConditionVariable(*Reader.getContext(),
+ cast_or_null<VarDecl>(Reader.GetDecl(Record[Idx++])));
+ S->setInc(Reader.ReadSubExpr());
+ S->setBody(Reader.ReadSubStmt());
+ S->setForLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ S->setLParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ S->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+
+void PCHStmtReader::VisitGotoStmt(GotoStmt *S) {
+ VisitStmt(S);
+ Reader.SetLabelOf(S, Record[Idx++]);
+ S->setGotoLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ S->setLabelLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+
+void PCHStmtReader::VisitIndirectGotoStmt(IndirectGotoStmt *S) {
+ VisitStmt(S);
+ S->setGotoLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ S->setStarLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ S->setTarget(Reader.ReadSubExpr());
+}
+
+void PCHStmtReader::VisitContinueStmt(ContinueStmt *S) {
+ VisitStmt(S);
+ S->setContinueLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+
+void PCHStmtReader::VisitBreakStmt(BreakStmt *S) {
+ VisitStmt(S);
+ S->setBreakLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+
+void PCHStmtReader::VisitReturnStmt(ReturnStmt *S) {
+ VisitStmt(S);
+ S->setRetValue(Reader.ReadSubExpr());
+ S->setReturnLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ S->setNRVOCandidate(cast_or_null<VarDecl>(Reader.GetDecl(Record[Idx++])));
+}
+
+void PCHStmtReader::VisitDeclStmt(DeclStmt *S) {
+ VisitStmt(S);
+ S->setStartLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ S->setEndLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+
+ if (Idx + 1 == Record.size()) {
+ // Single declaration
+ S->setDeclGroup(DeclGroupRef(Reader.GetDecl(Record[Idx++])));
+ } else {
+ llvm::SmallVector<Decl *, 16> Decls;
+ Decls.reserve(Record.size() - Idx);
+ for (unsigned N = Record.size(); Idx != N; ++Idx)
+ Decls.push_back(Reader.GetDecl(Record[Idx]));
+ S->setDeclGroup(DeclGroupRef(DeclGroup::Create(*Reader.getContext(),
+ Decls.data(),
+ Decls.size())));
+ }
+}
+
+void PCHStmtReader::VisitAsmStmt(AsmStmt *S) {
+ VisitStmt(S);
+ unsigned NumOutputs = Record[Idx++];
+ unsigned NumInputs = Record[Idx++];
+ unsigned NumClobbers = Record[Idx++];
+ S->setAsmLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ S->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ S->setVolatile(Record[Idx++]);
+ S->setSimple(Record[Idx++]);
+ S->setMSAsm(Record[Idx++]);
+
+ S->setAsmString(cast_or_null<StringLiteral>(Reader.ReadSubStmt()));
+
+ // Outputs and inputs
+ llvm::SmallVector<IdentifierInfo *, 16> Names;
+ llvm::SmallVector<StringLiteral*, 16> Constraints;
+ llvm::SmallVector<Stmt*, 16> Exprs;
+ for (unsigned I = 0, N = NumOutputs + NumInputs; I != N; ++I) {
+ Names.push_back(Reader.GetIdentifierInfo(Record, Idx));
+ Constraints.push_back(cast_or_null<StringLiteral>(Reader.ReadSubStmt()));
+ Exprs.push_back(Reader.ReadSubStmt());
+ }
+
+ // Constraints
+ llvm::SmallVector<StringLiteral*, 16> Clobbers;
+ for (unsigned I = 0; I != NumClobbers; ++I)
+ Clobbers.push_back(cast_or_null<StringLiteral>(Reader.ReadSubStmt()));
+
+ S->setOutputsAndInputsAndClobbers(*Reader.getContext(),
+ Names.data(), Constraints.data(),
+ Exprs.data(), NumOutputs, NumInputs,
+ Clobbers.data(), NumClobbers);
+}
+
+void PCHStmtReader::VisitExpr(Expr *E) {
+ VisitStmt(E);
+ E->setType(Reader.GetType(Record[Idx++]));
+ E->setTypeDependent(Record[Idx++]);
+ E->setValueDependent(Record[Idx++]);
+ assert(Idx == NumExprFields && "Incorrect expression field count");
+}
+
+void PCHStmtReader::VisitPredefinedExpr(PredefinedExpr *E) {
+ VisitExpr(E);
+ E->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setIdentType((PredefinedExpr::IdentType)Record[Idx++]);
+}
+
+void PCHStmtReader::VisitDeclRefExpr(DeclRefExpr *E) {
+ VisitExpr(E);
+
+ bool HasQualifier = Record[Idx++];
+ unsigned NumTemplateArgs = Record[Idx++];
+
+ E->DecoratedD.setInt((HasQualifier? DeclRefExpr::HasQualifierFlag : 0) |
+ (NumTemplateArgs ? DeclRefExpr::HasExplicitTemplateArgumentListFlag : 0));
+
+ if (HasQualifier) {
+ E->getNameQualifier()->NNS = Reader.ReadNestedNameSpecifier(Record, Idx);
+ E->getNameQualifier()->Range = Reader.ReadSourceRange(Record, Idx);
+ }
+
+ if (NumTemplateArgs)
+ ReadExplicitTemplateArgumentList(*E->getExplicitTemplateArgumentList(),
+ NumTemplateArgs);
+
+ E->setDecl(cast<ValueDecl>(Reader.GetDecl(Record[Idx++])));
+ E->setLocation(Reader.ReadSourceLocation(Record, Idx));
+}
+
+void PCHStmtReader::VisitIntegerLiteral(IntegerLiteral *E) {
+ VisitExpr(E);
+ E->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setValue(Reader.ReadAPInt(Record, Idx));
+}
+
+void PCHStmtReader::VisitFloatingLiteral(FloatingLiteral *E) {
+ VisitExpr(E);
+ E->setValue(Reader.ReadAPFloat(Record, Idx));
+ E->setExact(Record[Idx++]);
+ E->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+
+void PCHStmtReader::VisitImaginaryLiteral(ImaginaryLiteral *E) {
+ VisitExpr(E);
+ E->setSubExpr(Reader.ReadSubExpr());
+}
+
+void PCHStmtReader::VisitStringLiteral(StringLiteral *E) {
+ VisitExpr(E);
+ unsigned Len = Record[Idx++];
+ assert(Record[Idx] == E->getNumConcatenated() &&
+ "Wrong number of concatenated tokens!");
+ ++Idx;
+ E->setWide(Record[Idx++]);
+
+ // Read string data
+ llvm::SmallString<16> Str(&Record[Idx], &Record[Idx] + Len);
+ E->setString(*Reader.getContext(), Str.str());
+ Idx += Len;
+
+ // Read source locations
+ for (unsigned I = 0, N = E->getNumConcatenated(); I != N; ++I)
+ E->setStrTokenLoc(I, SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+
+void PCHStmtReader::VisitCharacterLiteral(CharacterLiteral *E) {
+ VisitExpr(E);
+ E->setValue(Record[Idx++]);
+ E->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setWide(Record[Idx++]);
+}
+
+void PCHStmtReader::VisitParenExpr(ParenExpr *E) {
+ VisitExpr(E);
+ E->setLParen(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setRParen(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setSubExpr(Reader.ReadSubExpr());
+}
+
+void PCHStmtReader::VisitParenListExpr(ParenListExpr *E) {
+ VisitExpr(E);
+ unsigned NumExprs = Record[Idx++];
+ E->Exprs = new (*Reader.getContext()) Stmt*[NumExprs];
+ for (unsigned i = 0; i != NumExprs; ++i)
+ E->Exprs[i] = Reader.ReadSubStmt();
+ E->NumExprs = NumExprs;
+ E->LParenLoc = Reader.ReadSourceLocation(Record, Idx);
+ E->RParenLoc = Reader.ReadSourceLocation(Record, Idx);
+}
+
+void PCHStmtReader::VisitUnaryOperator(UnaryOperator *E) {
+ VisitExpr(E);
+ E->setSubExpr(Reader.ReadSubExpr());
+ E->setOpcode((UnaryOperator::Opcode)Record[Idx++]);
+ E->setOperatorLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+
+void PCHStmtReader::VisitOffsetOfExpr(OffsetOfExpr *E) {
+ typedef OffsetOfExpr::OffsetOfNode Node;
+ VisitExpr(E);
+ assert(E->getNumComponents() == Record[Idx]);
+ ++Idx;
+ assert(E->getNumExpressions() == Record[Idx]);
+ ++Idx;
+ E->setOperatorLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setTypeSourceInfo(Reader.GetTypeSourceInfo(Record, Idx));
+ for (unsigned I = 0, N = E->getNumComponents(); I != N; ++I) {
+ Node::Kind Kind = static_cast<Node::Kind>(Record[Idx++]);
+ SourceLocation Start = SourceLocation::getFromRawEncoding(Record[Idx++]);
+ SourceLocation End = SourceLocation::getFromRawEncoding(Record[Idx++]);
+ switch (Kind) {
+ case Node::Array:
+ E->setComponent(I, Node(Start, Record[Idx++], End));
+ break;
+
+ case Node::Field:
+ E->setComponent(I,
+ Node(Start,
+ dyn_cast_or_null<FieldDecl>(Reader.GetDecl(Record[Idx++])),
+ End));
+ break;
+
+ case Node::Identifier:
+ E->setComponent(I, Node(Start, Reader.GetIdentifier(Record[Idx++]), End));
+ break;
+
+ case Node::Base:
+ // FIXME: Implement this!
+ llvm_unreachable("PCH for offsetof(base-specifier) not implemented");
+ break;
+ }
+ }
+
+ for (unsigned I = 0, N = E->getNumExpressions(); I != N; ++I)
+ E->setIndexExpr(I, Reader.ReadSubExpr());
+}
+
+void PCHStmtReader::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) {
+ VisitExpr(E);
+ E->setSizeof(Record[Idx++]);
+ if (Record[Idx] == 0) {
+ E->setArgument(Reader.ReadSubExpr());
+ ++Idx;
+ } else {
+ E->setArgument(Reader.GetTypeSourceInfo(Record, Idx));
+ }
+ E->setOperatorLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+
+void PCHStmtReader::VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
+ VisitExpr(E);
+ E->setLHS(Reader.ReadSubExpr());
+ E->setRHS(Reader.ReadSubExpr());
+ E->setRBracketLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+
+void PCHStmtReader::VisitCallExpr(CallExpr *E) {
+ VisitExpr(E);
+ E->setNumArgs(*Reader.getContext(), Record[Idx++]);
+ E->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setCallee(Reader.ReadSubExpr());
+ for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I)
+ E->setArg(I, Reader.ReadSubExpr());
+}
+
+void PCHStmtReader::VisitMemberExpr(MemberExpr *E) {
+ // Don't call VisitExpr, this is fully initialized at creation.
+ assert(E->getStmtClass() == Stmt::MemberExprClass &&
+ "It's a subclass, we must advance Idx!");
+}
+
+void PCHStmtReader::VisitObjCIsaExpr(ObjCIsaExpr *E) {
+ VisitExpr(E);
+ E->setBase(Reader.ReadSubExpr());
+ E->setIsaMemberLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setArrow(Record[Idx++]);
+}
+
+void PCHStmtReader::VisitCastExpr(CastExpr *E) {
+ VisitExpr(E);
+ E->setSubExpr(Reader.ReadSubExpr());
+ E->setCastKind((CastExpr::CastKind)Record[Idx++]);
+ CXXBaseSpecifierArray &BasePath = E->getBasePath();
+ unsigned NumBaseSpecs = Record[Idx++];
+ while (NumBaseSpecs--) {
+ // FIXME: These gets leaked.
+ CXXBaseSpecifier *BaseSpec = new (*Reader.getContext()) CXXBaseSpecifier;
+ *BaseSpec = Reader.ReadCXXBaseSpecifier(Record, Idx);
+ BasePath.push_back(BaseSpec);
+ }
+}
+
+void PCHStmtReader::VisitBinaryOperator(BinaryOperator *E) {
+ VisitExpr(E);
+ E->setLHS(Reader.ReadSubExpr());
+ E->setRHS(Reader.ReadSubExpr());
+ E->setOpcode((BinaryOperator::Opcode)Record[Idx++]);
+ E->setOperatorLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+
+void PCHStmtReader::VisitCompoundAssignOperator(CompoundAssignOperator *E) {
+ VisitBinaryOperator(E);
+ E->setComputationLHSType(Reader.GetType(Record[Idx++]));
+ E->setComputationResultType(Reader.GetType(Record[Idx++]));
+}
+
+void PCHStmtReader::VisitConditionalOperator(ConditionalOperator *E) {
+ VisitExpr(E);
+ E->setCond(Reader.ReadSubExpr());
+ E->setLHS(Reader.ReadSubExpr());
+ E->setRHS(Reader.ReadSubExpr());
+ E->setQuestionLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setColonLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+
+void PCHStmtReader::VisitImplicitCastExpr(ImplicitCastExpr *E) {
+ VisitCastExpr(E);
+ E->setLvalueCast(Record[Idx++]);
+}
+
+void PCHStmtReader::VisitExplicitCastExpr(ExplicitCastExpr *E) {
+ VisitCastExpr(E);
+ E->setTypeInfoAsWritten(Reader.GetTypeSourceInfo(Record, Idx));
+}
+
+void PCHStmtReader::VisitCStyleCastExpr(CStyleCastExpr *E) {
+ VisitExplicitCastExpr(E);
+ E->setLParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+
+void PCHStmtReader::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) {
+ VisitExpr(E);
+ E->setLParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setTypeSourceInfo(Reader.GetTypeSourceInfo(Record, Idx));
+ E->setInitializer(Reader.ReadSubExpr());
+ E->setFileScope(Record[Idx++]);
+}
+
+void PCHStmtReader::VisitExtVectorElementExpr(ExtVectorElementExpr *E) {
+ VisitExpr(E);
+ E->setBase(Reader.ReadSubExpr());
+ E->setAccessor(Reader.GetIdentifierInfo(Record, Idx));
+ E->setAccessorLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+
+void PCHStmtReader::VisitInitListExpr(InitListExpr *E) {
+ VisitExpr(E);
+ unsigned NumInits = Record[Idx++];
+ E->reserveInits(*Reader.getContext(), NumInits);
+ for (unsigned I = 0; I != NumInits; ++I)
+ E->updateInit(*Reader.getContext(), I, Reader.ReadSubExpr());
+ E->setSyntacticForm(cast_or_null<InitListExpr>(Reader.ReadSubStmt()));
+ E->setLBraceLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setRBraceLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setInitializedFieldInUnion(
+ cast_or_null<FieldDecl>(Reader.GetDecl(Record[Idx++])));
+ E->sawArrayRangeDesignator(Record[Idx++]);
+}
+
+void PCHStmtReader::VisitDesignatedInitExpr(DesignatedInitExpr *E) {
+ typedef DesignatedInitExpr::Designator Designator;
+
+ VisitExpr(E);
+ unsigned NumSubExprs = Record[Idx++];
+ assert(NumSubExprs == E->getNumSubExprs() && "Wrong number of subexprs");
+ for (unsigned I = 0; I != NumSubExprs; ++I)
+ E->setSubExpr(I, Reader.ReadSubExpr());
+ E->setEqualOrColonLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setGNUSyntax(Record[Idx++]);
+
+ llvm::SmallVector<Designator, 4> Designators;
+ while (Idx < Record.size()) {
+ switch ((pch::DesignatorTypes)Record[Idx++]) {
+ case pch::DESIG_FIELD_DECL: {
+ FieldDecl *Field = cast<FieldDecl>(Reader.GetDecl(Record[Idx++]));
+ SourceLocation DotLoc
+ = SourceLocation::getFromRawEncoding(Record[Idx++]);
+ SourceLocation FieldLoc
+ = SourceLocation::getFromRawEncoding(Record[Idx++]);
+ Designators.push_back(Designator(Field->getIdentifier(), DotLoc,
+ FieldLoc));
+ Designators.back().setField(Field);
+ break;
+ }
+
+ case pch::DESIG_FIELD_NAME: {
+ const IdentifierInfo *Name = Reader.GetIdentifierInfo(Record, Idx);
+ SourceLocation DotLoc
+ = SourceLocation::getFromRawEncoding(Record[Idx++]);
+ SourceLocation FieldLoc
+ = SourceLocation::getFromRawEncoding(Record[Idx++]);
+ Designators.push_back(Designator(Name, DotLoc, FieldLoc));
+ break;
+ }
+
+ case pch::DESIG_ARRAY: {
+ unsigned Index = Record[Idx++];
+ SourceLocation LBracketLoc
+ = SourceLocation::getFromRawEncoding(Record[Idx++]);
+ SourceLocation RBracketLoc
+ = SourceLocation::getFromRawEncoding(Record[Idx++]);
+ Designators.push_back(Designator(Index, LBracketLoc, RBracketLoc));
+ break;
+ }
+
+ case pch::DESIG_ARRAY_RANGE: {
+ unsigned Index = Record[Idx++];
+ SourceLocation LBracketLoc
+ = SourceLocation::getFromRawEncoding(Record[Idx++]);
+ SourceLocation EllipsisLoc
+ = SourceLocation::getFromRawEncoding(Record[Idx++]);
+ SourceLocation RBracketLoc
+ = SourceLocation::getFromRawEncoding(Record[Idx++]);
+ Designators.push_back(Designator(Index, LBracketLoc, EllipsisLoc,
+ RBracketLoc));
+ break;
+ }
+ }
+ }
+ E->setDesignators(*Reader.getContext(),
+ Designators.data(), Designators.size());
+}
+
+void PCHStmtReader::VisitImplicitValueInitExpr(ImplicitValueInitExpr *E) {
+ VisitExpr(E);
+}
+
+void PCHStmtReader::VisitVAArgExpr(VAArgExpr *E) {
+ VisitExpr(E);
+ E->setSubExpr(Reader.ReadSubExpr());
+ E->setBuiltinLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+
+void PCHStmtReader::VisitAddrLabelExpr(AddrLabelExpr *E) {
+ VisitExpr(E);
+ E->setAmpAmpLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setLabelLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ Reader.SetLabelOf(E, Record[Idx++]);
+}
+
+void PCHStmtReader::VisitStmtExpr(StmtExpr *E) {
+ VisitExpr(E);
+ E->setLParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setSubStmt(cast_or_null<CompoundStmt>(Reader.ReadSubStmt()));
+}
+
+void PCHStmtReader::VisitTypesCompatibleExpr(TypesCompatibleExpr *E) {
+ VisitExpr(E);
+ E->setArgType1(Reader.GetType(Record[Idx++]));
+ E->setArgType2(Reader.GetType(Record[Idx++]));
+ E->setBuiltinLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+
+void PCHStmtReader::VisitChooseExpr(ChooseExpr *E) {
+ VisitExpr(E);
+ E->setCond(Reader.ReadSubExpr());
+ E->setLHS(Reader.ReadSubExpr());
+ E->setRHS(Reader.ReadSubExpr());
+ E->setBuiltinLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+
+void PCHStmtReader::VisitGNUNullExpr(GNUNullExpr *E) {
+ VisitExpr(E);
+ E->setTokenLocation(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+
+void PCHStmtReader::VisitShuffleVectorExpr(ShuffleVectorExpr *E) {
+ VisitExpr(E);
+ llvm::SmallVector<Expr *, 16> Exprs;
+ unsigned NumExprs = Record[Idx++];
+ while (NumExprs--)
+ Exprs.push_back(Reader.ReadSubExpr());
+ E->setExprs(*Reader.getContext(), Exprs.data(), Exprs.size());
+ E->setBuiltinLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+
+void PCHStmtReader::VisitBlockExpr(BlockExpr *E) {
+ VisitExpr(E);
+ E->setBlockDecl(cast_or_null<BlockDecl>(Reader.GetDecl(Record[Idx++])));
+ E->setHasBlockDeclRefExprs(Record[Idx++]);
+}
+
+void PCHStmtReader::VisitBlockDeclRefExpr(BlockDeclRefExpr *E) {
+ VisitExpr(E);
+ E->setDecl(cast<ValueDecl>(Reader.GetDecl(Record[Idx++])));
+ E->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setByRef(Record[Idx++]);
+ E->setConstQualAdded(Record[Idx++]);
+ E->setCopyConstructorExpr(Reader.ReadSubExpr());
+}
+
+//===----------------------------------------------------------------------===//
+// Objective-C Expressions and Statements
+
+void PCHStmtReader::VisitObjCStringLiteral(ObjCStringLiteral *E) {
+ VisitExpr(E);
+ E->setString(cast<StringLiteral>(Reader.ReadSubStmt()));
+ E->setAtLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+
+void PCHStmtReader::VisitObjCEncodeExpr(ObjCEncodeExpr *E) {
+ VisitExpr(E);
+ E->setEncodedTypeSourceInfo(Reader.GetTypeSourceInfo(Record, Idx));
+ E->setAtLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+
+void PCHStmtReader::VisitObjCSelectorExpr(ObjCSelectorExpr *E) {
+ VisitExpr(E);
+ E->setSelector(Reader.GetSelector(Record, Idx));
+ E->setAtLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+
+void PCHStmtReader::VisitObjCProtocolExpr(ObjCProtocolExpr *E) {
+ VisitExpr(E);
+ E->setProtocol(cast<ObjCProtocolDecl>(Reader.GetDecl(Record[Idx++])));
+ E->setAtLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+
+void PCHStmtReader::VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) {
+ VisitExpr(E);
+ E->setDecl(cast<ObjCIvarDecl>(Reader.GetDecl(Record[Idx++])));
+ E->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setBase(Reader.ReadSubExpr());
+ E->setIsArrow(Record[Idx++]);
+ E->setIsFreeIvar(Record[Idx++]);
+}
+
+void PCHStmtReader::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E) {
+ VisitExpr(E);
+ E->setProperty(cast<ObjCPropertyDecl>(Reader.GetDecl(Record[Idx++])));
+ E->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setBase(Reader.ReadSubExpr());
+}
+
+void PCHStmtReader::VisitObjCImplicitSetterGetterRefExpr(
+ ObjCImplicitSetterGetterRefExpr *E) {
+ VisitExpr(E);
+ E->setGetterMethod(
+ cast_or_null<ObjCMethodDecl>(Reader.GetDecl(Record[Idx++])));
+ E->setSetterMethod(
+ cast_or_null<ObjCMethodDecl>(Reader.GetDecl(Record[Idx++])));
+ E->setInterfaceDecl(
+ cast_or_null<ObjCInterfaceDecl>(Reader.GetDecl(Record[Idx++])));
+ E->setBase(Reader.ReadSubExpr());
+ E->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setClassLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+
+void PCHStmtReader::VisitObjCMessageExpr(ObjCMessageExpr *E) {
+ VisitExpr(E);
+ assert(Record[Idx] == E->getNumArgs());
+ ++Idx;
+ ObjCMessageExpr::ReceiverKind Kind
+ = static_cast<ObjCMessageExpr::ReceiverKind>(Record[Idx++]);
+ switch (Kind) {
+ case ObjCMessageExpr::Instance:
+ E->setInstanceReceiver(Reader.ReadSubExpr());
+ break;
+
+ case ObjCMessageExpr::Class:
+ E->setClassReceiver(Reader.GetTypeSourceInfo(Record, Idx));
+ break;
+
+ case ObjCMessageExpr::SuperClass:
+ case ObjCMessageExpr::SuperInstance: {
+ QualType T = Reader.GetType(Record[Idx++]);
+ SourceLocation SuperLoc = SourceLocation::getFromRawEncoding(Record[Idx++]);
+ E->setSuper(SuperLoc, T, Kind == ObjCMessageExpr::SuperInstance);
+ break;
+ }
+ }
+
+ assert(Kind == E->getReceiverKind());
+
+ if (Record[Idx++])
+ E->setMethodDecl(cast_or_null<ObjCMethodDecl>(Reader.GetDecl(Record[Idx++])));
+ else
+ E->setSelector(Reader.GetSelector(Record, Idx));
+
+ E->setLeftLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setRightLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+
+ for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I)
+ E->setArg(I, Reader.ReadSubExpr());
+}
+
+void PCHStmtReader::VisitObjCSuperExpr(ObjCSuperExpr *E) {
+ VisitExpr(E);
+ E->setLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+
+void PCHStmtReader::VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) {
+ VisitStmt(S);
+ S->setElement(Reader.ReadSubStmt());
+ S->setCollection(Reader.ReadSubExpr());
+ S->setBody(Reader.ReadSubStmt());
+ S->setForLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ S->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+
+void PCHStmtReader::VisitObjCAtCatchStmt(ObjCAtCatchStmt *S) {
+ VisitStmt(S);
+ S->setCatchBody(Reader.ReadSubStmt());
+ S->setCatchParamDecl(cast_or_null<VarDecl>(Reader.GetDecl(Record[Idx++])));
+ S->setAtCatchLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ S->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+
+void PCHStmtReader::VisitObjCAtFinallyStmt(ObjCAtFinallyStmt *S) {
+ VisitStmt(S);
+ S->setFinallyBody(Reader.ReadSubStmt());
+ S->setAtFinallyLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+
+void PCHStmtReader::VisitObjCAtTryStmt(ObjCAtTryStmt *S) {
+ VisitStmt(S);
+ assert(Record[Idx] == S->getNumCatchStmts());
+ ++Idx;
+ bool HasFinally = Record[Idx++];
+ S->setTryBody(Reader.ReadSubStmt());
+ for (unsigned I = 0, N = S->getNumCatchStmts(); I != N; ++I)
+ S->setCatchStmt(I, cast_or_null<ObjCAtCatchStmt>(Reader.ReadSubStmt()));
+
+ if (HasFinally)
+ S->setFinallyStmt(Reader.ReadSubStmt());
+ S->setAtTryLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+
+void PCHStmtReader::VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *S) {
+ VisitStmt(S);
+ S->setSynchExpr(Reader.ReadSubStmt());
+ S->setSynchBody(Reader.ReadSubStmt());
+ S->setAtSynchronizedLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+
+void PCHStmtReader::VisitObjCAtThrowStmt(ObjCAtThrowStmt *S) {
+ VisitStmt(S);
+ S->setThrowExpr(Reader.ReadSubStmt());
+ S->setThrowLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+
+//===----------------------------------------------------------------------===//
+// C++ Expressions and Statements
+
+void PCHStmtReader::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
+ VisitCallExpr(E);
+ E->setOperator((OverloadedOperatorKind)Record[Idx++]);
+}
+
+void PCHStmtReader::VisitCXXConstructExpr(CXXConstructExpr *E) {
+ VisitExpr(E);
+ E->NumArgs = Record[Idx++];
+ if (E->NumArgs)
+ E->Args = new (*Reader.getContext()) Stmt*[E->NumArgs];
+ for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I)
+ E->setArg(I, Reader.ReadSubExpr());
+ E->setConstructor(cast<CXXConstructorDecl>(Reader.GetDecl(Record[Idx++])));
+ E->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setElidable(Record[Idx++]);
+ E->setRequiresZeroInitialization(Record[Idx++]);
+ E->setConstructionKind((CXXConstructExpr::ConstructionKind)Record[Idx++]);
+}
+
+void PCHStmtReader::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *E) {
+ VisitCXXConstructExpr(E);
+ E->TyBeginLoc = Reader.ReadSourceLocation(Record, Idx);
+ E->RParenLoc = Reader.ReadSourceLocation(Record, Idx);
+}
+
+void PCHStmtReader::VisitCXXNamedCastExpr(CXXNamedCastExpr *E) {
+ VisitExplicitCastExpr(E);
+ E->setOperatorLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+
+void PCHStmtReader::VisitCXXStaticCastExpr(CXXStaticCastExpr *E) {
+ return VisitCXXNamedCastExpr(E);
+}
+
+void PCHStmtReader::VisitCXXDynamicCastExpr(CXXDynamicCastExpr *E) {
+ return VisitCXXNamedCastExpr(E);
+}
+
+void PCHStmtReader::VisitCXXReinterpretCastExpr(CXXReinterpretCastExpr *E) {
+ return VisitCXXNamedCastExpr(E);
+}
+
+void PCHStmtReader::VisitCXXConstCastExpr(CXXConstCastExpr *E) {
+ return VisitCXXNamedCastExpr(E);
+}
+
+void PCHStmtReader::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E) {
+ VisitExplicitCastExpr(E);
+ E->setTypeBeginLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+
+void PCHStmtReader::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E) {
+ VisitExpr(E);
+ E->setValue(Record[Idx++]);
+ E->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+
+void PCHStmtReader::VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *E) {
+ VisitExpr(E);
+ E->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+
+void PCHStmtReader::VisitCXXTypeidExpr(CXXTypeidExpr *E) {
+ VisitExpr(E);
+ E->setSourceRange(Reader.ReadSourceRange(Record, Idx));
+ if (E->isTypeOperand()) { // typeid(int)
+ E->setTypeOperandSourceInfo(Reader.GetTypeSourceInfo(Record, Idx));
+ return;
+ }
+
+ // typeid(42+2)
+ E->setExprOperand(Reader.ReadSubExpr());
+}
+
+void PCHStmtReader::VisitCXXThisExpr(CXXThisExpr *E) {
+ VisitExpr(E);
+ E->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setImplicit(Record[Idx++]);
+}
+
+void PCHStmtReader::VisitCXXThrowExpr(CXXThrowExpr *E) {
+ VisitExpr(E);
+ E->setThrowLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setSubExpr(Reader.ReadSubExpr());
+}
+
+void PCHStmtReader::VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) {
+ VisitExpr(E);
+
+ assert(Record[Idx] == E->Param.getInt() && "We messed up at creation ?");
+ ++Idx; // HasOtherExprStored and SubExpr was handled during creation.
+ E->Param.setPointer(cast<ParmVarDecl>(Reader.GetDecl(Record[Idx++])));
+ E->Loc = Reader.ReadSourceLocation(Record, Idx);
+}
+
+void PCHStmtReader::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) {
+ VisitExpr(E);
+ E->setTemporary(Reader.ReadCXXTemporary(Record, Idx));
+ E->setSubExpr(Reader.ReadSubExpr());
+}
+
+void PCHStmtReader::VisitCXXBindReferenceExpr(CXXBindReferenceExpr *E) {
+ VisitExpr(E);
+ E->SubExpr = Reader.ReadSubExpr();
+ E->ExtendsLifetime = Record[Idx++];
+ E->RequiresTemporaryCopy = Record[Idx++];
+}
+
+void PCHStmtReader::VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E) {
+ VisitExpr(E);
+ E->setTypeBeginLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+
+void PCHStmtReader::VisitCXXNewExpr(CXXNewExpr *E) {
+ VisitExpr(E);
+ E->setGlobalNew(Record[Idx++]);
+ E->setHasInitializer(Record[Idx++]);
+ bool isArray = Record[Idx++];
+ unsigned NumPlacementArgs = Record[Idx++];
+ unsigned NumCtorArgs = Record[Idx++];
+ E->setOperatorNew(cast_or_null<FunctionDecl>(Reader.GetDecl(Record[Idx++])));
+ E->setOperatorDelete(
+ cast_or_null<FunctionDecl>(Reader.GetDecl(Record[Idx++])));
+ E->setConstructor(
+ cast_or_null<CXXConstructorDecl>(Reader.GetDecl(Record[Idx++])));
+ SourceRange TypeIdParens;
+ TypeIdParens.setBegin(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ TypeIdParens.setEnd(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->TypeIdParens = TypeIdParens;
+ E->setStartLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setEndLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+
+ E->AllocateArgsArray(*Reader.getContext(), isArray, NumPlacementArgs,
+ NumCtorArgs);
+
+ // Install all the subexpressions.
+ for (CXXNewExpr::raw_arg_iterator I = E->raw_arg_begin(),e = E->raw_arg_end();
+ I != e; ++I)
+ *I = Reader.ReadSubStmt();
+}
+
+void PCHStmtReader::VisitCXXDeleteExpr(CXXDeleteExpr *E) {
+ VisitExpr(E);
+ E->setGlobalDelete(Record[Idx++]);
+ E->setArrayForm(Record[Idx++]);
+ E->setOperatorDelete(
+ cast_or_null<FunctionDecl>(Reader.GetDecl(Record[Idx++])));
+ E->setArgument(Reader.ReadSubExpr());
+ E->setStartLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+
+void PCHStmtReader::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E) {
+ VisitExpr(E);
+
+ E->setBase(Reader.ReadSubExpr());
+ E->setArrow(Record[Idx++]);
+ E->setOperatorLoc(Reader.ReadSourceLocation(Record, Idx));
+ E->setQualifier(Reader.ReadNestedNameSpecifier(Record, Idx));
+ E->setQualifierRange(Reader.ReadSourceRange(Record, Idx));
+ E->setScopeTypeInfo(Reader.GetTypeSourceInfo(Record, Idx));
+ E->setColonColonLoc(Reader.ReadSourceLocation(Record, Idx));
+ E->setTildeLoc(Reader.ReadSourceLocation(Record, Idx));
+
+ IdentifierInfo *II = Reader.GetIdentifierInfo(Record, Idx);
+ if (II)
+ E->setDestroyedType(II, Reader.ReadSourceLocation(Record, Idx));
+ else
+ E->setDestroyedType(Reader.GetTypeSourceInfo(Record, Idx));
+}
+
+void PCHStmtReader::VisitCXXExprWithTemporaries(CXXExprWithTemporaries *E) {
+ VisitExpr(E);
+ unsigned NumTemps = Record[Idx++];
+ if (NumTemps) {
+ E->setNumTemporaries(*Reader.getContext(), NumTemps);
+ for (unsigned i = 0; i != NumTemps; ++i)
+ E->setTemporary(i, Reader.ReadCXXTemporary(Record, Idx));
+ }
+ E->setSubExpr(Reader.ReadSubExpr());
+}
+
+void
+PCHStmtReader::VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E){
+ VisitExpr(E);
+
+ unsigned NumTemplateArgs = Record[Idx++];
+ assert((NumTemplateArgs != 0) == E->hasExplicitTemplateArgs() &&
+ "Read wrong record during creation ?");
+ if (E->hasExplicitTemplateArgs())
+ ReadExplicitTemplateArgumentList(*E->getExplicitTemplateArgumentList(),
+ NumTemplateArgs);
+
+ E->setBase(Reader.ReadSubExpr());
+ E->setBaseType(Reader.GetType(Record[Idx++]));
+ E->setArrow(Record[Idx++]);
+ E->setOperatorLoc(Reader.ReadSourceLocation(Record, Idx));
+ E->setQualifier(Reader.ReadNestedNameSpecifier(Record, Idx));
+ E->setQualifierRange(Reader.ReadSourceRange(Record, Idx));
+ E->setFirstQualifierFoundInScope(
+ cast_or_null<NamedDecl>(Reader.GetDecl(Record[Idx++])));
+ E->setMember(Reader.ReadDeclarationName(Record, Idx));
+ E->setMemberLoc(Reader.ReadSourceLocation(Record, Idx));
+}
+
+void
+PCHStmtReader::VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E) {
+ VisitExpr(E);
+
+ unsigned NumTemplateArgs = Record[Idx++];
+ assert((NumTemplateArgs != 0) == E->hasExplicitTemplateArgs() &&
+ "Read wrong record during creation ?");
+ if (E->hasExplicitTemplateArgs())
+ ReadExplicitTemplateArgumentList(E->getExplicitTemplateArgs(),
+ NumTemplateArgs);
+
+ E->setDeclName(Reader.ReadDeclarationName(Record, Idx));
+ E->setLocation(Reader.ReadSourceLocation(Record, Idx));
+ E->setQualifierRange(Reader.ReadSourceRange(Record, Idx));
+ E->setQualifier(Reader.ReadNestedNameSpecifier(Record, Idx));
+}
+
+void
+PCHStmtReader::VisitCXXUnresolvedConstructExpr(CXXUnresolvedConstructExpr *E) {
+ VisitExpr(E);
+ assert(Record[Idx] == E->arg_size() && "Read wrong record during creation ?");
+ ++Idx; // NumArgs;
+ for (unsigned I = 0, N = E->arg_size(); I != N; ++I)
+ E->setArg(I, Reader.ReadSubExpr());
+ E->setTypeBeginLoc(Reader.ReadSourceLocation(Record, Idx));
+ E->setTypeAsWritten(Reader.GetType(Record[Idx++]));
+ E->setLParenLoc(Reader.ReadSourceLocation(Record, Idx));
+ E->setRParenLoc(Reader.ReadSourceLocation(Record, Idx));
+}
+
+void PCHStmtReader::VisitOverloadExpr(OverloadExpr *E) {
+ VisitExpr(E);
+
+ unsigned NumTemplateArgs = Record[Idx++];
+ assert((NumTemplateArgs != 0) == E->hasExplicitTemplateArgs() &&
+ "Read wrong record during creation ?");
+ if (E->hasExplicitTemplateArgs())
+ ReadExplicitTemplateArgumentList(E->getExplicitTemplateArgs(),
+ NumTemplateArgs);
+
+ unsigned NumDecls = Record[Idx++];
+ UnresolvedSet<8> Decls;
+ for (unsigned i = 0; i != NumDecls; ++i) {
+ NamedDecl *D = cast<NamedDecl>(Reader.GetDecl(Record[Idx++]));
+ AccessSpecifier AS = (AccessSpecifier)Record[Idx++];
+ Decls.addDecl(D, AS);
+ }
+ E->initializeResults(*Reader.getContext(), Decls.begin(), Decls.end());
+
+ E->setName(Reader.ReadDeclarationName(Record, Idx));
+ E->setQualifier(Reader.ReadNestedNameSpecifier(Record, Idx));
+ E->setQualifierRange(Reader.ReadSourceRange(Record, Idx));
+ E->setNameLoc(Reader.ReadSourceLocation(Record, Idx));
+}
+
+void PCHStmtReader::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *E) {
+ VisitOverloadExpr(E);
+ E->setArrow(Record[Idx++]);
+ E->setHasUnresolvedUsing(Record[Idx++]);
+ E->setBase(Reader.ReadSubExpr());
+ E->setBaseType(Reader.GetType(Record[Idx++]));
+ E->setOperatorLoc(Reader.ReadSourceLocation(Record, Idx));
+}
+
+void PCHStmtReader::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *E) {
+ VisitOverloadExpr(E);
+ E->setRequiresADL(Record[Idx++]);
+ E->setOverloaded(Record[Idx++]);
+ E->setNamingClass(cast_or_null<CXXRecordDecl>(Reader.GetDecl(Record[Idx++])));
+}
+
+void PCHStmtReader::VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *E) {
+ VisitExpr(E);
+ E->UTT = (UnaryTypeTrait)Record[Idx++];
+ SourceRange Range = Reader.ReadSourceRange(Record, Idx);
+ E->Loc = Range.getBegin();
+ E->RParen = Range.getEnd();
+ E->QueriedType = Reader.GetType(Record[Idx++]);
+}
+
+Stmt *PCHReader::ReadStmt() {
+ switch (ReadingKind) {
+ case Read_Decl:
+ case Read_Type:
+ // Read a statement from the current DeclCursor.
+ return ReadStmtFromStream(DeclsCursor);
+ case Read_Stmt:
+ return ReadSubStmt();
+ }
+
+ llvm_unreachable("ReadingKind not set ?");
+ return 0;
+}
+
+Expr *PCHReader::ReadExpr() {
+ return cast_or_null<Expr>(ReadStmt());
+}
+
+Expr *PCHReader::ReadSubExpr() {
+ return cast_or_null<Expr>(ReadSubStmt());
+}
+
+// Within the bitstream, expressions are stored in Reverse Polish
+// Notation, with each of the subexpressions preceding the
+// expression they are stored in. Subexpressions are stored from last to first.
+// To evaluate expressions, we continue reading expressions and placing them on
+// the stack, with expressions having operands removing those operands from the
+// stack. Evaluation terminates when we see a STMT_STOP record, and
+// the single remaining expression on the stack is our result.
+Stmt *PCHReader::ReadStmtFromStream(llvm::BitstreamCursor &Cursor) {
+
+ ReadingKindTracker ReadingKind(Read_Stmt, *this);
+
+#ifndef NDEBUG
+ unsigned PrevNumStmts = StmtStack.size();
+#endif
+
+ RecordData Record;
+ unsigned Idx;
+ PCHStmtReader Reader(*this, Record, Idx);
+ Stmt::EmptyShell Empty;
+
+ while (true) {
+ unsigned Code = Cursor.ReadCode();
+ if (Code == llvm::bitc::END_BLOCK) {
+ if (Cursor.ReadBlockEnd()) {
+ Error("error at end of block in PCH file");
+ return 0;
+ }
+ break;
+ }
+
+ if (Code == llvm::bitc::ENTER_SUBBLOCK) {
+ // No known subblocks, always skip them.
+ Cursor.ReadSubBlockID();
+ if (Cursor.SkipBlock()) {
+ Error("malformed block record in PCH file");
+ return 0;
+ }
+ continue;
+ }
+
+ if (Code == llvm::bitc::DEFINE_ABBREV) {
+ Cursor.ReadAbbrevRecord();
+ continue;
+ }
+
+ Stmt *S = 0;
+ Idx = 0;
+ Record.clear();
+ bool Finished = false;
+ switch ((pch::StmtCode)Cursor.ReadRecord(Code, Record)) {
+ case pch::STMT_STOP:
+ Finished = true;
+ break;
+
+ case pch::STMT_NULL_PTR:
+ S = 0;
+ break;
+
+ case pch::STMT_NULL:
+ S = new (Context) NullStmt(Empty);
+ break;
+
+ case pch::STMT_COMPOUND:
+ S = new (Context) CompoundStmt(Empty);
+ break;
+
+ case pch::STMT_CASE:
+ S = new (Context) CaseStmt(Empty);
+ break;
+
+ case pch::STMT_DEFAULT:
+ S = new (Context) DefaultStmt(Empty);
+ break;
+
+ case pch::STMT_LABEL:
+ S = new (Context) LabelStmt(Empty);
+ break;
+
+ case pch::STMT_IF:
+ S = new (Context) IfStmt(Empty);
+ break;
+
+ case pch::STMT_SWITCH:
+ S = new (Context) SwitchStmt(Empty);
+ break;
+
+ case pch::STMT_WHILE:
+ S = new (Context) WhileStmt(Empty);
+ break;
+
+ case pch::STMT_DO:
+ S = new (Context) DoStmt(Empty);
+ break;
+
+ case pch::STMT_FOR:
+ S = new (Context) ForStmt(Empty);
+ break;
+
+ case pch::STMT_GOTO:
+ S = new (Context) GotoStmt(Empty);
+ break;
+
+ case pch::STMT_INDIRECT_GOTO:
+ S = new (Context) IndirectGotoStmt(Empty);
+ break;
+
+ case pch::STMT_CONTINUE:
+ S = new (Context) ContinueStmt(Empty);
+ break;
+
+ case pch::STMT_BREAK:
+ S = new (Context) BreakStmt(Empty);
+ break;
+
+ case pch::STMT_RETURN:
+ S = new (Context) ReturnStmt(Empty);
+ break;
+
+ case pch::STMT_DECL:
+ S = new (Context) DeclStmt(Empty);
+ break;
+
+ case pch::STMT_ASM:
+ S = new (Context) AsmStmt(Empty);
+ break;
+
+ case pch::EXPR_PREDEFINED:
+ S = new (Context) PredefinedExpr(Empty);
+ break;
+
+ case pch::EXPR_DECL_REF:
+ S = DeclRefExpr::CreateEmpty(*Context,
+ /*HasQualifier=*/Record[PCHStmtReader::NumExprFields],
+ /*NumTemplateArgs=*/Record[PCHStmtReader::NumExprFields + 1]);
+ break;
+
+ case pch::EXPR_INTEGER_LITERAL:
+ S = new (Context) IntegerLiteral(Empty);
+ break;
+
+ case pch::EXPR_FLOATING_LITERAL:
+ S = new (Context) FloatingLiteral(Empty);
+ break;
+
+ case pch::EXPR_IMAGINARY_LITERAL:
+ S = new (Context) ImaginaryLiteral(Empty);
+ break;
+
+ case pch::EXPR_STRING_LITERAL:
+ S = StringLiteral::CreateEmpty(*Context,
+ Record[PCHStmtReader::NumExprFields + 1]);
+ break;
+
+ case pch::EXPR_CHARACTER_LITERAL:
+ S = new (Context) CharacterLiteral(Empty);
+ break;
+
+ case pch::EXPR_PAREN:
+ S = new (Context) ParenExpr(Empty);
+ break;
+
+ case pch::EXPR_PAREN_LIST:
+ S = new (Context) ParenListExpr(Empty);
+ break;
+
+ case pch::EXPR_UNARY_OPERATOR:
+ S = new (Context) UnaryOperator(Empty);
+ break;
+
+ case pch::EXPR_OFFSETOF:
+ S = OffsetOfExpr::CreateEmpty(*Context,
+ Record[PCHStmtReader::NumExprFields],
+ Record[PCHStmtReader::NumExprFields + 1]);
+ break;
+
+ case pch::EXPR_SIZEOF_ALIGN_OF:
+ S = new (Context) SizeOfAlignOfExpr(Empty);
+ break;
+
+ case pch::EXPR_ARRAY_SUBSCRIPT:
+ S = new (Context) ArraySubscriptExpr(Empty);
+ break;
+
+ case pch::EXPR_CALL:
+ S = new (Context) CallExpr(*Context, Stmt::CallExprClass, Empty);
+ break;
+
+ case pch::EXPR_MEMBER: {
+ // We load everything here and fully initialize it at creation.
+ // That way we can use MemberExpr::Create and don't have to duplicate its
+ // logic with a MemberExpr::CreateEmpty.
+
+ assert(Idx == 0);
+ NestedNameSpecifier *NNS = 0;
+ SourceRange QualifierRange;
+ if (Record[Idx++]) { // HasQualifier.
+ NNS = ReadNestedNameSpecifier(Record, Idx);
+ QualifierRange = ReadSourceRange(Record, Idx);
+ }
+
+ TemplateArgumentListInfo ArgInfo;
+ unsigned NumTemplateArgs = Record[Idx++];
+ if (NumTemplateArgs) {
+ ArgInfo.setLAngleLoc(ReadSourceLocation(Record, Idx));
+ ArgInfo.setRAngleLoc(ReadSourceLocation(Record, Idx));
+ for (unsigned i = 0; i != NumTemplateArgs; ++i)
+ ArgInfo.addArgument(ReadTemplateArgumentLoc(Record, Idx));
+ }
+
+ NamedDecl *FoundD = cast_or_null<NamedDecl>(GetDecl(Record[Idx++]));
+ AccessSpecifier AS = (AccessSpecifier)Record[Idx++];
+ DeclAccessPair FoundDecl = DeclAccessPair::make(FoundD, AS);
+
+ QualType T = GetType(Record[Idx++]);
+ Expr *Base = ReadSubExpr();
+ ValueDecl *MemberD = cast<ValueDecl>(GetDecl(Record[Idx++]));
+ SourceLocation MemberLoc = ReadSourceLocation(Record, Idx);
+ bool IsArrow = Record[Idx++];
+
+ S = MemberExpr::Create(*Context, Base, IsArrow, NNS, QualifierRange,
+ MemberD, FoundDecl, MemberLoc,
+ NumTemplateArgs ? &ArgInfo : 0, T);
+ break;
+ }
+
+ case pch::EXPR_BINARY_OPERATOR:
+ S = new (Context) BinaryOperator(Empty);
+ break;
+
+ case pch::EXPR_COMPOUND_ASSIGN_OPERATOR:
+ S = new (Context) CompoundAssignOperator(Empty);
+ break;
+
+ case pch::EXPR_CONDITIONAL_OPERATOR:
+ S = new (Context) ConditionalOperator(Empty);
+ break;
+
+ case pch::EXPR_IMPLICIT_CAST:
+ S = new (Context) ImplicitCastExpr(Empty);
+ break;
+
+ case pch::EXPR_CSTYLE_CAST:
+ S = new (Context) CStyleCastExpr(Empty);
+ break;
+
+ case pch::EXPR_COMPOUND_LITERAL:
+ S = new (Context) CompoundLiteralExpr(Empty);
+ break;
+
+ case pch::EXPR_EXT_VECTOR_ELEMENT:
+ S = new (Context) ExtVectorElementExpr(Empty);
+ break;
+
+ case pch::EXPR_INIT_LIST:
+ S = new (Context) InitListExpr(*getContext(), Empty);
+ break;
+
+ case pch::EXPR_DESIGNATED_INIT:
+ S = DesignatedInitExpr::CreateEmpty(*Context,
+ Record[PCHStmtReader::NumExprFields] - 1);
+
+ break;
+
+ case pch::EXPR_IMPLICIT_VALUE_INIT:
+ S = new (Context) ImplicitValueInitExpr(Empty);
+ break;
+
+ case pch::EXPR_VA_ARG:
+ S = new (Context) VAArgExpr(Empty);
+ break;
+
+ case pch::EXPR_ADDR_LABEL:
+ S = new (Context) AddrLabelExpr(Empty);
+ break;
+
+ case pch::EXPR_STMT:
+ S = new (Context) StmtExpr(Empty);
+ break;
+
+ case pch::EXPR_TYPES_COMPATIBLE:
+ S = new (Context) TypesCompatibleExpr(Empty);
+ break;
+
+ case pch::EXPR_CHOOSE:
+ S = new (Context) ChooseExpr(Empty);
+ break;
+
+ case pch::EXPR_GNU_NULL:
+ S = new (Context) GNUNullExpr(Empty);
+ break;
+
+ case pch::EXPR_SHUFFLE_VECTOR:
+ S = new (Context) ShuffleVectorExpr(Empty);
+ break;
+
+ case pch::EXPR_BLOCK:
+ S = new (Context) BlockExpr(Empty);
+ break;
+
+ case pch::EXPR_BLOCK_DECL_REF:
+ S = new (Context) BlockDeclRefExpr(Empty);
+ break;
+
+ case pch::EXPR_OBJC_STRING_LITERAL:
+ S = new (Context) ObjCStringLiteral(Empty);
+ break;
+ case pch::EXPR_OBJC_ENCODE:
+ S = new (Context) ObjCEncodeExpr(Empty);
+ break;
+ case pch::EXPR_OBJC_SELECTOR_EXPR:
+ S = new (Context) ObjCSelectorExpr(Empty);
+ break;
+ case pch::EXPR_OBJC_PROTOCOL_EXPR:
+ S = new (Context) ObjCProtocolExpr(Empty);
+ break;
+ case pch::EXPR_OBJC_IVAR_REF_EXPR:
+ S = new (Context) ObjCIvarRefExpr(Empty);
+ break;
+ case pch::EXPR_OBJC_PROPERTY_REF_EXPR:
+ S = new (Context) ObjCPropertyRefExpr(Empty);
+ break;
+ case pch::EXPR_OBJC_KVC_REF_EXPR:
+ S = new (Context) ObjCImplicitSetterGetterRefExpr(Empty);
+ break;
+ case pch::EXPR_OBJC_MESSAGE_EXPR:
+ S = ObjCMessageExpr::CreateEmpty(*Context,
+ Record[PCHStmtReader::NumExprFields]);
+ break;
+ case pch::EXPR_OBJC_SUPER_EXPR:
+ S = new (Context) ObjCSuperExpr(Empty);
+ break;
+ case pch::EXPR_OBJC_ISA:
+ S = new (Context) ObjCIsaExpr(Empty);
+ break;
+ case pch::STMT_OBJC_FOR_COLLECTION:
+ S = new (Context) ObjCForCollectionStmt(Empty);
+ break;
+ case pch::STMT_OBJC_CATCH:
+ S = new (Context) ObjCAtCatchStmt(Empty);
+ break;
+ case pch::STMT_OBJC_FINALLY:
+ S = new (Context) ObjCAtFinallyStmt(Empty);
+ break;
+ case pch::STMT_OBJC_AT_TRY:
+ S = ObjCAtTryStmt::CreateEmpty(*Context,
+ Record[PCHStmtReader::NumStmtFields],
+ Record[PCHStmtReader::NumStmtFields + 1]);
+ break;
+ case pch::STMT_OBJC_AT_SYNCHRONIZED:
+ S = new (Context) ObjCAtSynchronizedStmt(Empty);
+ break;
+ case pch::STMT_OBJC_AT_THROW:
+ S = new (Context) ObjCAtThrowStmt(Empty);
+ break;
+
+ case pch::EXPR_CXX_OPERATOR_CALL:
+ S = new (Context) CXXOperatorCallExpr(*Context, Empty);
+ break;
+
+ case pch::EXPR_CXX_MEMBER_CALL:
+ S = new (Context) CXXMemberCallExpr(*Context, Empty);
+ break;
+
+ case pch::EXPR_CXX_CONSTRUCT:
+ S = new (Context) CXXConstructExpr(Empty);
+ break;
+
+ case pch::EXPR_CXX_TEMPORARY_OBJECT:
+ S = new (Context) CXXTemporaryObjectExpr(Empty);
+ break;
+
+ case pch::EXPR_CXX_STATIC_CAST:
+ S = new (Context) CXXStaticCastExpr(Empty);
+ break;
+
+ case pch::EXPR_CXX_DYNAMIC_CAST:
+ S = new (Context) CXXDynamicCastExpr(Empty);
+ break;
+
+ case pch::EXPR_CXX_REINTERPRET_CAST:
+ S = new (Context) CXXReinterpretCastExpr(Empty);
+ break;
+
+ case pch::EXPR_CXX_CONST_CAST:
+ S = new (Context) CXXConstCastExpr(Empty);
+ break;
+
+ case pch::EXPR_CXX_FUNCTIONAL_CAST:
+ S = new (Context) CXXFunctionalCastExpr(Empty);
+ break;
+
+ case pch::EXPR_CXX_BOOL_LITERAL:
+ S = new (Context) CXXBoolLiteralExpr(Empty);
+ break;
+
+ case pch::EXPR_CXX_NULL_PTR_LITERAL:
+ S = new (Context) CXXNullPtrLiteralExpr(Empty);
+ break;
+ case pch::EXPR_CXX_TYPEID_EXPR:
+ S = new (Context) CXXTypeidExpr(Empty, true);
+ break;
+ case pch::EXPR_CXX_TYPEID_TYPE:
+ S = new (Context) CXXTypeidExpr(Empty, false);
+ break;
+ case pch::EXPR_CXX_THIS:
+ S = new (Context) CXXThisExpr(Empty);
+ break;
+ case pch::EXPR_CXX_THROW:
+ S = new (Context) CXXThrowExpr(Empty);
+ break;
+ case pch::EXPR_CXX_DEFAULT_ARG: {
+ bool HasOtherExprStored = Record[PCHStmtReader::NumExprFields];
+ if (HasOtherExprStored) {
+ Expr *SubExpr = ReadSubExpr();
+ S = CXXDefaultArgExpr::Create(*Context, SourceLocation(), 0, SubExpr);
+ } else
+ S = new (Context) CXXDefaultArgExpr(Empty);
+ break;
+ }
+ case pch::EXPR_CXX_BIND_TEMPORARY:
+ S = new (Context) CXXBindTemporaryExpr(Empty);
+ break;
+ case pch::EXPR_CXX_BIND_REFERENCE:
+ S = new (Context) CXXBindReferenceExpr(Empty);
+ break;
+
+ case pch::EXPR_CXX_SCALAR_VALUE_INIT:
+ S = new (Context) CXXScalarValueInitExpr(Empty);
+ break;
+ case pch::EXPR_CXX_NEW:
+ S = new (Context) CXXNewExpr(Empty);
+ break;
+ case pch::EXPR_CXX_DELETE:
+ S = new (Context) CXXDeleteExpr(Empty);
+ break;
+ case pch::EXPR_CXX_PSEUDO_DESTRUCTOR:
+ S = new (Context) CXXPseudoDestructorExpr(Empty);
+ break;
+
+ case pch::EXPR_CXX_EXPR_WITH_TEMPORARIES:
+ S = new (Context) CXXExprWithTemporaries(Empty);
+ break;
+
+ case pch::EXPR_CXX_DEPENDENT_SCOPE_MEMBER:
+ S = CXXDependentScopeMemberExpr::CreateEmpty(*Context,
+ /*NumTemplateArgs=*/Record[PCHStmtReader::NumExprFields]);
+ break;
+
+ case pch::EXPR_CXX_DEPENDENT_SCOPE_DECL_REF:
+ S = DependentScopeDeclRefExpr::CreateEmpty(*Context,
+ /*NumTemplateArgs=*/Record[PCHStmtReader::NumExprFields]);
+ break;
+
+ case pch::EXPR_CXX_UNRESOLVED_CONSTRUCT:
+ S = CXXUnresolvedConstructExpr::CreateEmpty(*Context,
+ /*NumArgs=*/Record[PCHStmtReader::NumExprFields]);
+ break;
+
+ case pch::EXPR_CXX_UNRESOLVED_MEMBER:
+ S = UnresolvedMemberExpr::CreateEmpty(*Context,
+ /*NumTemplateArgs=*/Record[PCHStmtReader::NumExprFields]);
+ break;
+
+ case pch::EXPR_CXX_UNRESOLVED_LOOKUP:
+ S = UnresolvedLookupExpr::CreateEmpty(*Context,
+ /*NumTemplateArgs=*/Record[PCHStmtReader::NumExprFields]);
+ break;
+
+ case pch::EXPR_CXX_UNARY_TYPE_TRAIT:
+ S = new (Context) UnaryTypeTraitExpr(Empty);
+ break;
+ }
+
+ // We hit a STMT_STOP, so we're done with this expression.
+ if (Finished)
+ break;
+
+ ++NumStatementsRead;
+
+ if (S)
+ Reader.Visit(S);
+
+ assert(Idx == Record.size() && "Invalid deserialization of statement");
+ StmtStack.push_back(S);
+ }
+
+#ifndef NDEBUG
+ assert(StmtStack.size() > PrevNumStmts && "Read too many sub stmts!");
+ assert(StmtStack.size() == PrevNumStmts + 1 && "Extra expressions on stack!");
+#endif
+
+ return StmtStack.pop_back_val();
+}
diff --git a/contrib/llvm/tools/clang/lib/Frontend/PCHWriter.cpp b/contrib/llvm/tools/clang/lib/Frontend/PCHWriter.cpp
new file mode 100644
index 0000000..093c1e3
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Frontend/PCHWriter.cpp
@@ -0,0 +1,2748 @@
+//===--- PCHWriter.cpp - Precompiled Headers Writer -----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the PCHWriter class, which writes a precompiled header.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/PCHWriter.h"
+#include "../Sema/Sema.h" // FIXME: move header into include/clang/Sema
+#include "../Sema/IdentifierResolver.h" // FIXME: move header
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclContextInternals.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/Type.h"
+#include "clang/AST/TypeLocVisitor.h"
+#include "clang/Frontend/PCHReader.h"
+#include "clang/Lex/MacroInfo.h"
+#include "clang/Lex/PreprocessingRecord.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/HeaderSearch.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/OnDiskHashTable.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/SourceManagerInternals.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/Version.h"
+#include "llvm/ADT/APFloat.h"
+#include "llvm/ADT/APInt.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Bitcode/BitstreamWriter.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/System/Path.h"
+#include <cstdio>
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// Type serialization
+//===----------------------------------------------------------------------===//
+
+namespace {
+ class PCHTypeWriter {
+ PCHWriter &Writer;
+ PCHWriter::RecordData &Record;
+
+ public:
+ /// \brief Type code that corresponds to the record generated.
+ pch::TypeCode Code;
+
+ PCHTypeWriter(PCHWriter &Writer, PCHWriter::RecordData &Record)
+ : Writer(Writer), Record(Record), Code(pch::TYPE_EXT_QUAL) { }
+
+ void VisitArrayType(const ArrayType *T);
+ void VisitFunctionType(const FunctionType *T);
+ void VisitTagType(const TagType *T);
+
+#define TYPE(Class, Base) void Visit##Class##Type(const Class##Type *T);
+#define ABSTRACT_TYPE(Class, Base)
+#include "clang/AST/TypeNodes.def"
+ };
+}
+
+void PCHTypeWriter::VisitBuiltinType(const BuiltinType *T) {
+ assert(false && "Built-in types are never serialized");
+}
+
+void PCHTypeWriter::VisitComplexType(const ComplexType *T) {
+ Writer.AddTypeRef(T->getElementType(), Record);
+ Code = pch::TYPE_COMPLEX;
+}
+
+void PCHTypeWriter::VisitPointerType(const PointerType *T) {
+ Writer.AddTypeRef(T->getPointeeType(), Record);
+ Code = pch::TYPE_POINTER;
+}
+
+void PCHTypeWriter::VisitBlockPointerType(const BlockPointerType *T) {
+ Writer.AddTypeRef(T->getPointeeType(), Record);
+ Code = pch::TYPE_BLOCK_POINTER;
+}
+
+void PCHTypeWriter::VisitLValueReferenceType(const LValueReferenceType *T) {
+ Writer.AddTypeRef(T->getPointeeType(), Record);
+ Code = pch::TYPE_LVALUE_REFERENCE;
+}
+
+void PCHTypeWriter::VisitRValueReferenceType(const RValueReferenceType *T) {
+ Writer.AddTypeRef(T->getPointeeType(), Record);
+ Code = pch::TYPE_RVALUE_REFERENCE;
+}
+
+void PCHTypeWriter::VisitMemberPointerType(const MemberPointerType *T) {
+ Writer.AddTypeRef(T->getPointeeType(), Record);
+ Writer.AddTypeRef(QualType(T->getClass(), 0), Record);
+ Code = pch::TYPE_MEMBER_POINTER;
+}
+
+void PCHTypeWriter::VisitArrayType(const ArrayType *T) {
+ Writer.AddTypeRef(T->getElementType(), Record);
+ Record.push_back(T->getSizeModifier()); // FIXME: stable values
+ Record.push_back(T->getIndexTypeCVRQualifiers()); // FIXME: stable values
+}
+
+void PCHTypeWriter::VisitConstantArrayType(const ConstantArrayType *T) {
+ VisitArrayType(T);
+ Writer.AddAPInt(T->getSize(), Record);
+ Code = pch::TYPE_CONSTANT_ARRAY;
+}
+
+void PCHTypeWriter::VisitIncompleteArrayType(const IncompleteArrayType *T) {
+ VisitArrayType(T);
+ Code = pch::TYPE_INCOMPLETE_ARRAY;
+}
+
+void PCHTypeWriter::VisitVariableArrayType(const VariableArrayType *T) {
+ VisitArrayType(T);
+ Writer.AddSourceLocation(T->getLBracketLoc(), Record);
+ Writer.AddSourceLocation(T->getRBracketLoc(), Record);
+ Writer.AddStmt(T->getSizeExpr());
+ Code = pch::TYPE_VARIABLE_ARRAY;
+}
+
+void PCHTypeWriter::VisitVectorType(const VectorType *T) {
+ Writer.AddTypeRef(T->getElementType(), Record);
+ Record.push_back(T->getNumElements());
+ Record.push_back(T->getAltiVecSpecific());
+ Code = pch::TYPE_VECTOR;
+}
+
+void PCHTypeWriter::VisitExtVectorType(const ExtVectorType *T) {
+ VisitVectorType(T);
+ Code = pch::TYPE_EXT_VECTOR;
+}
+
+void PCHTypeWriter::VisitFunctionType(const FunctionType *T) {
+ Writer.AddTypeRef(T->getResultType(), Record);
+ FunctionType::ExtInfo C = T->getExtInfo();
+ Record.push_back(C.getNoReturn());
+ Record.push_back(C.getRegParm());
+ // FIXME: need to stabilize encoding of calling convention...
+ Record.push_back(C.getCC());
+}
+
+void PCHTypeWriter::VisitFunctionNoProtoType(const FunctionNoProtoType *T) {
+ VisitFunctionType(T);
+ Code = pch::TYPE_FUNCTION_NO_PROTO;
+}
+
+void PCHTypeWriter::VisitFunctionProtoType(const FunctionProtoType *T) {
+ VisitFunctionType(T);
+ Record.push_back(T->getNumArgs());
+ for (unsigned I = 0, N = T->getNumArgs(); I != N; ++I)
+ Writer.AddTypeRef(T->getArgType(I), Record);
+ Record.push_back(T->isVariadic());
+ Record.push_back(T->getTypeQuals());
+ Record.push_back(T->hasExceptionSpec());
+ Record.push_back(T->hasAnyExceptionSpec());
+ Record.push_back(T->getNumExceptions());
+ for (unsigned I = 0, N = T->getNumExceptions(); I != N; ++I)
+ Writer.AddTypeRef(T->getExceptionType(I), Record);
+ Code = pch::TYPE_FUNCTION_PROTO;
+}
+
+void PCHTypeWriter::VisitUnresolvedUsingType(const UnresolvedUsingType *T) {
+ Writer.AddDeclRef(T->getDecl(), Record);
+ Code = pch::TYPE_UNRESOLVED_USING;
+}
+
+void PCHTypeWriter::VisitTypedefType(const TypedefType *T) {
+ Writer.AddDeclRef(T->getDecl(), Record);
+ assert(!T->isCanonicalUnqualified() && "Invalid typedef ?");
+ Writer.AddTypeRef(T->getCanonicalTypeInternal(), Record);
+ Code = pch::TYPE_TYPEDEF;
+}
+
+void PCHTypeWriter::VisitTypeOfExprType(const TypeOfExprType *T) {
+ Writer.AddStmt(T->getUnderlyingExpr());
+ Code = pch::TYPE_TYPEOF_EXPR;
+}
+
+void PCHTypeWriter::VisitTypeOfType(const TypeOfType *T) {
+ Writer.AddTypeRef(T->getUnderlyingType(), Record);
+ Code = pch::TYPE_TYPEOF;
+}
+
+void PCHTypeWriter::VisitDecltypeType(const DecltypeType *T) {
+ Writer.AddStmt(T->getUnderlyingExpr());
+ Code = pch::TYPE_DECLTYPE;
+}
+
+void PCHTypeWriter::VisitTagType(const TagType *T) {
+ Record.push_back(T->isDependentType());
+ Writer.AddDeclRef(T->getDecl(), Record);
+ assert(!T->isBeingDefined() &&
+ "Cannot serialize in the middle of a type definition");
+}
+
+void PCHTypeWriter::VisitRecordType(const RecordType *T) {
+ VisitTagType(T);
+ Code = pch::TYPE_RECORD;
+}
+
+void PCHTypeWriter::VisitEnumType(const EnumType *T) {
+ VisitTagType(T);
+ Code = pch::TYPE_ENUM;
+}
+
+void
+PCHTypeWriter::VisitSubstTemplateTypeParmType(
+ const SubstTemplateTypeParmType *T) {
+ Writer.AddTypeRef(QualType(T->getReplacedParameter(), 0), Record);
+ Writer.AddTypeRef(T->getReplacementType(), Record);
+ Code = pch::TYPE_SUBST_TEMPLATE_TYPE_PARM;
+}
+
+void
+PCHTypeWriter::VisitTemplateSpecializationType(
+ const TemplateSpecializationType *T) {
+ Record.push_back(T->isDependentType());
+ Writer.AddTemplateName(T->getTemplateName(), Record);
+ Record.push_back(T->getNumArgs());
+ for (TemplateSpecializationType::iterator ArgI = T->begin(), ArgE = T->end();
+ ArgI != ArgE; ++ArgI)
+ Writer.AddTemplateArgument(*ArgI, Record);
+ Writer.AddTypeRef(T->isCanonicalUnqualified() ? QualType()
+ : T->getCanonicalTypeInternal(),
+ Record);
+ Code = pch::TYPE_TEMPLATE_SPECIALIZATION;
+}
+
+void
+PCHTypeWriter::VisitDependentSizedArrayType(const DependentSizedArrayType *T) {
+ VisitArrayType(T);
+ Writer.AddStmt(T->getSizeExpr());
+ Writer.AddSourceRange(T->getBracketsRange(), Record);
+ Code = pch::TYPE_DEPENDENT_SIZED_ARRAY;
+}
+
+void
+PCHTypeWriter::VisitDependentSizedExtVectorType(
+ const DependentSizedExtVectorType *T) {
+ // FIXME: Serialize this type (C++ only)
+ assert(false && "Cannot serialize dependent sized extended vector types");
+}
+
+void
+PCHTypeWriter::VisitTemplateTypeParmType(const TemplateTypeParmType *T) {
+ Record.push_back(T->getDepth());
+ Record.push_back(T->getIndex());
+ Record.push_back(T->isParameterPack());
+ Writer.AddIdentifierRef(T->getName(), Record);
+ Code = pch::TYPE_TEMPLATE_TYPE_PARM;
+}
+
+void
+PCHTypeWriter::VisitDependentNameType(const DependentNameType *T) {
+ Record.push_back(T->getKeyword());
+ Writer.AddNestedNameSpecifier(T->getQualifier(), Record);
+ Writer.AddIdentifierRef(T->getIdentifier(), Record);
+ Writer.AddTypeRef(T->isCanonicalUnqualified() ? QualType()
+ : T->getCanonicalTypeInternal(),
+ Record);
+ Code = pch::TYPE_DEPENDENT_NAME;
+}
+
+void
+PCHTypeWriter::VisitDependentTemplateSpecializationType(
+ const DependentTemplateSpecializationType *T) {
+ Record.push_back(T->getKeyword());
+ Writer.AddNestedNameSpecifier(T->getQualifier(), Record);
+ Writer.AddIdentifierRef(T->getIdentifier(), Record);
+ Record.push_back(T->getNumArgs());
+ for (DependentTemplateSpecializationType::iterator
+ I = T->begin(), E = T->end(); I != E; ++I)
+ Writer.AddTemplateArgument(*I, Record);
+ Code = pch::TYPE_DEPENDENT_TEMPLATE_SPECIALIZATION;
+}
+
+void PCHTypeWriter::VisitElaboratedType(const ElaboratedType *T) {
+ Record.push_back(T->getKeyword());
+ Writer.AddNestedNameSpecifier(T->getQualifier(), Record);
+ Writer.AddTypeRef(T->getNamedType(), Record);
+ Code = pch::TYPE_ELABORATED;
+}
+
+void PCHTypeWriter::VisitInjectedClassNameType(const InjectedClassNameType *T) {
+ Writer.AddDeclRef(T->getDecl(), Record);
+ Writer.AddTypeRef(T->getInjectedSpecializationType(), Record);
+ Code = pch::TYPE_INJECTED_CLASS_NAME;
+}
+
+void PCHTypeWriter::VisitObjCInterfaceType(const ObjCInterfaceType *T) {
+ Writer.AddDeclRef(T->getDecl(), Record);
+ Code = pch::TYPE_OBJC_INTERFACE;
+}
+
+void PCHTypeWriter::VisitObjCObjectType(const ObjCObjectType *T) {
+ Writer.AddTypeRef(T->getBaseType(), Record);
+ Record.push_back(T->getNumProtocols());
+ for (ObjCObjectType::qual_iterator I = T->qual_begin(),
+ E = T->qual_end(); I != E; ++I)
+ Writer.AddDeclRef(*I, Record);
+ Code = pch::TYPE_OBJC_OBJECT;
+}
+
+void
+PCHTypeWriter::VisitObjCObjectPointerType(const ObjCObjectPointerType *T) {
+ Writer.AddTypeRef(T->getPointeeType(), Record);
+ Code = pch::TYPE_OBJC_OBJECT_POINTER;
+}
+
+namespace {
+
+class TypeLocWriter : public TypeLocVisitor<TypeLocWriter> {
+ PCHWriter &Writer;
+ PCHWriter::RecordData &Record;
+
+public:
+ TypeLocWriter(PCHWriter &Writer, PCHWriter::RecordData &Record)
+ : Writer(Writer), Record(Record) { }
+
+#define ABSTRACT_TYPELOC(CLASS, PARENT)
+#define TYPELOC(CLASS, PARENT) \
+ void Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc);
+#include "clang/AST/TypeLocNodes.def"
+
+ void VisitArrayTypeLoc(ArrayTypeLoc TyLoc);
+ void VisitFunctionTypeLoc(FunctionTypeLoc TyLoc);
+};
+
+}
+
+void TypeLocWriter::VisitQualifiedTypeLoc(QualifiedTypeLoc TL) {
+ // nothing to do
+}
+void TypeLocWriter::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) {
+ Writer.AddSourceLocation(TL.getBuiltinLoc(), Record);
+ if (TL.needsExtraLocalData()) {
+ Record.push_back(TL.getWrittenTypeSpec());
+ Record.push_back(TL.getWrittenSignSpec());
+ Record.push_back(TL.getWrittenWidthSpec());
+ Record.push_back(TL.hasModeAttr());
+ }
+}
+void TypeLocWriter::VisitComplexTypeLoc(ComplexTypeLoc TL) {
+ Writer.AddSourceLocation(TL.getNameLoc(), Record);
+}
+void TypeLocWriter::VisitPointerTypeLoc(PointerTypeLoc TL) {
+ Writer.AddSourceLocation(TL.getStarLoc(), Record);
+}
+void TypeLocWriter::VisitBlockPointerTypeLoc(BlockPointerTypeLoc TL) {
+ Writer.AddSourceLocation(TL.getCaretLoc(), Record);
+}
+void TypeLocWriter::VisitLValueReferenceTypeLoc(LValueReferenceTypeLoc TL) {
+ Writer.AddSourceLocation(TL.getAmpLoc(), Record);
+}
+void TypeLocWriter::VisitRValueReferenceTypeLoc(RValueReferenceTypeLoc TL) {
+ Writer.AddSourceLocation(TL.getAmpAmpLoc(), Record);
+}
+void TypeLocWriter::VisitMemberPointerTypeLoc(MemberPointerTypeLoc TL) {
+ Writer.AddSourceLocation(TL.getStarLoc(), Record);
+}
+void TypeLocWriter::VisitArrayTypeLoc(ArrayTypeLoc TL) {
+ Writer.AddSourceLocation(TL.getLBracketLoc(), Record);
+ Writer.AddSourceLocation(TL.getRBracketLoc(), Record);
+ Record.push_back(TL.getSizeExpr() ? 1 : 0);
+ if (TL.getSizeExpr())
+ Writer.AddStmt(TL.getSizeExpr());
+}
+void TypeLocWriter::VisitConstantArrayTypeLoc(ConstantArrayTypeLoc TL) {
+ VisitArrayTypeLoc(TL);
+}
+void TypeLocWriter::VisitIncompleteArrayTypeLoc(IncompleteArrayTypeLoc TL) {
+ VisitArrayTypeLoc(TL);
+}
+void TypeLocWriter::VisitVariableArrayTypeLoc(VariableArrayTypeLoc TL) {
+ VisitArrayTypeLoc(TL);
+}
+void TypeLocWriter::VisitDependentSizedArrayTypeLoc(
+ DependentSizedArrayTypeLoc TL) {
+ VisitArrayTypeLoc(TL);
+}
+void TypeLocWriter::VisitDependentSizedExtVectorTypeLoc(
+ DependentSizedExtVectorTypeLoc TL) {
+ Writer.AddSourceLocation(TL.getNameLoc(), Record);
+}
+void TypeLocWriter::VisitVectorTypeLoc(VectorTypeLoc TL) {
+ Writer.AddSourceLocation(TL.getNameLoc(), Record);
+}
+void TypeLocWriter::VisitExtVectorTypeLoc(ExtVectorTypeLoc TL) {
+ Writer.AddSourceLocation(TL.getNameLoc(), Record);
+}
+void TypeLocWriter::VisitFunctionTypeLoc(FunctionTypeLoc TL) {
+ Writer.AddSourceLocation(TL.getLParenLoc(), Record);
+ Writer.AddSourceLocation(TL.getRParenLoc(), Record);
+ for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i)
+ Writer.AddDeclRef(TL.getArg(i), Record);
+}
+void TypeLocWriter::VisitFunctionProtoTypeLoc(FunctionProtoTypeLoc TL) {
+ VisitFunctionTypeLoc(TL);
+}
+void TypeLocWriter::VisitFunctionNoProtoTypeLoc(FunctionNoProtoTypeLoc TL) {
+ VisitFunctionTypeLoc(TL);
+}
+void TypeLocWriter::VisitUnresolvedUsingTypeLoc(UnresolvedUsingTypeLoc TL) {
+ Writer.AddSourceLocation(TL.getNameLoc(), Record);
+}
+void TypeLocWriter::VisitTypedefTypeLoc(TypedefTypeLoc TL) {
+ Writer.AddSourceLocation(TL.getNameLoc(), Record);
+}
+void TypeLocWriter::VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL) {
+ Writer.AddSourceLocation(TL.getTypeofLoc(), Record);
+ Writer.AddSourceLocation(TL.getLParenLoc(), Record);
+ Writer.AddSourceLocation(TL.getRParenLoc(), Record);
+}
+void TypeLocWriter::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) {
+ Writer.AddSourceLocation(TL.getTypeofLoc(), Record);
+ Writer.AddSourceLocation(TL.getLParenLoc(), Record);
+ Writer.AddSourceLocation(TL.getRParenLoc(), Record);
+ Writer.AddTypeSourceInfo(TL.getUnderlyingTInfo(), Record);
+}
+void TypeLocWriter::VisitDecltypeTypeLoc(DecltypeTypeLoc TL) {
+ Writer.AddSourceLocation(TL.getNameLoc(), Record);
+}
+void TypeLocWriter::VisitRecordTypeLoc(RecordTypeLoc TL) {
+ Writer.AddSourceLocation(TL.getNameLoc(), Record);
+}
+void TypeLocWriter::VisitEnumTypeLoc(EnumTypeLoc TL) {
+ Writer.AddSourceLocation(TL.getNameLoc(), Record);
+}
+void TypeLocWriter::VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) {
+ Writer.AddSourceLocation(TL.getNameLoc(), Record);
+}
+void TypeLocWriter::VisitSubstTemplateTypeParmTypeLoc(
+ SubstTemplateTypeParmTypeLoc TL) {
+ Writer.AddSourceLocation(TL.getNameLoc(), Record);
+}
+void TypeLocWriter::VisitTemplateSpecializationTypeLoc(
+ TemplateSpecializationTypeLoc TL) {
+ Writer.AddSourceLocation(TL.getTemplateNameLoc(), Record);
+ Writer.AddSourceLocation(TL.getLAngleLoc(), Record);
+ Writer.AddSourceLocation(TL.getRAngleLoc(), Record);
+ for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i)
+ Writer.AddTemplateArgumentLocInfo(TL.getArgLoc(i).getArgument().getKind(),
+ TL.getArgLoc(i).getLocInfo(), Record);
+}
+void TypeLocWriter::VisitElaboratedTypeLoc(ElaboratedTypeLoc TL) {
+ Writer.AddSourceLocation(TL.getKeywordLoc(), Record);
+ Writer.AddSourceRange(TL.getQualifierRange(), Record);
+}
+void TypeLocWriter::VisitInjectedClassNameTypeLoc(InjectedClassNameTypeLoc TL) {
+ Writer.AddSourceLocation(TL.getNameLoc(), Record);
+}
+void TypeLocWriter::VisitDependentNameTypeLoc(DependentNameTypeLoc TL) {
+ Writer.AddSourceLocation(TL.getKeywordLoc(), Record);
+ Writer.AddSourceRange(TL.getQualifierRange(), Record);
+ Writer.AddSourceLocation(TL.getNameLoc(), Record);
+}
+void TypeLocWriter::VisitDependentTemplateSpecializationTypeLoc(
+ DependentTemplateSpecializationTypeLoc TL) {
+ Writer.AddSourceLocation(TL.getKeywordLoc(), Record);
+ Writer.AddSourceRange(TL.getQualifierRange(), Record);
+ Writer.AddSourceLocation(TL.getNameLoc(), Record);
+ Writer.AddSourceLocation(TL.getLAngleLoc(), Record);
+ Writer.AddSourceLocation(TL.getRAngleLoc(), Record);
+ for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I)
+ Writer.AddTemplateArgumentLocInfo(TL.getArgLoc(I).getArgument().getKind(),
+ TL.getArgLoc(I).getLocInfo(), Record);
+}
+void TypeLocWriter::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) {
+ Writer.AddSourceLocation(TL.getNameLoc(), Record);
+}
+void TypeLocWriter::VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) {
+ Record.push_back(TL.hasBaseTypeAsWritten());
+ Writer.AddSourceLocation(TL.getLAngleLoc(), Record);
+ Writer.AddSourceLocation(TL.getRAngleLoc(), Record);
+ for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i)
+ Writer.AddSourceLocation(TL.getProtocolLoc(i), Record);
+}
+void TypeLocWriter::VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) {
+ Writer.AddSourceLocation(TL.getStarLoc(), Record);
+}
+
+//===----------------------------------------------------------------------===//
+// PCHWriter Implementation
+//===----------------------------------------------------------------------===//
+
+static void EmitBlockID(unsigned ID, const char *Name,
+ llvm::BitstreamWriter &Stream,
+ PCHWriter::RecordData &Record) {
+ Record.clear();
+ Record.push_back(ID);
+ Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETBID, Record);
+
+ // Emit the block name if present.
+ if (Name == 0 || Name[0] == 0) return;
+ Record.clear();
+ while (*Name)
+ Record.push_back(*Name++);
+ Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_BLOCKNAME, Record);
+}
+
+static void EmitRecordID(unsigned ID, const char *Name,
+ llvm::BitstreamWriter &Stream,
+ PCHWriter::RecordData &Record) {
+ Record.clear();
+ Record.push_back(ID);
+ while (*Name)
+ Record.push_back(*Name++);
+ Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, Record);
+}
+
+static void AddStmtsExprs(llvm::BitstreamWriter &Stream,
+ PCHWriter::RecordData &Record) {
+#define RECORD(X) EmitRecordID(pch::X, #X, Stream, Record)
+ RECORD(STMT_STOP);
+ RECORD(STMT_NULL_PTR);
+ RECORD(STMT_NULL);
+ RECORD(STMT_COMPOUND);
+ RECORD(STMT_CASE);
+ RECORD(STMT_DEFAULT);
+ RECORD(STMT_LABEL);
+ RECORD(STMT_IF);
+ RECORD(STMT_SWITCH);
+ RECORD(STMT_WHILE);
+ RECORD(STMT_DO);
+ RECORD(STMT_FOR);
+ RECORD(STMT_GOTO);
+ RECORD(STMT_INDIRECT_GOTO);
+ RECORD(STMT_CONTINUE);
+ RECORD(STMT_BREAK);
+ RECORD(STMT_RETURN);
+ RECORD(STMT_DECL);
+ RECORD(STMT_ASM);
+ RECORD(EXPR_PREDEFINED);
+ RECORD(EXPR_DECL_REF);
+ RECORD(EXPR_INTEGER_LITERAL);
+ RECORD(EXPR_FLOATING_LITERAL);
+ RECORD(EXPR_IMAGINARY_LITERAL);
+ RECORD(EXPR_STRING_LITERAL);
+ RECORD(EXPR_CHARACTER_LITERAL);
+ RECORD(EXPR_PAREN);
+ RECORD(EXPR_UNARY_OPERATOR);
+ RECORD(EXPR_SIZEOF_ALIGN_OF);
+ RECORD(EXPR_ARRAY_SUBSCRIPT);
+ RECORD(EXPR_CALL);
+ RECORD(EXPR_MEMBER);
+ RECORD(EXPR_BINARY_OPERATOR);
+ RECORD(EXPR_COMPOUND_ASSIGN_OPERATOR);
+ RECORD(EXPR_CONDITIONAL_OPERATOR);
+ RECORD(EXPR_IMPLICIT_CAST);
+ RECORD(EXPR_CSTYLE_CAST);
+ RECORD(EXPR_COMPOUND_LITERAL);
+ RECORD(EXPR_EXT_VECTOR_ELEMENT);
+ RECORD(EXPR_INIT_LIST);
+ RECORD(EXPR_DESIGNATED_INIT);
+ RECORD(EXPR_IMPLICIT_VALUE_INIT);
+ RECORD(EXPR_VA_ARG);
+ RECORD(EXPR_ADDR_LABEL);
+ RECORD(EXPR_STMT);
+ RECORD(EXPR_TYPES_COMPATIBLE);
+ RECORD(EXPR_CHOOSE);
+ RECORD(EXPR_GNU_NULL);
+ RECORD(EXPR_SHUFFLE_VECTOR);
+ RECORD(EXPR_BLOCK);
+ RECORD(EXPR_BLOCK_DECL_REF);
+ RECORD(EXPR_OBJC_STRING_LITERAL);
+ RECORD(EXPR_OBJC_ENCODE);
+ RECORD(EXPR_OBJC_SELECTOR_EXPR);
+ RECORD(EXPR_OBJC_PROTOCOL_EXPR);
+ RECORD(EXPR_OBJC_IVAR_REF_EXPR);
+ RECORD(EXPR_OBJC_PROPERTY_REF_EXPR);
+ RECORD(EXPR_OBJC_KVC_REF_EXPR);
+ RECORD(EXPR_OBJC_MESSAGE_EXPR);
+ RECORD(EXPR_OBJC_SUPER_EXPR);
+ RECORD(STMT_OBJC_FOR_COLLECTION);
+ RECORD(STMT_OBJC_CATCH);
+ RECORD(STMT_OBJC_FINALLY);
+ RECORD(STMT_OBJC_AT_TRY);
+ RECORD(STMT_OBJC_AT_SYNCHRONIZED);
+ RECORD(STMT_OBJC_AT_THROW);
+ RECORD(EXPR_CXX_OPERATOR_CALL);
+ RECORD(EXPR_CXX_CONSTRUCT);
+ RECORD(EXPR_CXX_STATIC_CAST);
+ RECORD(EXPR_CXX_DYNAMIC_CAST);
+ RECORD(EXPR_CXX_REINTERPRET_CAST);
+ RECORD(EXPR_CXX_CONST_CAST);
+ RECORD(EXPR_CXX_FUNCTIONAL_CAST);
+ RECORD(EXPR_CXX_BOOL_LITERAL);
+ RECORD(EXPR_CXX_NULL_PTR_LITERAL);
+#undef RECORD
+}
+
+void PCHWriter::WriteBlockInfoBlock() {
+ RecordData Record;
+ Stream.EnterSubblock(llvm::bitc::BLOCKINFO_BLOCK_ID, 3);
+
+#define BLOCK(X) EmitBlockID(pch::X ## _ID, #X, Stream, Record)
+#define RECORD(X) EmitRecordID(pch::X, #X, Stream, Record)
+
+ // PCH Top-Level Block.
+ BLOCK(PCH_BLOCK);
+ RECORD(ORIGINAL_FILE_NAME);
+ RECORD(TYPE_OFFSET);
+ RECORD(DECL_OFFSET);
+ RECORD(LANGUAGE_OPTIONS);
+ RECORD(METADATA);
+ RECORD(IDENTIFIER_OFFSET);
+ RECORD(IDENTIFIER_TABLE);
+ RECORD(EXTERNAL_DEFINITIONS);
+ RECORD(SPECIAL_TYPES);
+ RECORD(STATISTICS);
+ RECORD(TENTATIVE_DEFINITIONS);
+ RECORD(UNUSED_STATIC_FUNCS);
+ RECORD(LOCALLY_SCOPED_EXTERNAL_DECLS);
+ RECORD(SELECTOR_OFFSETS);
+ RECORD(METHOD_POOL);
+ RECORD(PP_COUNTER_VALUE);
+ RECORD(SOURCE_LOCATION_OFFSETS);
+ RECORD(SOURCE_LOCATION_PRELOADS);
+ RECORD(STAT_CACHE);
+ RECORD(EXT_VECTOR_DECLS);
+ RECORD(VERSION_CONTROL_BRANCH_REVISION);
+ RECORD(UNUSED_STATIC_FUNCS);
+ RECORD(MACRO_DEFINITION_OFFSETS);
+ RECORD(CHAINED_METADATA);
+
+ // SourceManager Block.
+ BLOCK(SOURCE_MANAGER_BLOCK);
+ RECORD(SM_SLOC_FILE_ENTRY);
+ RECORD(SM_SLOC_BUFFER_ENTRY);
+ RECORD(SM_SLOC_BUFFER_BLOB);
+ RECORD(SM_SLOC_INSTANTIATION_ENTRY);
+ RECORD(SM_LINE_TABLE);
+
+ // Preprocessor Block.
+ BLOCK(PREPROCESSOR_BLOCK);
+ RECORD(PP_MACRO_OBJECT_LIKE);
+ RECORD(PP_MACRO_FUNCTION_LIKE);
+ RECORD(PP_TOKEN);
+ RECORD(PP_MACRO_INSTANTIATION);
+ RECORD(PP_MACRO_DEFINITION);
+
+ // Decls and Types block.
+ BLOCK(DECLTYPES_BLOCK);
+ RECORD(TYPE_EXT_QUAL);
+ RECORD(TYPE_COMPLEX);
+ RECORD(TYPE_POINTER);
+ RECORD(TYPE_BLOCK_POINTER);
+ RECORD(TYPE_LVALUE_REFERENCE);
+ RECORD(TYPE_RVALUE_REFERENCE);
+ RECORD(TYPE_MEMBER_POINTER);
+ RECORD(TYPE_CONSTANT_ARRAY);
+ RECORD(TYPE_INCOMPLETE_ARRAY);
+ RECORD(TYPE_VARIABLE_ARRAY);
+ RECORD(TYPE_VECTOR);
+ RECORD(TYPE_EXT_VECTOR);
+ RECORD(TYPE_FUNCTION_PROTO);
+ RECORD(TYPE_FUNCTION_NO_PROTO);
+ RECORD(TYPE_TYPEDEF);
+ RECORD(TYPE_TYPEOF_EXPR);
+ RECORD(TYPE_TYPEOF);
+ RECORD(TYPE_RECORD);
+ RECORD(TYPE_ENUM);
+ RECORD(TYPE_OBJC_INTERFACE);
+ RECORD(TYPE_OBJC_OBJECT);
+ RECORD(TYPE_OBJC_OBJECT_POINTER);
+ RECORD(DECL_ATTR);
+ RECORD(DECL_TRANSLATION_UNIT);
+ RECORD(DECL_TYPEDEF);
+ RECORD(DECL_ENUM);
+ RECORD(DECL_RECORD);
+ RECORD(DECL_ENUM_CONSTANT);
+ RECORD(DECL_FUNCTION);
+ RECORD(DECL_OBJC_METHOD);
+ RECORD(DECL_OBJC_INTERFACE);
+ RECORD(DECL_OBJC_PROTOCOL);
+ RECORD(DECL_OBJC_IVAR);
+ RECORD(DECL_OBJC_AT_DEFS_FIELD);
+ RECORD(DECL_OBJC_CLASS);
+ RECORD(DECL_OBJC_FORWARD_PROTOCOL);
+ RECORD(DECL_OBJC_CATEGORY);
+ RECORD(DECL_OBJC_CATEGORY_IMPL);
+ RECORD(DECL_OBJC_IMPLEMENTATION);
+ RECORD(DECL_OBJC_COMPATIBLE_ALIAS);
+ RECORD(DECL_OBJC_PROPERTY);
+ RECORD(DECL_OBJC_PROPERTY_IMPL);
+ RECORD(DECL_FIELD);
+ RECORD(DECL_VAR);
+ RECORD(DECL_IMPLICIT_PARAM);
+ RECORD(DECL_PARM_VAR);
+ RECORD(DECL_FILE_SCOPE_ASM);
+ RECORD(DECL_BLOCK);
+ RECORD(DECL_CONTEXT_LEXICAL);
+ RECORD(DECL_CONTEXT_VISIBLE);
+ // Statements and Exprs can occur in the Decls and Types block.
+ AddStmtsExprs(Stream, Record);
+#undef RECORD
+#undef BLOCK
+ Stream.ExitBlock();
+}
+
+/// \brief Adjusts the given filename to only write out the portion of the
+/// filename that is not part of the system root directory.
+///
+/// \param Filename the file name to adjust.
+///
+/// \param isysroot When non-NULL, the PCH file is a relocatable PCH file and
+/// the returned filename will be adjusted by this system root.
+///
+/// \returns either the original filename (if it needs no adjustment) or the
+/// adjusted filename (which points into the @p Filename parameter).
+static const char *
+adjustFilenameForRelocatablePCH(const char *Filename, const char *isysroot) {
+ assert(Filename && "No file name to adjust?");
+
+ if (!isysroot)
+ return Filename;
+
+ // Verify that the filename and the system root have the same prefix.
+ unsigned Pos = 0;
+ for (; Filename[Pos] && isysroot[Pos]; ++Pos)
+ if (Filename[Pos] != isysroot[Pos])
+ return Filename; // Prefixes don't match.
+
+ // We hit the end of the filename before we hit the end of the system root.
+ if (!Filename[Pos])
+ return Filename;
+
+ // If the file name has a '/' at the current position, skip over the '/'.
+ // We distinguish sysroot-based includes from absolute includes by the
+ // absence of '/' at the beginning of sysroot-based includes.
+ if (Filename[Pos] == '/')
+ ++Pos;
+
+ return Filename + Pos;
+}
+
+/// \brief Write the PCH metadata (e.g., i686-apple-darwin9).
+void PCHWriter::WriteMetadata(ASTContext &Context, const char *isysroot) {
+ using namespace llvm;
+
+ // Metadata
+ const TargetInfo &Target = Context.Target;
+ BitCodeAbbrev *MetaAbbrev = new BitCodeAbbrev();
+ MetaAbbrev->Add(BitCodeAbbrevOp(
+ Chain ? pch::CHAINED_METADATA : pch::METADATA));
+ MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // PCH major
+ MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // PCH minor
+ MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Clang major
+ MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Clang minor
+ MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Relocatable
+ // Target triple or chained PCH name
+ MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
+ unsigned MetaAbbrevCode = Stream.EmitAbbrev(MetaAbbrev);
+
+ RecordData Record;
+ Record.push_back(Chain ? pch::CHAINED_METADATA : pch::METADATA);
+ Record.push_back(pch::VERSION_MAJOR);
+ Record.push_back(pch::VERSION_MINOR);
+ Record.push_back(CLANG_VERSION_MAJOR);
+ Record.push_back(CLANG_VERSION_MINOR);
+ Record.push_back(isysroot != 0);
+ // FIXME: This writes the absolute path for chained headers.
+ const std::string &BlobStr = Chain ? Chain->getFileName() : Target.getTriple().getTriple();
+ Stream.EmitRecordWithBlob(MetaAbbrevCode, Record, BlobStr);
+
+ // Original file name
+ SourceManager &SM = Context.getSourceManager();
+ if (const FileEntry *MainFile = SM.getFileEntryForID(SM.getMainFileID())) {
+ BitCodeAbbrev *FileAbbrev = new BitCodeAbbrev();
+ FileAbbrev->Add(BitCodeAbbrevOp(pch::ORIGINAL_FILE_NAME));
+ FileAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name
+ unsigned FileAbbrevCode = Stream.EmitAbbrev(FileAbbrev);
+
+ llvm::sys::Path MainFilePath(MainFile->getName());
+
+ MainFilePath.makeAbsolute();
+
+ const char *MainFileNameStr = MainFilePath.c_str();
+ MainFileNameStr = adjustFilenameForRelocatablePCH(MainFileNameStr,
+ isysroot);
+ RecordData Record;
+ Record.push_back(pch::ORIGINAL_FILE_NAME);
+ Stream.EmitRecordWithBlob(FileAbbrevCode, Record, MainFileNameStr);
+ }
+
+ // Repository branch/version information.
+ BitCodeAbbrev *RepoAbbrev = new BitCodeAbbrev();
+ RepoAbbrev->Add(BitCodeAbbrevOp(pch::VERSION_CONTROL_BRANCH_REVISION));
+ RepoAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // SVN branch/tag
+ unsigned RepoAbbrevCode = Stream.EmitAbbrev(RepoAbbrev);
+ Record.clear();
+ Record.push_back(pch::VERSION_CONTROL_BRANCH_REVISION);
+ Stream.EmitRecordWithBlob(RepoAbbrevCode, Record,
+ getClangFullRepositoryVersion());
+}
+
+/// \brief Write the LangOptions structure.
+void PCHWriter::WriteLanguageOptions(const LangOptions &LangOpts) {
+ RecordData Record;
+ Record.push_back(LangOpts.Trigraphs);
+ Record.push_back(LangOpts.BCPLComment); // BCPL-style '//' comments.
+ Record.push_back(LangOpts.DollarIdents); // '$' allowed in identifiers.
+ Record.push_back(LangOpts.AsmPreprocessor); // Preprocessor in asm mode.
+ Record.push_back(LangOpts.GNUMode); // True in gnu99 mode false in c99 mode (etc)
+ Record.push_back(LangOpts.GNUKeywords); // Allow GNU-extension keywords
+ Record.push_back(LangOpts.ImplicitInt); // C89 implicit 'int'.
+ Record.push_back(LangOpts.Digraphs); // C94, C99 and C++
+ Record.push_back(LangOpts.HexFloats); // C99 Hexadecimal float constants.
+ Record.push_back(LangOpts.C99); // C99 Support
+ Record.push_back(LangOpts.Microsoft); // Microsoft extensions.
+ Record.push_back(LangOpts.CPlusPlus); // C++ Support
+ Record.push_back(LangOpts.CPlusPlus0x); // C++0x Support
+ Record.push_back(LangOpts.CXXOperatorNames); // Treat C++ operator names as keywords.
+
+ Record.push_back(LangOpts.ObjC1); // Objective-C 1 support enabled.
+ Record.push_back(LangOpts.ObjC2); // Objective-C 2 support enabled.
+ Record.push_back(LangOpts.ObjCNonFragileABI); // Objective-C
+ // modern abi enabled.
+ Record.push_back(LangOpts.ObjCNonFragileABI2); // Objective-C enhanced
+ // modern abi enabled.
+ Record.push_back(LangOpts.NoConstantCFStrings); // non cfstring generation enabled..
+
+ Record.push_back(LangOpts.PascalStrings); // Allow Pascal strings
+ Record.push_back(LangOpts.WritableStrings); // Allow writable strings
+ Record.push_back(LangOpts.LaxVectorConversions);
+ Record.push_back(LangOpts.AltiVec);
+ Record.push_back(LangOpts.Exceptions); // Support exception handling.
+ Record.push_back(LangOpts.SjLjExceptions);
+
+ Record.push_back(LangOpts.NeXTRuntime); // Use NeXT runtime.
+ Record.push_back(LangOpts.Freestanding); // Freestanding implementation
+ Record.push_back(LangOpts.NoBuiltin); // Do not use builtin functions (-fno-builtin)
+
+ // Whether static initializers are protected by locks.
+ Record.push_back(LangOpts.ThreadsafeStatics);
+ Record.push_back(LangOpts.POSIXThreads);
+ Record.push_back(LangOpts.Blocks); // block extension to C
+ Record.push_back(LangOpts.EmitAllDecls); // Emit all declarations, even if
+ // they are unused.
+ Record.push_back(LangOpts.MathErrno); // Math functions must respect errno
+ // (modulo the platform support).
+
+ Record.push_back(LangOpts.getSignedOverflowBehavior());
+ Record.push_back(LangOpts.HeinousExtensions);
+
+ Record.push_back(LangOpts.Optimize); // Whether __OPTIMIZE__ should be defined.
+ Record.push_back(LangOpts.OptimizeSize); // Whether __OPTIMIZE_SIZE__ should be
+ // defined.
+ Record.push_back(LangOpts.Static); // Should __STATIC__ be defined (as
+ // opposed to __DYNAMIC__).
+ Record.push_back(LangOpts.PICLevel); // The value for __PIC__, if non-zero.
+
+ Record.push_back(LangOpts.GNUInline); // Should GNU inline semantics be
+ // used (instead of C99 semantics).
+ Record.push_back(LangOpts.NoInline); // Should __NO_INLINE__ be defined.
+ Record.push_back(LangOpts.AccessControl); // Whether C++ access control should
+ // be enabled.
+ Record.push_back(LangOpts.CharIsSigned); // Whether char is a signed or
+ // unsigned type
+ Record.push_back(LangOpts.ShortWChar); // force wchar_t to be unsigned short
+ Record.push_back(LangOpts.getGCMode());
+ Record.push_back(LangOpts.getVisibilityMode());
+ Record.push_back(LangOpts.getStackProtectorMode());
+ Record.push_back(LangOpts.InstantiationDepth);
+ Record.push_back(LangOpts.OpenCL);
+ Record.push_back(LangOpts.CatchUndefined);
+ Record.push_back(LangOpts.ElideConstructors);
+ Record.push_back(LangOpts.SpellChecking);
+ Stream.EmitRecord(pch::LANGUAGE_OPTIONS, Record);
+}
+
+//===----------------------------------------------------------------------===//
+// stat cache Serialization
+//===----------------------------------------------------------------------===//
+
+namespace {
+// Trait used for the on-disk hash table of stat cache results.
+class PCHStatCacheTrait {
+public:
+ typedef const char * key_type;
+ typedef key_type key_type_ref;
+
+ typedef std::pair<int, struct stat> data_type;
+ typedef const data_type& data_type_ref;
+
+ static unsigned ComputeHash(const char *path) {
+ return llvm::HashString(path);
+ }
+
+ std::pair<unsigned,unsigned>
+ EmitKeyDataLength(llvm::raw_ostream& Out, const char *path,
+ data_type_ref Data) {
+ unsigned StrLen = strlen(path);
+ clang::io::Emit16(Out, StrLen);
+ unsigned DataLen = 1; // result value
+ if (Data.first == 0)
+ DataLen += 4 + 4 + 2 + 8 + 8;
+ clang::io::Emit8(Out, DataLen);
+ return std::make_pair(StrLen + 1, DataLen);
+ }
+
+ void EmitKey(llvm::raw_ostream& Out, const char *path, unsigned KeyLen) {
+ Out.write(path, KeyLen);
+ }
+
+ void EmitData(llvm::raw_ostream& Out, key_type_ref,
+ data_type_ref Data, unsigned DataLen) {
+ using namespace clang::io;
+ uint64_t Start = Out.tell(); (void)Start;
+
+ // Result of stat()
+ Emit8(Out, Data.first? 1 : 0);
+
+ if (Data.first == 0) {
+ Emit32(Out, (uint32_t) Data.second.st_ino);
+ Emit32(Out, (uint32_t) Data.second.st_dev);
+ Emit16(Out, (uint16_t) Data.second.st_mode);
+ Emit64(Out, (uint64_t) Data.second.st_mtime);
+ Emit64(Out, (uint64_t) Data.second.st_size);
+ }
+
+ assert(Out.tell() - Start == DataLen && "Wrong data length");
+ }
+};
+} // end anonymous namespace
+
+/// \brief Write the stat() system call cache to the PCH file.
+void PCHWriter::WriteStatCache(MemorizeStatCalls &StatCalls) {
+ // Build the on-disk hash table containing information about every
+ // stat() call.
+ OnDiskChainedHashTableGenerator<PCHStatCacheTrait> Generator;
+ unsigned NumStatEntries = 0;
+ for (MemorizeStatCalls::iterator Stat = StatCalls.begin(),
+ StatEnd = StatCalls.end();
+ Stat != StatEnd; ++Stat, ++NumStatEntries) {
+ const char *Filename = Stat->first();
+ Generator.insert(Filename, Stat->second);
+ }
+
+ // Create the on-disk hash table in a buffer.
+ llvm::SmallString<4096> StatCacheData;
+ uint32_t BucketOffset;
+ {
+ llvm::raw_svector_ostream Out(StatCacheData);
+ // Make sure that no bucket is at offset 0
+ clang::io::Emit32(Out, 0);
+ BucketOffset = Generator.Emit(Out);
+ }
+
+ // Create a blob abbreviation
+ using namespace llvm;
+ BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(pch::STAT_CACHE));
+ 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;
+ Record.push_back(pch::STAT_CACHE);
+ Record.push_back(BucketOffset);
+ Record.push_back(NumStatEntries);
+ Stream.EmitRecordWithBlob(StatCacheAbbrev, Record, StatCacheData.str());
+}
+
+//===----------------------------------------------------------------------===//
+// Source Manager Serialization
+//===----------------------------------------------------------------------===//
+
+/// \brief Create an abbreviation for the SLocEntry that refers to a
+/// file.
+static unsigned CreateSLocFileAbbrev(llvm::BitstreamWriter &Stream) {
+ using namespace llvm;
+ BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(pch::SM_SLOC_FILE_ENTRY));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Offset
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Include location
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // Characteristic
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Line directives
+ // FileEntry fields.
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 12)); // Size
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 32)); // Modification time
+ // 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
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name
+ return Stream.EmitAbbrev(Abbrev);
+}
+
+/// \brief Create an abbreviation for the SLocEntry that refers to a
+/// buffer.
+static unsigned CreateSLocBufferAbbrev(llvm::BitstreamWriter &Stream) {
+ using namespace llvm;
+ BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(pch::SM_SLOC_BUFFER_ENTRY));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Offset
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Include location
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // Characteristic
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Line directives
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Buffer name blob
+ return Stream.EmitAbbrev(Abbrev);
+}
+
+/// \brief Create an abbreviation for the SLocEntry that refers to a
+/// buffer's blob.
+static unsigned CreateSLocBufferBlobAbbrev(llvm::BitstreamWriter &Stream) {
+ using namespace llvm;
+ BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(pch::SM_SLOC_BUFFER_BLOB));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Blob
+ return Stream.EmitAbbrev(Abbrev);
+}
+
+/// \brief Create an abbreviation for the SLocEntry that refers to an
+/// buffer.
+static unsigned CreateSLocInstantiationAbbrev(llvm::BitstreamWriter &Stream) {
+ using namespace llvm;
+ BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(pch::SM_SLOC_INSTANTIATION_ENTRY));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Offset
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Spelling location
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Start location
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // End location
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Token length
+ return Stream.EmitAbbrev(Abbrev);
+}
+
+/// \brief Writes the block containing the serialized form of the
+/// source manager.
+///
+/// TODO: We should probably use an on-disk hash table (stored in a
+/// blob), indexed based on the file name, so that we only create
+/// entries for files that we actually need. In the common case (no
+/// errors), we probably won't have to create file entries for any of
+/// the files in the AST.
+void PCHWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
+ const Preprocessor &PP,
+ const char *isysroot) {
+ RecordData Record;
+
+ // Enter the source manager block.
+ Stream.EnterSubblock(pch::SOURCE_MANAGER_BLOCK_ID, 3);
+
+ // Abbreviations for the various kinds of source-location entries.
+ unsigned SLocFileAbbrv = CreateSLocFileAbbrev(Stream);
+ unsigned SLocBufferAbbrv = CreateSLocBufferAbbrev(Stream);
+ unsigned SLocBufferBlobAbbrv = CreateSLocBufferBlobAbbrev(Stream);
+ unsigned SLocInstantiationAbbrv = CreateSLocInstantiationAbbrev(Stream);
+
+ // 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);
+ Filename = adjustFilenameForRelocatablePCH(Filename, isysroot);
+ unsigned FilenameLen = Filename? strlen(Filename) : 0;
+ Record.push_back(FilenameLen);
+ if (FilenameLen)
+ Record.insert(Record.end(), Filename, Filename + FilenameLen);
+ }
+
+ // Emit the line entries
+ for (LineTableInfo::iterator L = LineTable.begin(), LEnd = LineTable.end();
+ L != LEnd; ++L) {
+ // Emit the file ID
+ Record.push_back(L->first);
+
+ // Emit the line entries
+ Record.push_back(L->second.size());
+ for (std::vector<LineEntry>::iterator LE = L->second.begin(),
+ LEEnd = L->second.end();
+ LE != LEEnd; ++LE) {
+ Record.push_back(LE->FileOffset);
+ Record.push_back(LE->LineNo);
+ Record.push_back(LE->FilenameID);
+ Record.push_back((unsigned)LE->FileKind);
+ Record.push_back(LE->IncludeOffset);
+ }
+ }
+ Stream.EmitRecord(pch::SM_LINE_TABLE, Record);
+ }
+
+ // Write out the source location entry table. We skip the first
+ // entry, which is always the same dummy entry.
+ std::vector<uint32_t> SLocEntryOffsets;
+ RecordData PreloadSLocs;
+ SLocEntryOffsets.reserve(SourceMgr.sloc_entry_size() - 1);
+ for (unsigned I = 1, N = SourceMgr.sloc_entry_size(); I != N; ++I) {
+ // Get this source location entry.
+ const SrcMgr::SLocEntry *SLoc = &SourceMgr.getSLocEntry(I);
+
+ // Record the offset of this source-location entry.
+ SLocEntryOffsets.push_back(Stream.GetCurrentBitNo());
+
+ // Figure out which record code to use.
+ unsigned Code;
+ if (SLoc->isFile()) {
+ if (SLoc->getFile().getContentCache()->Entry)
+ Code = pch::SM_SLOC_FILE_ENTRY;
+ else
+ Code = pch::SM_SLOC_BUFFER_ENTRY;
+ } else
+ Code = pch::SM_SLOC_INSTANTIATION_ENTRY;
+ Record.clear();
+ 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
+ Record.push_back(File.hasLineDirectives());
+
+ 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.
+
+ // Emit size/modification time for this file.
+ Record.push_back(Content->Entry->getSize());
+ Record.push_back(Content->Entry->getModificationTime());
+
+ // 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);
+
+ // 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));
+ FilePath.makeAbsolute();
+ Filename = FilePath.c_str();
+
+ Filename = adjustFilenameForRelocatablePCH(Filename, isysroot);
+ Stream.EmitRecordWithBlob(SLocFileAbbrv, Record, Filename);
+
+ // FIXME: For now, preload all file source locations, so that
+ // we get the appropriate File entries in the reader. This is
+ // a temporary measure.
+ PreloadSLocs.push_back(SLocEntryOffsets.size());
+ } else {
+ // The source location entry is a buffer. The blob associated
+ // with this entry contains the contents of the buffer.
+
+ // We add one to the size so that we capture the trailing NULL
+ // that is required by llvm::MemoryBuffer::getMemBuffer (on
+ // the reader side).
+ const llvm::MemoryBuffer *Buffer
+ = Content->getBuffer(PP.getDiagnostics(), PP.getSourceManager());
+ const char *Name = Buffer->getBufferIdentifier();
+ Stream.EmitRecordWithBlob(SLocBufferAbbrv, Record,
+ llvm::StringRef(Name, strlen(Name) + 1));
+ Record.clear();
+ Record.push_back(pch::SM_SLOC_BUFFER_BLOB);
+ Stream.EmitRecordWithBlob(SLocBufferBlobAbbrv, Record,
+ llvm::StringRef(Buffer->getBufferStart(),
+ Buffer->getBufferSize() + 1));
+
+ if (strcmp(Name, "<built-in>") == 0)
+ PreloadSLocs.push_back(SLocEntryOffsets.size());
+ }
+ } 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());
+
+ // Compute the token length for this macro expansion.
+ unsigned NextOffset = SourceMgr.getNextOffset();
+ if (I + 1 != N)
+ NextOffset = SourceMgr.getSLocEntry(I + 1).getOffset();
+ Record.push_back(NextOffset - SLoc->getOffset() - 1);
+ Stream.EmitRecordWithAbbrev(SLocInstantiationAbbrv, Record);
+ }
+ }
+
+ Stream.ExitBlock();
+
+ if (SLocEntryOffsets.empty())
+ return;
+
+ // Write the source-location offsets table into the PCH block. This
+ // table is used for lazily loading source-location information.
+ using namespace llvm;
+ BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(pch::SOURCE_LOCATION_OFFSETS));
+ 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);
+
+ Record.clear();
+ Record.push_back(pch::SOURCE_LOCATION_OFFSETS);
+ Record.push_back(SLocEntryOffsets.size());
+ Record.push_back(SourceMgr.getNextOffset());
+ Stream.EmitRecordWithBlob(SLocOffsetsAbbrev, Record,
+ (const char *)&SLocEntryOffsets.front(),
+ SLocEntryOffsets.size()*sizeof(SLocEntryOffsets[0]));
+
+ // Write the source location entry preloads array, telling the PCH
+ // reader which source locations entries it should load eagerly.
+ Stream.EmitRecord(pch::SOURCE_LOCATION_PRELOADS, PreloadSLocs);
+}
+
+//===----------------------------------------------------------------------===//
+// Preprocessor Serialization
+//===----------------------------------------------------------------------===//
+
+/// \brief Writes the block containing the serialized form of the
+/// preprocessor.
+///
+void PCHWriter::WritePreprocessor(const Preprocessor &PP) {
+ RecordData Record;
+
+ // If the preprocessor __COUNTER__ value has been bumped, remember it.
+ if (PP.getCounterValue() != 0) {
+ Record.push_back(PP.getCounterValue());
+ Stream.EmitRecord(pch::PP_COUNTER_VALUE, Record);
+ Record.clear();
+ }
+
+ // Enter the preprocessor block.
+ Stream.EnterSubblock(pch::PREPROCESSOR_BLOCK_ID, 2);
+
+ // If the PCH file contains __DATE__ or __TIME__ emit a warning about this.
+ // FIXME: use diagnostics subsystem for localization etc.
+ if (PP.SawDateOrTime())
+ fprintf(stderr, "warning: precompiled header used __DATE__ or __TIME__.\n");
+
+ // Loop over all the macro definitions that are live at the end of the file,
+ // emitting each to the PP section.
+ PreprocessingRecord *PPRec = PP.getPreprocessingRecord();
+ for (Preprocessor::macro_iterator I = PP.macro_begin(), E = PP.macro_end();
+ I != E; ++I) {
+ // FIXME: This emits macros in hash table order, we should do it in a stable
+ // order so that output is reproducible.
+ MacroInfo *MI = I->second;
+
+ // Don't emit builtin macros like __LINE__ to the PCH file unless they have
+ // been redefined by the header (in which case they are not isBuiltinMacro).
+ if (MI->isBuiltinMacro())
+ continue;
+
+ AddIdentifierRef(I->first, Record);
+ MacroOffsets[I->first] = Stream.GetCurrentBitNo();
+ Record.push_back(MI->getDefinitionLoc().getRawEncoding());
+ Record.push_back(MI->isUsed());
+
+ unsigned Code;
+ if (MI->isObjectLike()) {
+ Code = pch::PP_MACRO_OBJECT_LIKE;
+ } else {
+ Code = pch::PP_MACRO_FUNCTION_LIKE;
+
+ Record.push_back(MI->isC99Varargs());
+ Record.push_back(MI->isGNUVarargs());
+ Record.push_back(MI->getNumArgs());
+ for (MacroInfo::arg_iterator I = MI->arg_begin(), E = MI->arg_end();
+ I != E; ++I)
+ AddIdentifierRef(*I, Record);
+ }
+
+ // If we have a detailed preprocessing record, record the macro definition
+ // ID that corresponds to this macro.
+ if (PPRec)
+ Record.push_back(getMacroDefinitionID(PPRec->findMacroDefinition(MI)));
+
+ Stream.EmitRecord(Code, Record);
+ Record.clear();
+
+ // Emit the tokens array.
+ for (unsigned TokNo = 0, e = MI->getNumTokens(); TokNo != e; ++TokNo) {
+ // Note that we know that the preprocessor does not have any annotation
+ // tokens in it because they are created by the parser, and thus can't be
+ // in a macro definition.
+ const Token &Tok = MI->getReplacementToken(TokNo);
+
+ Record.push_back(Tok.getLocation().getRawEncoding());
+ Record.push_back(Tok.getLength());
+
+ // FIXME: When reading literal tokens, reconstruct the literal pointer if
+ // it is needed.
+ AddIdentifierRef(Tok.getIdentifierInfo(), Record);
+
+ // 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());
+
+ Stream.EmitRecord(pch::PP_TOKEN, Record);
+ Record.clear();
+ }
+ ++NumMacros;
+ }
+
+ // If the preprocessor has a preprocessing record, emit it.
+ unsigned NumPreprocessingRecords = 0;
+ if (PPRec) {
+ for (PreprocessingRecord::iterator E = PPRec->begin(), EEnd = PPRec->end();
+ E != EEnd; ++E) {
+ Record.clear();
+
+ if (MacroInstantiation *MI = dyn_cast<MacroInstantiation>(*E)) {
+ Record.push_back(NumPreprocessingRecords++);
+ AddSourceLocation(MI->getSourceRange().getBegin(), Record);
+ AddSourceLocation(MI->getSourceRange().getEnd(), Record);
+ AddIdentifierRef(MI->getName(), Record);
+ Record.push_back(getMacroDefinitionID(MI->getDefinition()));
+ Stream.EmitRecord(pch::PP_MACRO_INSTANTIATION, Record);
+ continue;
+ }
+
+ if (MacroDefinition *MD = dyn_cast<MacroDefinition>(*E)) {
+ // Record this macro definition's location.
+ pch::IdentID ID = getMacroDefinitionID(MD);
+ if (ID != MacroDefinitionOffsets.size()) {
+ if (ID > MacroDefinitionOffsets.size())
+ MacroDefinitionOffsets.resize(ID + 1);
+
+ MacroDefinitionOffsets[ID] = Stream.GetCurrentBitNo();
+ } else
+ MacroDefinitionOffsets.push_back(Stream.GetCurrentBitNo());
+
+ Record.push_back(NumPreprocessingRecords++);
+ Record.push_back(ID);
+ AddSourceLocation(MD->getSourceRange().getBegin(), Record);
+ AddSourceLocation(MD->getSourceRange().getEnd(), Record);
+ AddIdentifierRef(MD->getName(), Record);
+ AddSourceLocation(MD->getLocation(), Record);
+ Stream.EmitRecord(pch::PP_MACRO_DEFINITION, Record);
+ continue;
+ }
+ }
+ }
+
+ Stream.ExitBlock();
+
+ // 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();
+ Abbrev->Add(BitCodeAbbrevOp(pch::MACRO_DEFINITION_OFFSETS));
+ 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();
+ Record.push_back(pch::MACRO_DEFINITION_OFFSETS);
+ Record.push_back(NumPreprocessingRecords);
+ Record.push_back(MacroDefinitionOffsets.size());
+ Stream.EmitRecordWithBlob(MacroDefOffsetAbbrev, Record,
+ (const char *)&MacroDefinitionOffsets.front(),
+ MacroDefinitionOffsets.size() * sizeof(uint32_t));
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// Type Serialization
+//===----------------------------------------------------------------------===//
+
+/// \brief Write the representation of a type to the PCH stream.
+void PCHWriter::WriteType(QualType T) {
+ pch::TypeID &ID = TypeIDs[T];
+ if (ID == 0) // we haven't seen this type before.
+ ID = NextTypeID++;
+
+ // Record the offset for this type.
+ if (TypeOffsets.size() == ID - pch::NUM_PREDEF_TYPE_IDS)
+ TypeOffsets.push_back(Stream.GetCurrentBitNo());
+ else if (TypeOffsets.size() < ID - pch::NUM_PREDEF_TYPE_IDS) {
+ TypeOffsets.resize(ID + 1 - pch::NUM_PREDEF_TYPE_IDS);
+ TypeOffsets[ID - pch::NUM_PREDEF_TYPE_IDS] = Stream.GetCurrentBitNo();
+ }
+
+ RecordData Record;
+
+ // Emit the type's representation.
+ PCHTypeWriter W(*this, Record);
+
+ if (T.hasLocalNonFastQualifiers()) {
+ Qualifiers Qs = T.getLocalQualifiers();
+ AddTypeRef(T.getLocalUnqualifiedType(), Record);
+ Record.push_back(Qs.getAsOpaqueValue());
+ W.Code = pch::TYPE_EXT_QUAL;
+ } else {
+ switch (T->getTypeClass()) {
+ // For all of the concrete, non-dependent types, call the
+ // appropriate visitor function.
+#define TYPE(Class, Base) \
+ case Type::Class: W.Visit##Class##Type(cast<Class##Type>(T)); break;
+#define ABSTRACT_TYPE(Class, Base)
+#include "clang/AST/TypeNodes.def"
+ }
+ }
+
+ // Emit the serialized record.
+ Stream.EmitRecord(W.Code, Record);
+
+ // Flush any expressions that were written as part of this type.
+ FlushStmts();
+}
+
+//===----------------------------------------------------------------------===//
+// Declaration Serialization
+//===----------------------------------------------------------------------===//
+
+/// \brief Write the block containing all of the declaration IDs
+/// lexically declared within the given DeclContext.
+///
+/// \returns the offset of the DECL_CONTEXT_LEXICAL block within the
+/// bistream, or 0 if no block was written.
+uint64_t PCHWriter::WriteDeclContextLexicalBlock(ASTContext &Context,
+ DeclContext *DC) {
+ if (DC->decls_empty())
+ return 0;
+
+ uint64_t Offset = Stream.GetCurrentBitNo();
+ RecordData Record;
+ for (DeclContext::decl_iterator D = DC->decls_begin(), DEnd = DC->decls_end();
+ D != DEnd; ++D)
+ AddDeclRef(*D, Record);
+
+ ++NumLexicalDeclContexts;
+ Stream.EmitRecord(pch::DECL_CONTEXT_LEXICAL, Record);
+ return Offset;
+}
+
+/// \brief Write the block containing all of the declaration IDs
+/// visible from the given DeclContext.
+///
+/// \returns the offset of the DECL_CONTEXT_VISIBLE block within the
+/// bistream, or 0 if no block was written.
+uint64_t PCHWriter::WriteDeclContextVisibleBlock(ASTContext &Context,
+ DeclContext *DC) {
+ if (DC->getPrimaryContext() != DC)
+ return 0;
+
+ // 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.
+ DC->lookup(DeclarationName());
+
+ // Serialize the contents of the mapping used for lookup. Note that,
+ // although we have two very different code paths, the serialized
+ // representation is the same for both cases: a declaration name,
+ // followed by a size, followed by references to the visible
+ // declarations that have that name.
+ uint64_t Offset = Stream.GetCurrentBitNo();
+ RecordData Record;
+ StoredDeclsMap *Map = static_cast<StoredDeclsMap*>(DC->getLookupPtr());
+ if (!Map)
+ return 0;
+
+ for (StoredDeclsMap::iterator D = Map->begin(), DEnd = Map->end();
+ D != DEnd; ++D) {
+ AddDeclarationName(D->first, Record);
+ DeclContext::lookup_result Result = D->second.getLookupResult(Context);
+ Record.push_back(Result.second - Result.first);
+ for (; Result.first != Result.second; ++Result.first)
+ AddDeclRef(*Result.first, Record);
+ }
+
+ if (Record.size() == 0)
+ return 0;
+
+ Stream.EmitRecord(pch::DECL_CONTEXT_VISIBLE, Record);
+ ++NumVisibleDeclContexts;
+ return Offset;
+}
+
+//===----------------------------------------------------------------------===//
+// Global Method Pool and Selector Serialization
+//===----------------------------------------------------------------------===//
+
+namespace {
+// Trait used for the on-disk hash table used in the method pool.
+class PCHMethodPoolTrait {
+ PCHWriter &Writer;
+
+public:
+ typedef Selector key_type;
+ typedef key_type key_type_ref;
+
+ typedef std::pair<ObjCMethodList, ObjCMethodList> data_type;
+ typedef const data_type& data_type_ref;
+
+ explicit PCHMethodPoolTrait(PCHWriter &Writer) : Writer(Writer) { }
+
+ static unsigned ComputeHash(Selector Sel) {
+ unsigned N = Sel.getNumArgs();
+ if (N == 0)
+ ++N;
+ unsigned R = 5381;
+ for (unsigned I = 0; I != N; ++I)
+ if (IdentifierInfo *II = Sel.getIdentifierInfoForSlot(I))
+ R = llvm::HashString(II->getName(), R);
+ return R;
+ }
+
+ std::pair<unsigned,unsigned>
+ EmitKeyDataLength(llvm::raw_ostream& Out, Selector Sel,
+ data_type_ref Methods) {
+ unsigned KeyLen = 2 + (Sel.getNumArgs()? Sel.getNumArgs() * 4 : 4);
+ clang::io::Emit16(Out, KeyLen);
+ unsigned DataLen = 2 + 2; // 2 bytes for each of the method counts
+ for (const ObjCMethodList *Method = &Methods.first; Method;
+ Method = Method->Next)
+ if (Method->Method)
+ DataLen += 4;
+ for (const ObjCMethodList *Method = &Methods.second; Method;
+ Method = Method->Next)
+ if (Method->Method)
+ DataLen += 4;
+ clang::io::Emit16(Out, DataLen);
+ return std::make_pair(KeyLen, DataLen);
+ }
+
+ void EmitKey(llvm::raw_ostream& Out, Selector Sel, unsigned) {
+ uint64_t Start = Out.tell();
+ assert((Start >> 32) == 0 && "Selector key offset too large");
+ Writer.SetSelectorOffset(Sel, Start);
+ unsigned N = Sel.getNumArgs();
+ clang::io::Emit16(Out, N);
+ if (N == 0)
+ N = 1;
+ for (unsigned I = 0; I != N; ++I)
+ clang::io::Emit32(Out,
+ Writer.getIdentifierRef(Sel.getIdentifierInfoForSlot(I)));
+ }
+
+ void EmitData(llvm::raw_ostream& Out, key_type_ref,
+ data_type_ref Methods, unsigned DataLen) {
+ uint64_t Start = Out.tell(); (void)Start;
+ unsigned NumInstanceMethods = 0;
+ for (const ObjCMethodList *Method = &Methods.first; Method;
+ Method = Method->Next)
+ if (Method->Method)
+ ++NumInstanceMethods;
+
+ unsigned NumFactoryMethods = 0;
+ for (const ObjCMethodList *Method = &Methods.second; Method;
+ Method = Method->Next)
+ if (Method->Method)
+ ++NumFactoryMethods;
+
+ clang::io::Emit16(Out, NumInstanceMethods);
+ clang::io::Emit16(Out, NumFactoryMethods);
+ for (const ObjCMethodList *Method = &Methods.first; Method;
+ Method = Method->Next)
+ if (Method->Method)
+ clang::io::Emit32(Out, Writer.getDeclID(Method->Method));
+ for (const ObjCMethodList *Method = &Methods.second; Method;
+ Method = Method->Next)
+ if (Method->Method)
+ clang::io::Emit32(Out, Writer.getDeclID(Method->Method));
+
+ assert(Out.tell() - Start == DataLen && "Data length is wrong");
+ }
+};
+} // end anonymous namespace
+
+/// \brief Write the method pool into the PCH file.
+///
+/// The method pool contains both instance and factory methods, stored
+/// in an on-disk hash table indexed by the selector.
+void PCHWriter::WriteMethodPool(Sema &SemaRef) {
+ using namespace llvm;
+
+ // Create and write out the blob that contains the instance and
+ // factor method pools.
+ bool Empty = true;
+ {
+ OnDiskChainedHashTableGenerator<PCHMethodPoolTrait> Generator;
+
+ // Create the on-disk hash table representation. Start by
+ // iterating through the instance method pool.
+ PCHMethodPoolTrait::key_type Key;
+ unsigned NumSelectorsInMethodPool = 0;
+ for (llvm::DenseMap<Selector, ObjCMethodList>::iterator
+ Instance = SemaRef.InstanceMethodPool.begin(),
+ InstanceEnd = SemaRef.InstanceMethodPool.end();
+ Instance != InstanceEnd; ++Instance) {
+ // Check whether there is a factory method with the same
+ // selector.
+ llvm::DenseMap<Selector, ObjCMethodList>::iterator Factory
+ = SemaRef.FactoryMethodPool.find(Instance->first);
+
+ if (Factory == SemaRef.FactoryMethodPool.end())
+ Generator.insert(Instance->first,
+ std::make_pair(Instance->second,
+ ObjCMethodList()));
+ else
+ Generator.insert(Instance->first,
+ std::make_pair(Instance->second, Factory->second));
+
+ ++NumSelectorsInMethodPool;
+ Empty = false;
+ }
+
+ // Now iterate through the factory method pool, to pick up any
+ // selectors that weren't already in the instance method pool.
+ for (llvm::DenseMap<Selector, ObjCMethodList>::iterator
+ Factory = SemaRef.FactoryMethodPool.begin(),
+ FactoryEnd = SemaRef.FactoryMethodPool.end();
+ Factory != FactoryEnd; ++Factory) {
+ // Check whether there is an instance method with the same
+ // selector. If so, there is no work to do here.
+ llvm::DenseMap<Selector, ObjCMethodList>::iterator Instance
+ = SemaRef.InstanceMethodPool.find(Factory->first);
+
+ if (Instance == SemaRef.InstanceMethodPool.end()) {
+ Generator.insert(Factory->first,
+ std::make_pair(ObjCMethodList(), Factory->second));
+ ++NumSelectorsInMethodPool;
+ }
+
+ Empty = false;
+ }
+
+ if (Empty && SelectorOffsets.empty())
+ return;
+
+ // Create the on-disk hash table in a buffer.
+ llvm::SmallString<4096> MethodPool;
+ uint32_t BucketOffset;
+ SelectorOffsets.resize(SelVector.size());
+ {
+ PCHMethodPoolTrait Trait(*this);
+ llvm::raw_svector_ostream Out(MethodPool);
+ // Make sure that no bucket is at offset 0
+ clang::io::Emit32(Out, 0);
+ BucketOffset = Generator.Emit(Out, Trait);
+
+ // For every selector that we have seen but which was not
+ // written into the hash table, write the selector itself and
+ // record it's offset.
+ for (unsigned I = 0, N = SelVector.size(); I != N; ++I)
+ if (SelectorOffsets[I] == 0)
+ Trait.EmitKey(Out, SelVector[I], 0);
+ }
+
+ // Create a blob abbreviation
+ BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(pch::METHOD_POOL));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
+ unsigned MethodPoolAbbrev = Stream.EmitAbbrev(Abbrev);
+
+ // Write the method pool
+ RecordData Record;
+ Record.push_back(pch::METHOD_POOL);
+ Record.push_back(BucketOffset);
+ Record.push_back(NumSelectorsInMethodPool);
+ Stream.EmitRecordWithBlob(MethodPoolAbbrev, Record, MethodPool.str());
+
+ // Create a blob abbreviation for the selector table offsets.
+ Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(pch::SELECTOR_OFFSETS));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // index
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
+ unsigned SelectorOffsetAbbrev = Stream.EmitAbbrev(Abbrev);
+
+ // Write the selector offsets table.
+ Record.clear();
+ Record.push_back(pch::SELECTOR_OFFSETS);
+ Record.push_back(SelectorOffsets.size());
+ Stream.EmitRecordWithBlob(SelectorOffsetAbbrev, Record,
+ (const char *)&SelectorOffsets.front(),
+ SelectorOffsets.size() * 4);
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// Identifier Table Serialization
+//===----------------------------------------------------------------------===//
+
+namespace {
+class PCHIdentifierTableTrait {
+ PCHWriter &Writer;
+ Preprocessor &PP;
+
+ /// \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>();
+ }
+
+public:
+ typedef const IdentifierInfo* key_type;
+ typedef key_type key_type_ref;
+
+ typedef pch::IdentID data_type;
+ typedef data_type data_type_ref;
+
+ PCHIdentifierTableTrait(PCHWriter &Writer, Preprocessor &PP)
+ : Writer(Writer), PP(PP) { }
+
+ static unsigned ComputeHash(const IdentifierInfo* II) {
+ return llvm::HashString(II->getName());
+ }
+
+ std::pair<unsigned,unsigned>
+ EmitKeyDataLength(llvm::raw_ostream& Out, const IdentifierInfo* II,
+ pch::IdentID ID) {
+ unsigned KeyLen = II->getLength() + 1;
+ unsigned DataLen = 4; // 4 bytes for the persistent ID << 1
+ if (isInterestingIdentifier(II)) {
+ DataLen += 2; // 2 bytes for builtin ID, flags
+ if (II->hasMacroDefinition() &&
+ !PP.getMacroInfo(const_cast<IdentifierInfo *>(II))->isBuiltinMacro())
+ DataLen += 4;
+ for (IdentifierResolver::iterator D = IdentifierResolver::begin(II),
+ DEnd = IdentifierResolver::end();
+ D != DEnd; ++D)
+ DataLen += sizeof(pch::DeclID);
+ }
+ clang::io::Emit16(Out, DataLen);
+ // 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.
+ clang::io::Emit16(Out, KeyLen);
+ return std::make_pair(KeyLen, DataLen);
+ }
+
+ void EmitKey(llvm::raw_ostream& Out, const IdentifierInfo* II,
+ unsigned KeyLen) {
+ // Record the location of the key data. This is used when generating
+ // the mapping from persistent IDs to strings.
+ Writer.SetIdentifierOffset(II, Out.tell());
+ Out.write(II->getNameStart(), KeyLen);
+ }
+
+ void EmitData(llvm::raw_ostream& Out, const IdentifierInfo* II,
+ pch::IdentID ID, unsigned) {
+ if (!isInterestingIdentifier(II)) {
+ clang::io::Emit32(Out, ID << 1);
+ return;
+ }
+
+ clang::io::Emit32(Out, (ID << 1) | 0x01);
+ uint32_t Bits = 0;
+ bool hasMacroDefinition =
+ II->hasMacroDefinition() &&
+ !PP.getMacroInfo(const_cast<IdentifierInfo *>(II))->isBuiltinMacro();
+ Bits = (uint32_t)II->getObjCOrBuiltinID();
+ Bits = (Bits << 1) | unsigned(hasMacroDefinition);
+ Bits = (Bits << 1) | unsigned(II->isExtensionToken());
+ Bits = (Bits << 1) | unsigned(II->isPoisoned());
+ Bits = (Bits << 1) | unsigned(II->isCPlusPlusOperatorKeyword());
+ clang::io::Emit16(Out, Bits);
+
+ if (hasMacroDefinition)
+ clang::io::Emit32(Out, Writer.getMacroOffset(II));
+
+ // Emit the declaration IDs in reverse order, because the
+ // IdentifierResolver provides the declarations as they would be
+ // visible (e.g., the function "stat" would come before the struct
+ // "stat"), but IdentifierResolver::AddDeclToIdentifierChain()
+ // adds declarations to the end of the list (so we need to see the
+ // struct "status" before the function "status").
+ llvm::SmallVector<Decl *, 16> Decls(IdentifierResolver::begin(II),
+ IdentifierResolver::end());
+ for (llvm::SmallVector<Decl *, 16>::reverse_iterator D = Decls.rbegin(),
+ DEnd = Decls.rend();
+ D != DEnd; ++D)
+ clang::io::Emit32(Out, Writer.getDeclID(*D));
+ }
+};
+} // end anonymous namespace
+
+/// \brief Write the identifier table into the PCH file.
+///
+/// The identifier table consists of a blob containing string data
+/// (the actual identifiers themselves) and a separate "offsets" index
+/// that maps identifier IDs to locations within the blob.
+void PCHWriter::WriteIdentifierTable(Preprocessor &PP) {
+ using namespace llvm;
+
+ // Create and write out the blob that contains the identifier
+ // strings.
+ {
+ OnDiskChainedHashTableGenerator<PCHIdentifierTableTrait> Generator;
+
+ // 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
+ // where the user adds new macro definitions when building the PCH
+ // file.
+ for (IdentifierTable::iterator ID = PP.getIdentifierTable().begin(),
+ IDEnd = PP.getIdentifierTable().end();
+ ID != IDEnd; ++ID)
+ getIdentifierRef(ID->second);
+
+ // Create the on-disk hash table representation.
+ IdentifierOffsets.resize(IdentifierIDs.size());
+ for (llvm::DenseMap<const IdentifierInfo *, pch::IdentID>::iterator
+ ID = IdentifierIDs.begin(), IDEnd = IdentifierIDs.end();
+ ID != IDEnd; ++ID) {
+ assert(ID->first && "NULL identifier in identifier table");
+ Generator.insert(ID->first, ID->second);
+ }
+
+ // Create the on-disk hash table in a buffer.
+ llvm::SmallString<4096> IdentifierTable;
+ uint32_t BucketOffset;
+ {
+ PCHIdentifierTableTrait Trait(*this, PP);
+ llvm::raw_svector_ostream Out(IdentifierTable);
+ // Make sure that no bucket is at offset 0
+ clang::io::Emit32(Out, 0);
+ BucketOffset = Generator.Emit(Out, Trait);
+ }
+
+ // Create a blob abbreviation
+ BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(pch::IDENTIFIER_TABLE));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
+ unsigned IDTableAbbrev = Stream.EmitAbbrev(Abbrev);
+
+ // Write the identifier table
+ RecordData Record;
+ Record.push_back(pch::IDENTIFIER_TABLE);
+ Record.push_back(BucketOffset);
+ Stream.EmitRecordWithBlob(IDTableAbbrev, Record, IdentifierTable.str());
+ }
+
+ // Write the offsets table for identifier IDs.
+ BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(pch::IDENTIFIER_OFFSET));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of identifiers
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
+ unsigned IdentifierOffsetAbbrev = Stream.EmitAbbrev(Abbrev);
+
+ RecordData Record;
+ Record.push_back(pch::IDENTIFIER_OFFSET);
+ Record.push_back(IdentifierOffsets.size());
+ Stream.EmitRecordWithBlob(IdentifierOffsetAbbrev, Record,
+ (const char *)&IdentifierOffsets.front(),
+ IdentifierOffsets.size() * sizeof(uint32_t));
+}
+
+//===----------------------------------------------------------------------===//
+// General Serialization Routines
+//===----------------------------------------------------------------------===//
+
+/// \brief Write a record containing the given attributes.
+void PCHWriter::WriteAttributeRecord(const Attr *Attr) {
+ RecordData Record;
+ for (; Attr; Attr = Attr->getNext()) {
+ Record.push_back(Attr->getKind()); // FIXME: stable encoding, target attrs
+ Record.push_back(Attr->isInherited());
+ switch (Attr->getKind()) {
+ default:
+ assert(0 && "Does not support PCH writing for this attribute yet!");
+ break;
+ case attr::Alias:
+ AddString(cast<AliasAttr>(Attr)->getAliasee(), Record);
+ break;
+
+ case attr::AlignMac68k:
+ break;
+
+ case attr::Aligned:
+ Record.push_back(cast<AlignedAttr>(Attr)->getAlignment());
+ break;
+
+ case attr::AlwaysInline:
+ break;
+
+ case attr::AnalyzerNoReturn:
+ break;
+
+ case attr::Annotate:
+ AddString(cast<AnnotateAttr>(Attr)->getAnnotation(), Record);
+ break;
+
+ case attr::AsmLabel:
+ AddString(cast<AsmLabelAttr>(Attr)->getLabel(), Record);
+ break;
+
+ case attr::BaseCheck:
+ break;
+
+ case attr::Blocks:
+ Record.push_back(cast<BlocksAttr>(Attr)->getType()); // FIXME: stable
+ break;
+
+ case attr::CDecl:
+ break;
+
+ case attr::Cleanup:
+ AddDeclRef(cast<CleanupAttr>(Attr)->getFunctionDecl(), Record);
+ break;
+
+ case attr::Const:
+ break;
+
+ case attr::Constructor:
+ Record.push_back(cast<ConstructorAttr>(Attr)->getPriority());
+ break;
+
+ case attr::DLLExport:
+ case attr::DLLImport:
+ case attr::Deprecated:
+ break;
+
+ case attr::Destructor:
+ Record.push_back(cast<DestructorAttr>(Attr)->getPriority());
+ break;
+
+ case attr::FastCall:
+ case attr::Final:
+ break;
+
+ case attr::Format: {
+ const FormatAttr *Format = cast<FormatAttr>(Attr);
+ AddString(Format->getType(), Record);
+ Record.push_back(Format->getFormatIdx());
+ Record.push_back(Format->getFirstArg());
+ break;
+ }
+
+ case attr::FormatArg: {
+ const FormatArgAttr *Format = cast<FormatArgAttr>(Attr);
+ Record.push_back(Format->getFormatIdx());
+ break;
+ }
+
+ case attr::Sentinel : {
+ const SentinelAttr *Sentinel = cast<SentinelAttr>(Attr);
+ Record.push_back(Sentinel->getSentinel());
+ Record.push_back(Sentinel->getNullPos());
+ break;
+ }
+
+ case attr::GNUInline:
+ case attr::Hiding:
+ case attr::IBAction:
+ case attr::IBOutlet:
+ case attr::Malloc:
+ case attr::NoDebug:
+ case attr::NoInline:
+ case attr::NoReturn:
+ case attr::NoThrow:
+ break;
+
+ case attr::IBOutletCollection: {
+ const IBOutletCollectionAttr *ICA = cast<IBOutletCollectionAttr>(Attr);
+ AddDeclRef(ICA->getClass(), Record);
+ break;
+ }
+
+ case attr::NonNull: {
+ const NonNullAttr *NonNull = cast<NonNullAttr>(Attr);
+ Record.push_back(NonNull->size());
+ Record.insert(Record.end(), NonNull->begin(), NonNull->end());
+ break;
+ }
+
+ case attr::CFReturnsNotRetained:
+ case attr::CFReturnsRetained:
+ case attr::NSReturnsNotRetained:
+ case attr::NSReturnsRetained:
+ case attr::ObjCException:
+ case attr::ObjCNSObject:
+ case attr::Overloadable:
+ case attr::Override:
+ break;
+
+ case attr::MaxFieldAlignment:
+ Record.push_back(cast<MaxFieldAlignmentAttr>(Attr)->getAlignment());
+ break;
+
+ case attr::Packed:
+ break;
+
+ case attr::Pure:
+ break;
+
+ case attr::Regparm:
+ Record.push_back(cast<RegparmAttr>(Attr)->getNumParams());
+ break;
+
+ case attr::ReqdWorkGroupSize:
+ Record.push_back(cast<ReqdWorkGroupSizeAttr>(Attr)->getXDim());
+ Record.push_back(cast<ReqdWorkGroupSizeAttr>(Attr)->getYDim());
+ Record.push_back(cast<ReqdWorkGroupSizeAttr>(Attr)->getZDim());
+ break;
+
+ case attr::Section:
+ AddString(cast<SectionAttr>(Attr)->getName(), Record);
+ break;
+
+ case attr::StdCall:
+ case attr::TransparentUnion:
+ case attr::Unavailable:
+ case attr::Unused:
+ case attr::Used:
+ break;
+
+ case attr::Visibility:
+ // FIXME: stable encoding
+ Record.push_back(cast<VisibilityAttr>(Attr)->getVisibility());
+ break;
+
+ case attr::WarnUnusedResult:
+ case attr::Weak:
+ case attr::WeakRef:
+ case attr::WeakImport:
+ break;
+ }
+ }
+
+ Stream.EmitRecord(pch::DECL_ATTR, Record);
+}
+
+void PCHWriter::AddString(const std::string &Str, RecordData &Record) {
+ Record.push_back(Str.size());
+ Record.insert(Record.end(), Str.begin(), Str.end());
+}
+
+/// \brief Note that the identifier II occurs at the given offset
+/// within the identifier table.
+void PCHWriter::SetIdentifierOffset(const IdentifierInfo *II, uint32_t Offset) {
+ IdentifierOffsets[IdentifierIDs[II] - 1] = Offset;
+}
+
+/// \brief Note that the selector Sel occurs at the given offset
+/// within the method pool/selector table.
+void PCHWriter::SetSelectorOffset(Selector Sel, uint32_t Offset) {
+ unsigned ID = SelectorIDs[Sel];
+ assert(ID && "Unknown selector");
+ SelectorOffsets[ID - 1] = Offset;
+}
+
+PCHWriter::PCHWriter(llvm::BitstreamWriter &Stream, PCHReader *Chain)
+ : Stream(Stream), Chain(Chain), NextTypeID(pch::NUM_PREDEF_TYPE_IDS),
+ CollectedStmts(&StmtsToEmit), NumStatements(0), NumMacros(0),
+ NumLexicalDeclContexts(0), NumVisibleDeclContexts(0) {
+ if (Chain)
+ Chain->setDeserializationListener(this);
+}
+
+void PCHWriter::WritePCH(Sema &SemaRef, MemorizeStatCalls *StatCalls,
+ const char *isysroot) {
+ // Emit the file header.
+ Stream.Emit((unsigned)'C', 8);
+ Stream.Emit((unsigned)'P', 8);
+ Stream.Emit((unsigned)'C', 8);
+ Stream.Emit((unsigned)'H', 8);
+
+ WriteBlockInfoBlock();
+
+ if (Chain)
+ WritePCHChain(SemaRef, StatCalls, isysroot);
+ else
+ WritePCHCore(SemaRef, StatCalls, isysroot);
+}
+
+void PCHWriter::WritePCHCore(Sema &SemaRef, MemorizeStatCalls *StatCalls,
+ const char *isysroot) {
+ using namespace llvm;
+
+ ASTContext &Context = SemaRef.Context;
+ Preprocessor &PP = SemaRef.PP;
+
+ // The translation unit is the first declaration we'll emit.
+ DeclIDs[Context.getTranslationUnitDecl()] = 1;
+ DeclTypesToEmit.push(Context.getTranslationUnitDecl());
+
+ // 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]));
+ }
+
+ // Build a record containing all of the tentative definitions in this file, in
+ // TentativeDefinitions order. Generally, this record will be empty for
+ // headers.
+ RecordData TentativeDefinitions;
+ for (unsigned i = 0, e = SemaRef.TentativeDefinitions.size(); i != e; ++i) {
+ AddDeclRef(SemaRef.TentativeDefinitions[i], TentativeDefinitions);
+ }
+
+ // Build a record containing all of the static unused functions in this file.
+ RecordData UnusedStaticFuncs;
+ for (unsigned i=0, e = SemaRef.UnusedStaticFuncs.size(); i !=e; ++i)
+ AddDeclRef(SemaRef.UnusedStaticFuncs[i], UnusedStaticFuncs);
+
+ // Build a record containing all of the locally-scoped external
+ // declarations in this header file. Generally, this record will be
+ // empty.
+ RecordData LocallyScopedExternalDecls;
+ // FIXME: This is filling in the PCH file in densemap order which is
+ // nondeterminstic!
+ for (llvm::DenseMap<DeclarationName, NamedDecl *>::iterator
+ TD = SemaRef.LocallyScopedExternalDecls.begin(),
+ TDEnd = SemaRef.LocallyScopedExternalDecls.end();
+ TD != TDEnd; ++TD)
+ 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)
+ AddDeclRef(SemaRef.ExtVectorDecls[I], ExtVectorDecls);
+
+ // Build a record containing all of the VTable uses information.
+ RecordData VTableUses;
+ 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)
+ AddDeclRef(SemaRef.DynamicClasses[I], DynamicClasses);
+
+ // Write the remaining PCH contents.
+ RecordData Record;
+ Stream.EnterSubblock(pch::PCH_BLOCK_ID, 5);
+ WriteMetadata(Context, isysroot);
+ WriteLanguageOptions(Context.getLangOptions());
+ if (StatCalls && !isysroot)
+ WriteStatCache(*StatCalls);
+ WriteSourceManagerBlock(Context.getSourceManager(), PP, isysroot);
+ // Write the record of special types.
+ Record.clear();
+
+ 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);
+ AddTypeRef(Context.getjmp_bufType(), Record);
+ AddTypeRef(Context.getsigjmp_bufType(), Record);
+ AddTypeRef(Context.ObjCIdRedefinitionType, Record);
+ AddTypeRef(Context.ObjCClassRedefinitionType, Record);
+ AddTypeRef(Context.getRawBlockdescriptorType(), Record);
+ AddTypeRef(Context.getRawBlockdescriptorExtendedType(), Record);
+ AddTypeRef(Context.ObjCSelRedefinitionType, Record);
+ AddTypeRef(Context.getRawNSConstantStringType(), Record);
+ Record.push_back(Context.isInt128Installed());
+ Stream.EmitRecord(pch::SPECIAL_TYPES, Record);
+
+ // Keep writing types and declarations until all types and
+ // declarations have been written.
+ Stream.EnterSubblock(pch::DECLTYPES_BLOCK_ID, 3);
+ WriteDeclsBlockAbbrevs();
+ while (!DeclTypesToEmit.empty()) {
+ DeclOrType DOT = DeclTypesToEmit.front();
+ DeclTypesToEmit.pop();
+ if (DOT.isType())
+ WriteType(DOT.getType());
+ else
+ WriteDecl(Context, DOT.getDecl());
+ }
+ Stream.ExitBlock();
+
+ WritePreprocessor(PP);
+ WriteMethodPool(SemaRef);
+ WriteIdentifierTable(PP);
+
+ // Write the type offsets array
+ BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(pch::TYPE_OFFSET));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of types
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // types block
+ unsigned TypeOffsetAbbrev = Stream.EmitAbbrev(Abbrev);
+ Record.clear();
+ Record.push_back(pch::TYPE_OFFSET);
+ Record.push_back(TypeOffsets.size());
+ Stream.EmitRecordWithBlob(TypeOffsetAbbrev, Record,
+ (const char *)&TypeOffsets.front(),
+ TypeOffsets.size() * sizeof(TypeOffsets[0]));
+
+ // Write the declaration offsets array
+ Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(pch::DECL_OFFSET));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of declarations
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // declarations block
+ unsigned DeclOffsetAbbrev = Stream.EmitAbbrev(Abbrev);
+ Record.clear();
+ Record.push_back(pch::DECL_OFFSET);
+ Record.push_back(DeclOffsets.size());
+ Stream.EmitRecordWithBlob(DeclOffsetAbbrev, Record,
+ (const char *)&DeclOffsets.front(),
+ DeclOffsets.size() * sizeof(DeclOffsets[0]));
+
+ // Write the record containing external, unnamed definitions.
+ if (!ExternalDefinitions.empty())
+ Stream.EmitRecord(pch::EXTERNAL_DEFINITIONS, ExternalDefinitions);
+
+ // Write the record containing tentative definitions.
+ if (!TentativeDefinitions.empty())
+ Stream.EmitRecord(pch::TENTATIVE_DEFINITIONS, TentativeDefinitions);
+
+ // Write the record containing unused static functions.
+ if (!UnusedStaticFuncs.empty())
+ Stream.EmitRecord(pch::UNUSED_STATIC_FUNCS, UnusedStaticFuncs);
+
+ // Write the record containing locally-scoped external definitions.
+ if (!LocallyScopedExternalDecls.empty())
+ Stream.EmitRecord(pch::LOCALLY_SCOPED_EXTERNAL_DECLS,
+ LocallyScopedExternalDecls);
+
+ // Write the record containing ext_vector type names.
+ if (!ExtVectorDecls.empty())
+ Stream.EmitRecord(pch::EXT_VECTOR_DECLS, ExtVectorDecls);
+
+ // Write the record containing VTable uses information.
+ if (!VTableUses.empty())
+ Stream.EmitRecord(pch::VTABLE_USES, VTableUses);
+
+ // Write the record containing dynamic classes declarations.
+ if (!DynamicClasses.empty())
+ Stream.EmitRecord(pch::DYNAMIC_CLASSES, DynamicClasses);
+
+ // Some simple statistics
+ Record.clear();
+ Record.push_back(NumStatements);
+ Record.push_back(NumMacros);
+ Record.push_back(NumLexicalDeclContexts);
+ Record.push_back(NumVisibleDeclContexts);
+ Stream.EmitRecord(pch::STATISTICS, Record);
+ Stream.ExitBlock();
+}
+
+void PCHWriter::WritePCHChain(Sema &SemaRef, MemorizeStatCalls *StatCalls,
+ const char *isysroot) {
+ using namespace llvm;
+
+ ASTContext &Context = SemaRef.Context;
+ Preprocessor &PP = SemaRef.PP;
+ (void)PP;
+
+ RecordData Record;
+ Stream.EnterSubblock(pch::PCH_BLOCK_ID, 5);
+ WriteMetadata(Context, isysroot);
+ // FIXME: StatCache
+ // FIXME: Source manager block
+
+ // The special types are in the chained PCH.
+
+ // We don't start with the translation unit, but with its decls that
+ // don't come from the other PCH.
+ const TranslationUnitDecl *TU = Context.getTranslationUnitDecl();
+ // FIXME: We don't want to iterate over everything here, because it needlessly
+ // deserializes the entire original PCH. Instead we only want to iterate over
+ // the stuff that's already there.
+ // All in good time, though.
+ for (DeclContext::decl_iterator I = TU->decls_begin(), E = TU->decls_end();
+ I != E; ++I) {
+ if ((*I)->getPCHLevel() == 0) {
+ (*I)->dump();
+ DeclTypesToEmit.push(*I);
+ }
+ }
+
+ Stream.EnterSubblock(pch::DECLTYPES_BLOCK_ID, 3);
+ WriteDeclsBlockAbbrevs();
+ while (!DeclTypesToEmit.empty()) {
+ DeclOrType DOT = DeclTypesToEmit.front();
+ DeclTypesToEmit.pop();
+ if (DOT.isType())
+ WriteType(DOT.getType());
+ else
+ WriteDecl(Context, DOT.getDecl());
+ }
+ Stream.ExitBlock();
+
+ // FIXME: Preprocessor
+ // FIXME: Method pool
+ // FIXME: Identifier table
+ // FIXME: Type offsets
+ // FIXME: Declaration offsets
+ // FIXME: External unnamed definitions
+ // FIXME: Tentative definitions
+ // FIXME: Unused static functions
+ // FIXME: Locally-scoped external definitions
+ // FIXME: ext_vector type names
+ // FIXME: Dynamic classes declarations
+ // FIXME: Statistics
+ Stream.ExitBlock();
+}
+
+void PCHWriter::AddSourceLocation(SourceLocation Loc, RecordData &Record) {
+ Record.push_back(Loc.getRawEncoding());
+}
+
+void PCHWriter::AddSourceRange(SourceRange Range, RecordData &Record) {
+ AddSourceLocation(Range.getBegin(), Record);
+ AddSourceLocation(Range.getEnd(), Record);
+}
+
+void PCHWriter::AddAPInt(const llvm::APInt &Value, RecordData &Record) {
+ Record.push_back(Value.getBitWidth());
+ unsigned N = Value.getNumWords();
+ const uint64_t* Words = Value.getRawData();
+ for (unsigned I = 0; I != N; ++I)
+ Record.push_back(Words[I]);
+}
+
+void PCHWriter::AddAPSInt(const llvm::APSInt &Value, RecordData &Record) {
+ Record.push_back(Value.isUnsigned());
+ AddAPInt(Value, Record);
+}
+
+void PCHWriter::AddAPFloat(const llvm::APFloat &Value, RecordData &Record) {
+ AddAPInt(Value.bitcastToAPInt(), Record);
+}
+
+void PCHWriter::AddIdentifierRef(const IdentifierInfo *II, RecordData &Record) {
+ Record.push_back(getIdentifierRef(II));
+}
+
+pch::IdentID PCHWriter::getIdentifierRef(const IdentifierInfo *II) {
+ if (II == 0)
+ return 0;
+
+ pch::IdentID &ID = IdentifierIDs[II];
+ if (ID == 0)
+ ID = IdentifierIDs.size();
+ return ID;
+}
+
+pch::IdentID PCHWriter::getMacroDefinitionID(MacroDefinition *MD) {
+ if (MD == 0)
+ return 0;
+
+ pch::IdentID &ID = MacroDefinitions[MD];
+ if (ID == 0)
+ ID = MacroDefinitions.size();
+ return ID;
+}
+
+void PCHWriter::AddSelectorRef(const Selector SelRef, RecordData &Record) {
+ if (SelRef.getAsOpaquePtr() == 0) {
+ Record.push_back(0);
+ return;
+ }
+
+ pch::SelectorID &SID = SelectorIDs[SelRef];
+ if (SID == 0) {
+ SID = SelectorIDs.size();
+ SelVector.push_back(SelRef);
+ }
+ Record.push_back(SID);
+}
+
+void PCHWriter::AddCXXTemporary(const CXXTemporary *Temp, RecordData &Record) {
+ AddDeclRef(Temp->getDestructor(), Record);
+}
+
+void PCHWriter::AddTemplateArgumentLocInfo(TemplateArgument::ArgKind Kind,
+ const TemplateArgumentLocInfo &Arg,
+ RecordData &Record) {
+ switch (Kind) {
+ case TemplateArgument::Expression:
+ AddStmt(Arg.getAsExpr());
+ break;
+ case TemplateArgument::Type:
+ AddTypeSourceInfo(Arg.getAsTypeSourceInfo(), Record);
+ break;
+ case TemplateArgument::Template:
+ AddSourceRange(Arg.getTemplateQualifierRange(), Record);
+ AddSourceLocation(Arg.getTemplateNameLoc(), Record);
+ break;
+ case TemplateArgument::Null:
+ case TemplateArgument::Integral:
+ case TemplateArgument::Declaration:
+ case TemplateArgument::Pack:
+ break;
+ }
+}
+
+void PCHWriter::AddTemplateArgumentLoc(const TemplateArgumentLoc &Arg,
+ RecordData &Record) {
+ AddTemplateArgument(Arg.getArgument(), Record);
+
+ 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.
+ }
+ AddTemplateArgumentLocInfo(Arg.getArgument().getKind(), Arg.getLocInfo(),
+ Record);
+}
+
+void PCHWriter::AddTypeSourceInfo(TypeSourceInfo *TInfo, RecordData &Record) {
+ if (TInfo == 0) {
+ AddTypeRef(QualType(), Record);
+ return;
+ }
+
+ AddTypeRef(TInfo->getType(), Record);
+ TypeLocWriter TLW(*this, Record);
+ for (TypeLoc TL = TInfo->getTypeLoc(); !TL.isNull(); TL = TL.getNextTypeLoc())
+ TLW.Visit(TL);
+}
+
+void PCHWriter::AddTypeRef(QualType T, RecordData &Record) {
+ if (T.isNull()) {
+ Record.push_back(pch::PREDEF_TYPE_NULL_ID);
+ return;
+ }
+
+ unsigned FastQuals = T.getLocalFastQualifiers();
+ T.removeFastQualifiers();
+
+ if (T.hasLocalNonFastQualifiers()) {
+ pch::TypeID &ID = TypeIDs[T];
+ if (ID == 0) {
+ // We haven't seen these qualifiers applied to this type before.
+ // Assign it a new ID. This is the only time we enqueue a
+ // qualified type, and it has no CV qualifiers.
+ ID = NextTypeID++;
+ DeclTypesToEmit.push(T);
+ }
+
+ // Encode the type qualifiers in the type reference.
+ Record.push_back((ID << Qualifiers::FastWidth) | FastQuals);
+ return;
+ }
+
+ assert(!T.hasLocalQualifiers());
+
+ if (const BuiltinType *BT = dyn_cast<BuiltinType>(T.getTypePtr())) {
+ pch::TypeID ID = 0;
+ switch (BT->getKind()) {
+ case BuiltinType::Void: ID = pch::PREDEF_TYPE_VOID_ID; break;
+ case BuiltinType::Bool: ID = pch::PREDEF_TYPE_BOOL_ID; break;
+ case BuiltinType::Char_U: ID = pch::PREDEF_TYPE_CHAR_U_ID; break;
+ case BuiltinType::UChar: ID = pch::PREDEF_TYPE_UCHAR_ID; break;
+ case BuiltinType::UShort: ID = pch::PREDEF_TYPE_USHORT_ID; break;
+ case BuiltinType::UInt: ID = pch::PREDEF_TYPE_UINT_ID; break;
+ case BuiltinType::ULong: ID = pch::PREDEF_TYPE_ULONG_ID; break;
+ case BuiltinType::ULongLong: ID = pch::PREDEF_TYPE_ULONGLONG_ID; break;
+ case BuiltinType::UInt128: ID = pch::PREDEF_TYPE_UINT128_ID; break;
+ case BuiltinType::Char_S: ID = pch::PREDEF_TYPE_CHAR_S_ID; break;
+ case BuiltinType::SChar: ID = pch::PREDEF_TYPE_SCHAR_ID; break;
+ case BuiltinType::WChar: ID = pch::PREDEF_TYPE_WCHAR_ID; break;
+ case BuiltinType::Short: ID = pch::PREDEF_TYPE_SHORT_ID; break;
+ case BuiltinType::Int: ID = pch::PREDEF_TYPE_INT_ID; break;
+ case BuiltinType::Long: ID = pch::PREDEF_TYPE_LONG_ID; break;
+ case BuiltinType::LongLong: ID = pch::PREDEF_TYPE_LONGLONG_ID; break;
+ case BuiltinType::Int128: ID = pch::PREDEF_TYPE_INT128_ID; break;
+ case BuiltinType::Float: ID = pch::PREDEF_TYPE_FLOAT_ID; break;
+ case BuiltinType::Double: ID = pch::PREDEF_TYPE_DOUBLE_ID; break;
+ case BuiltinType::LongDouble: ID = pch::PREDEF_TYPE_LONGDOUBLE_ID; break;
+ case BuiltinType::NullPtr: ID = pch::PREDEF_TYPE_NULLPTR_ID; break;
+ case BuiltinType::Char16: ID = pch::PREDEF_TYPE_CHAR16_ID; break;
+ case BuiltinType::Char32: ID = pch::PREDEF_TYPE_CHAR32_ID; break;
+ case BuiltinType::Overload: ID = pch::PREDEF_TYPE_OVERLOAD_ID; break;
+ case BuiltinType::Dependent: ID = pch::PREDEF_TYPE_DEPENDENT_ID; break;
+ case BuiltinType::ObjCId: ID = pch::PREDEF_TYPE_OBJC_ID; break;
+ case BuiltinType::ObjCClass: ID = pch::PREDEF_TYPE_OBJC_CLASS; break;
+ case BuiltinType::ObjCSel: ID = pch::PREDEF_TYPE_OBJC_SEL; break;
+ case BuiltinType::UndeducedAuto:
+ assert(0 && "Should not see undeduced auto here");
+ break;
+ }
+
+ Record.push_back((ID << Qualifiers::FastWidth) | FastQuals);
+ return;
+ }
+
+ pch::TypeID &ID = TypeIDs[T];
+ if (ID == 0) {
+ // We haven't seen this type before. Assign it a new ID and put it
+ // into the queue of types to emit.
+ ID = NextTypeID++;
+ DeclTypesToEmit.push(T);
+ }
+
+ // Encode the type qualifiers in the type reference.
+ Record.push_back((ID << Qualifiers::FastWidth) | FastQuals);
+}
+
+void PCHWriter::AddDeclRef(const Decl *D, RecordData &Record) {
+ if (D == 0) {
+ Record.push_back(0);
+ return;
+ }
+
+ pch::DeclID &ID = DeclIDs[D];
+ if (ID == 0) {
+ // We haven't seen this declaration before. Give it a new ID and
+ // enqueue it in the list of declarations to emit.
+ ID = DeclIDs.size();
+ DeclTypesToEmit.push(const_cast<Decl *>(D));
+ }
+
+ Record.push_back(ID);
+}
+
+pch::DeclID PCHWriter::getDeclID(const Decl *D) {
+ if (D == 0)
+ return 0;
+
+ assert(DeclIDs.find(D) != DeclIDs.end() && "Declaration not emitted!");
+ return DeclIDs[D];
+}
+
+void PCHWriter::AddDeclarationName(DeclarationName Name, RecordData &Record) {
+ // FIXME: Emit a stable enum for NameKind. 0 = Identifier etc.
+ 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:
+ AddSelectorRef(Name.getObjCSelector(), Record);
+ break;
+
+ case DeclarationName::CXXConstructorName:
+ case DeclarationName::CXXDestructorName:
+ case DeclarationName::CXXConversionFunctionName:
+ AddTypeRef(Name.getCXXNameType(), Record);
+ break;
+
+ case DeclarationName::CXXOperatorName:
+ Record.push_back(Name.getCXXOverloadedOperator());
+ break;
+
+ case DeclarationName::CXXLiteralOperatorName:
+ AddIdentifierRef(Name.getCXXLiteralIdentifier(), Record);
+ break;
+
+ case DeclarationName::CXXUsingDirective:
+ // No extra data to emit
+ break;
+ }
+}
+
+void PCHWriter::AddNestedNameSpecifier(NestedNameSpecifier *NNS,
+ 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;
+ }
+ }
+}
+
+void PCHWriter::AddTemplateName(TemplateName Name, RecordData &Record) {
+ 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;
+ }
+ }
+}
+
+void PCHWriter::AddTemplateArgument(const TemplateArgument &Arg,
+ 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;
+ }
+}
+
+void
+PCHWriter::AddTemplateParameterList(const TemplateParameterList *TemplateParams,
+ 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
+PCHWriter::AddTemplateArgumentList(const TemplateArgumentList *TemplateArgs,
+ 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);
+}
+
+
+void
+PCHWriter::AddUnresolvedSet(const UnresolvedSetImpl &Set, RecordData &Record) {
+ 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());
+ }
+}
+
+void PCHWriter::AddCXXBaseSpecifier(const CXXBaseSpecifier &Base,
+ RecordData &Record) {
+ Record.push_back(Base.isVirtual());
+ Record.push_back(Base.isBaseOfClass());
+ Record.push_back(Base.getAccessSpecifierAsWritten());
+ AddTypeRef(Base.getType(), Record);
+ AddSourceRange(Base.getSourceRange(), Record);
+}
+
+void PCHWriter::TypeRead(pch::TypeID ID, QualType T) {
+}
+
+void PCHWriter::DeclRead(pch::DeclID ID, const Decl *D) {
+}
+
diff --git a/contrib/llvm/tools/clang/lib/Frontend/PCHWriterDecl.cpp b/contrib/llvm/tools/clang/lib/Frontend/PCHWriterDecl.cpp
new file mode 100644
index 0000000..bc4452e
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Frontend/PCHWriterDecl.cpp
@@ -0,0 +1,1172 @@
+//===--- PCHWriterDecl.cpp - Declaration Serialization --------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements serialization for Declarations.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/PCHWriter.h"
+#include "clang/AST/DeclVisitor.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/Expr.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Bitcode/BitstreamWriter.h"
+#include "llvm/Support/ErrorHandling.h"
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// Declaration serialization
+//===----------------------------------------------------------------------===//
+
+namespace clang {
+ class PCHDeclWriter : public DeclVisitor<PCHDeclWriter, void> {
+
+ PCHWriter &Writer;
+ ASTContext &Context;
+ PCHWriter::RecordData &Record;
+
+ public:
+ pch::DeclCode Code;
+ unsigned AbbrevToUse;
+
+ PCHDeclWriter(PCHWriter &Writer, ASTContext &Context,
+ PCHWriter::RecordData &Record)
+ : Writer(Writer), Context(Context), Record(Record) {
+ }
+
+ void Visit(Decl *D);
+
+ void VisitDecl(Decl *D);
+ void VisitTranslationUnitDecl(TranslationUnitDecl *D);
+ void VisitNamedDecl(NamedDecl *D);
+ void VisitNamespaceDecl(NamespaceDecl *D);
+ void VisitUsingDirectiveDecl(UsingDirectiveDecl *D);
+ void VisitNamespaceAliasDecl(NamespaceAliasDecl *D);
+ void VisitTypeDecl(TypeDecl *D);
+ void VisitTypedefDecl(TypedefDecl *D);
+ void VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D);
+ void VisitTagDecl(TagDecl *D);
+ void VisitEnumDecl(EnumDecl *D);
+ void VisitRecordDecl(RecordDecl *D);
+ void VisitCXXRecordDecl(CXXRecordDecl *D);
+ void VisitClassTemplateSpecializationDecl(
+ ClassTemplateSpecializationDecl *D);
+ void VisitClassTemplatePartialSpecializationDecl(
+ ClassTemplatePartialSpecializationDecl *D);
+ void VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D);
+ void VisitValueDecl(ValueDecl *D);
+ void VisitEnumConstantDecl(EnumConstantDecl *D);
+ void VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D);
+ void VisitDeclaratorDecl(DeclaratorDecl *D);
+ void VisitFunctionDecl(FunctionDecl *D);
+ void VisitCXXMethodDecl(CXXMethodDecl *D);
+ void VisitCXXConstructorDecl(CXXConstructorDecl *D);
+ void VisitCXXDestructorDecl(CXXDestructorDecl *D);
+ void VisitCXXConversionDecl(CXXConversionDecl *D);
+ void VisitFieldDecl(FieldDecl *D);
+ void VisitVarDecl(VarDecl *D);
+ void VisitImplicitParamDecl(ImplicitParamDecl *D);
+ void VisitParmVarDecl(ParmVarDecl *D);
+ void VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D);
+ void VisitTemplateDecl(TemplateDecl *D);
+ void VisitClassTemplateDecl(ClassTemplateDecl *D);
+ void VisitFunctionTemplateDecl(FunctionTemplateDecl *D);
+ void VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D);
+ void VisitUsingDecl(UsingDecl *D);
+ void VisitUsingShadowDecl(UsingShadowDecl *D);
+ void VisitLinkageSpecDecl(LinkageSpecDecl *D);
+ void VisitFileScopeAsmDecl(FileScopeAsmDecl *D);
+ void VisitAccessSpecDecl(AccessSpecDecl *D);
+ void VisitFriendDecl(FriendDecl *D);
+ void VisitFriendTemplateDecl(FriendTemplateDecl *D);
+ void VisitStaticAssertDecl(StaticAssertDecl *D);
+ void VisitBlockDecl(BlockDecl *D);
+
+ void VisitDeclContext(DeclContext *DC, uint64_t LexicalOffset,
+ uint64_t VisibleOffset);
+
+
+ // FIXME: Put in the same order is DeclNodes.td?
+ void VisitObjCMethodDecl(ObjCMethodDecl *D);
+ void VisitObjCContainerDecl(ObjCContainerDecl *D);
+ void VisitObjCInterfaceDecl(ObjCInterfaceDecl *D);
+ void VisitObjCIvarDecl(ObjCIvarDecl *D);
+ void VisitObjCProtocolDecl(ObjCProtocolDecl *D);
+ void VisitObjCAtDefsFieldDecl(ObjCAtDefsFieldDecl *D);
+ void VisitObjCClassDecl(ObjCClassDecl *D);
+ void VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D);
+ void VisitObjCCategoryDecl(ObjCCategoryDecl *D);
+ void VisitObjCImplDecl(ObjCImplDecl *D);
+ void VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D);
+ void VisitObjCImplementationDecl(ObjCImplementationDecl *D);
+ void VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *D);
+ void VisitObjCPropertyDecl(ObjCPropertyDecl *D);
+ void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D);
+ };
+}
+
+void PCHDeclWriter::Visit(Decl *D) {
+ DeclVisitor<PCHDeclWriter>::Visit(D);
+
+ // Handle FunctionDecl's body here and write it after all other Stmts/Exprs
+ // have been written. We want it last because we will not read it back when
+ // retrieving it from the PCH, we'll just lazily set the offset.
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ Record.push_back(FD->isThisDeclarationADefinition());
+ if (FD->isThisDeclarationADefinition())
+ Writer.AddStmt(FD->getBody());
+ }
+}
+
+void PCHDeclWriter::VisitDecl(Decl *D) {
+ Writer.AddDeclRef(cast_or_null<Decl>(D->getDeclContext()), Record);
+ Writer.AddDeclRef(cast_or_null<Decl>(D->getLexicalDeclContext()), Record);
+ Writer.AddSourceLocation(D->getLocation(), Record);
+ Record.push_back(D->isInvalidDecl());
+ Record.push_back(D->hasAttrs());
+ Record.push_back(D->isImplicit());
+ Record.push_back(D->isUsed(false));
+ Record.push_back(D->getAccess());
+ Record.push_back(D->getPCHLevel());
+}
+
+void PCHDeclWriter::VisitTranslationUnitDecl(TranslationUnitDecl *D) {
+ VisitDecl(D);
+ Writer.AddDeclRef(D->getAnonymousNamespace(), Record);
+ Code = pch::DECL_TRANSLATION_UNIT;
+}
+
+void PCHDeclWriter::VisitNamedDecl(NamedDecl *D) {
+ VisitDecl(D);
+ Writer.AddDeclarationName(D->getDeclName(), Record);
+}
+
+void PCHDeclWriter::VisitTypeDecl(TypeDecl *D) {
+ VisitNamedDecl(D);
+ Writer.AddTypeRef(QualType(D->getTypeForDecl(), 0), Record);
+}
+
+void PCHDeclWriter::VisitTypedefDecl(TypedefDecl *D) {
+ VisitTypeDecl(D);
+ Writer.AddTypeSourceInfo(D->getTypeSourceInfo(), Record);
+ Code = pch::DECL_TYPEDEF;
+}
+
+void PCHDeclWriter::VisitTagDecl(TagDecl *D) {
+ VisitTypeDecl(D);
+ Record.push_back(D->getIdentifierNamespace());
+ Writer.AddDeclRef(D->getPreviousDeclaration(), Record);
+ Record.push_back((unsigned)D->getTagKind()); // FIXME: stable encoding
+ Record.push_back(D->isDefinition());
+ Record.push_back(D->isEmbeddedInDeclarator());
+ Writer.AddSourceLocation(D->getRBraceLoc(), Record);
+ Writer.AddSourceLocation(D->getTagKeywordLoc(), Record);
+ // FIXME: maybe write optional qualifier and its range.
+ Writer.AddDeclRef(D->getTypedefForAnonDecl(), Record);
+}
+
+void PCHDeclWriter::VisitEnumDecl(EnumDecl *D) {
+ VisitTagDecl(D);
+ Writer.AddTypeRef(D->getIntegerType(), Record);
+ Writer.AddTypeRef(D->getPromotionType(), Record);
+ Record.push_back(D->getNumPositiveBits());
+ Record.push_back(D->getNumNegativeBits());
+ Writer.AddDeclRef(D->getInstantiatedFromMemberEnum(), Record);
+ Code = pch::DECL_ENUM;
+}
+
+void PCHDeclWriter::VisitRecordDecl(RecordDecl *D) {
+ VisitTagDecl(D);
+ Record.push_back(D->hasFlexibleArrayMember());
+ Record.push_back(D->isAnonymousStructOrUnion());
+ Record.push_back(D->hasObjectMember());
+ Code = pch::DECL_RECORD;
+}
+
+void PCHDeclWriter::VisitValueDecl(ValueDecl *D) {
+ VisitNamedDecl(D);
+ Writer.AddTypeRef(D->getType(), Record);
+}
+
+void PCHDeclWriter::VisitEnumConstantDecl(EnumConstantDecl *D) {
+ VisitValueDecl(D);
+ Record.push_back(D->getInitExpr()? 1 : 0);
+ if (D->getInitExpr())
+ Writer.AddStmt(D->getInitExpr());
+ Writer.AddAPSInt(D->getInitVal(), Record);
+ Code = pch::DECL_ENUM_CONSTANT;
+}
+
+void PCHDeclWriter::VisitDeclaratorDecl(DeclaratorDecl *D) {
+ VisitValueDecl(D);
+ Writer.AddTypeSourceInfo(D->getTypeSourceInfo(), Record);
+ // FIXME: write optional qualifier and its range.
+}
+
+void PCHDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
+ VisitDeclaratorDecl(D);
+
+ Record.push_back(D->getIdentifierNamespace());
+ Record.push_back(D->getTemplatedKind());
+ switch (D->getTemplatedKind()) {
+ default: assert(false && "Unhandled TemplatedKind!");
+ break;
+ case FunctionDecl::TK_NonTemplate:
+ break;
+ case FunctionDecl::TK_FunctionTemplate:
+ Writer.AddDeclRef(D->getDescribedFunctionTemplate(), Record);
+ break;
+ case FunctionDecl::TK_MemberSpecialization: {
+ MemberSpecializationInfo *MemberInfo = D->getMemberSpecializationInfo();
+ Writer.AddDeclRef(MemberInfo->getInstantiatedFrom(), Record);
+ Record.push_back(MemberInfo->getTemplateSpecializationKind());
+ Writer.AddSourceLocation(MemberInfo->getPointOfInstantiation(), Record);
+ break;
+ }
+ case FunctionDecl::TK_FunctionTemplateSpecialization: {
+ FunctionTemplateSpecializationInfo *
+ FTSInfo = D->getTemplateSpecializationInfo();
+ // We want it canonical to guarantee that it has a Common*.
+ Writer.AddDeclRef(FTSInfo->getTemplate()->getCanonicalDecl(), Record);
+ Record.push_back(FTSInfo->getTemplateSpecializationKind());
+
+ // Template arguments.
+ Writer.AddTemplateArgumentList(FTSInfo->TemplateArguments, Record);
+
+ // Template args as written.
+ Record.push_back(FTSInfo->TemplateArgumentsAsWritten != 0);
+ if (FTSInfo->TemplateArgumentsAsWritten) {
+ Record.push_back(FTSInfo->TemplateArgumentsAsWritten->size());
+ for (int i=0, e = FTSInfo->TemplateArgumentsAsWritten->size(); i!=e; ++i)
+ Writer.AddTemplateArgumentLoc((*FTSInfo->TemplateArgumentsAsWritten)[i],
+ Record);
+ Writer.AddSourceLocation(FTSInfo->TemplateArgumentsAsWritten->getLAngleLoc(),
+ Record);
+ Writer.AddSourceLocation(FTSInfo->TemplateArgumentsAsWritten->getRAngleLoc(),
+ Record);
+ }
+
+ Writer.AddSourceLocation(FTSInfo->getPointOfInstantiation(), Record);
+ break;
+ }
+ case FunctionDecl::TK_DependentFunctionTemplateSpecialization: {
+ DependentFunctionTemplateSpecializationInfo *
+ DFTSInfo = D->getDependentSpecializationInfo();
+
+ // Templates.
+ Record.push_back(DFTSInfo->getNumTemplates());
+ for (int i=0, e = DFTSInfo->getNumTemplates(); i != e; ++i)
+ Writer.AddDeclRef(DFTSInfo->getTemplate(i), Record);
+
+ // Templates args.
+ Record.push_back(DFTSInfo->getNumTemplateArgs());
+ for (int i=0, e = DFTSInfo->getNumTemplateArgs(); i != e; ++i)
+ Writer.AddTemplateArgumentLoc(DFTSInfo->getTemplateArg(i), Record);
+ Writer.AddSourceLocation(DFTSInfo->getLAngleLoc(), Record);
+ Writer.AddSourceLocation(DFTSInfo->getRAngleLoc(), Record);
+ break;
+ }
+ }
+
+ // FunctionDecl's body is handled last at PCHWriterDecl::Visit,
+ // after everything else is written.
+
+ Writer.AddDeclRef(D->getPreviousDeclaration(), Record);
+ Record.push_back(D->getStorageClass()); // FIXME: stable encoding
+ Record.push_back(D->getStorageClassAsWritten());
+ Record.push_back(D->isInlineSpecified());
+ Record.push_back(D->isVirtualAsWritten());
+ Record.push_back(D->isPure());
+ Record.push_back(D->hasInheritedPrototype());
+ Record.push_back(D->hasWrittenPrototype());
+ Record.push_back(D->isDeleted());
+ Record.push_back(D->isTrivial());
+ Record.push_back(D->isCopyAssignment());
+ Record.push_back(D->hasImplicitReturnZero());
+ Writer.AddSourceLocation(D->getLocEnd(), Record);
+
+ Record.push_back(D->param_size());
+ for (FunctionDecl::param_iterator P = D->param_begin(), PEnd = D->param_end();
+ P != PEnd; ++P)
+ Writer.AddDeclRef(*P, Record);
+ Code = pch::DECL_FUNCTION;
+}
+
+void PCHDeclWriter::VisitObjCMethodDecl(ObjCMethodDecl *D) {
+ VisitNamedDecl(D);
+ // FIXME: convert to LazyStmtPtr?
+ // Unlike C/C++, method bodies will never be in header files.
+ Record.push_back(D->getBody() != 0);
+ if (D->getBody() != 0) {
+ Writer.AddStmt(D->getBody());
+ Writer.AddDeclRef(D->getSelfDecl(), Record);
+ Writer.AddDeclRef(D->getCmdDecl(), Record);
+ }
+ Record.push_back(D->isInstanceMethod());
+ Record.push_back(D->isVariadic());
+ Record.push_back(D->isSynthesized());
+ // FIXME: stable encoding for @required/@optional
+ Record.push_back(D->getImplementationControl());
+ // FIXME: stable encoding for in/out/inout/bycopy/byref/oneway
+ Record.push_back(D->getObjCDeclQualifier());
+ Record.push_back(D->getNumSelectorArgs());
+ Writer.AddTypeRef(D->getResultType(), Record);
+ Writer.AddTypeSourceInfo(D->getResultTypeSourceInfo(), Record);
+ Writer.AddSourceLocation(D->getLocEnd(), Record);
+ Record.push_back(D->param_size());
+ for (ObjCMethodDecl::param_iterator P = D->param_begin(),
+ PEnd = D->param_end(); P != PEnd; ++P)
+ Writer.AddDeclRef(*P, Record);
+ Code = pch::DECL_OBJC_METHOD;
+}
+
+void PCHDeclWriter::VisitObjCContainerDecl(ObjCContainerDecl *D) {
+ VisitNamedDecl(D);
+ Writer.AddSourceRange(D->getAtEndRange(), Record);
+ // Abstract class (no need to define a stable pch::DECL code).
+}
+
+void PCHDeclWriter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
+ VisitObjCContainerDecl(D);
+ Writer.AddTypeRef(QualType(D->getTypeForDecl(), 0), Record);
+ Writer.AddDeclRef(D->getSuperClass(), Record);
+ Record.push_back(D->protocol_size());
+ for (ObjCInterfaceDecl::protocol_iterator P = D->protocol_begin(),
+ PEnd = D->protocol_end();
+ P != PEnd; ++P)
+ Writer.AddDeclRef(*P, Record);
+ for (ObjCInterfaceDecl::protocol_loc_iterator PL = D->protocol_loc_begin(),
+ PLEnd = D->protocol_loc_end();
+ PL != PLEnd; ++PL)
+ Writer.AddSourceLocation(*PL, Record);
+ Record.push_back(D->ivar_size());
+ for (ObjCInterfaceDecl::ivar_iterator I = D->ivar_begin(),
+ IEnd = D->ivar_end(); I != IEnd; ++I)
+ Writer.AddDeclRef(*I, Record);
+ Writer.AddDeclRef(D->getCategoryList(), Record);
+ Record.push_back(D->isForwardDecl());
+ Record.push_back(D->isImplicitInterfaceDecl());
+ Writer.AddSourceLocation(D->getClassLoc(), Record);
+ Writer.AddSourceLocation(D->getSuperClassLoc(), Record);
+ Writer.AddSourceLocation(D->getLocEnd(), Record);
+ Code = pch::DECL_OBJC_INTERFACE;
+}
+
+void PCHDeclWriter::VisitObjCIvarDecl(ObjCIvarDecl *D) {
+ VisitFieldDecl(D);
+ // FIXME: stable encoding for @public/@private/@protected/@package
+ Record.push_back(D->getAccessControl());
+ Code = pch::DECL_OBJC_IVAR;
+}
+
+void PCHDeclWriter::VisitObjCProtocolDecl(ObjCProtocolDecl *D) {
+ VisitObjCContainerDecl(D);
+ Record.push_back(D->isForwardDecl());
+ Writer.AddSourceLocation(D->getLocEnd(), Record);
+ Record.push_back(D->protocol_size());
+ for (ObjCProtocolDecl::protocol_iterator
+ I = D->protocol_begin(), IEnd = D->protocol_end(); I != IEnd; ++I)
+ Writer.AddDeclRef(*I, Record);
+ for (ObjCProtocolDecl::protocol_loc_iterator PL = D->protocol_loc_begin(),
+ PLEnd = D->protocol_loc_end();
+ PL != PLEnd; ++PL)
+ Writer.AddSourceLocation(*PL, Record);
+ Code = pch::DECL_OBJC_PROTOCOL;
+}
+
+void PCHDeclWriter::VisitObjCAtDefsFieldDecl(ObjCAtDefsFieldDecl *D) {
+ VisitFieldDecl(D);
+ Code = pch::DECL_OBJC_AT_DEFS_FIELD;
+}
+
+void PCHDeclWriter::VisitObjCClassDecl(ObjCClassDecl *D) {
+ VisitDecl(D);
+ Record.push_back(D->size());
+ for (ObjCClassDecl::iterator I = D->begin(), IEnd = D->end(); I != IEnd; ++I)
+ Writer.AddDeclRef(I->getInterface(), Record);
+ for (ObjCClassDecl::iterator I = D->begin(), IEnd = D->end(); I != IEnd; ++I)
+ Writer.AddSourceLocation(I->getLocation(), Record);
+ Code = pch::DECL_OBJC_CLASS;
+}
+
+void PCHDeclWriter::VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D) {
+ VisitDecl(D);
+ Record.push_back(D->protocol_size());
+ for (ObjCForwardProtocolDecl::protocol_iterator
+ I = D->protocol_begin(), IEnd = D->protocol_end(); I != IEnd; ++I)
+ Writer.AddDeclRef(*I, Record);
+ for (ObjCForwardProtocolDecl::protocol_loc_iterator
+ PL = D->protocol_loc_begin(), PLEnd = D->protocol_loc_end();
+ PL != PLEnd; ++PL)
+ Writer.AddSourceLocation(*PL, Record);
+ Code = pch::DECL_OBJC_FORWARD_PROTOCOL;
+}
+
+void PCHDeclWriter::VisitObjCCategoryDecl(ObjCCategoryDecl *D) {
+ VisitObjCContainerDecl(D);
+ Writer.AddDeclRef(D->getClassInterface(), Record);
+ Record.push_back(D->protocol_size());
+ for (ObjCCategoryDecl::protocol_iterator
+ I = D->protocol_begin(), IEnd = D->protocol_end(); I != IEnd; ++I)
+ Writer.AddDeclRef(*I, Record);
+ for (ObjCCategoryDecl::protocol_loc_iterator
+ PL = D->protocol_loc_begin(), PLEnd = D->protocol_loc_end();
+ PL != PLEnd; ++PL)
+ Writer.AddSourceLocation(*PL, Record);
+ Writer.AddDeclRef(D->getNextClassCategory(), Record);
+ Writer.AddSourceLocation(D->getAtLoc(), Record);
+ Writer.AddSourceLocation(D->getCategoryNameLoc(), Record);
+ Code = pch::DECL_OBJC_CATEGORY;
+}
+
+void PCHDeclWriter::VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *D) {
+ VisitNamedDecl(D);
+ Writer.AddDeclRef(D->getClassInterface(), Record);
+ Code = pch::DECL_OBJC_COMPATIBLE_ALIAS;
+}
+
+void PCHDeclWriter::VisitObjCPropertyDecl(ObjCPropertyDecl *D) {
+ VisitNamedDecl(D);
+ Writer.AddSourceLocation(D->getAtLoc(), Record);
+ Writer.AddTypeSourceInfo(D->getTypeSourceInfo(), Record);
+ // FIXME: stable encoding
+ Record.push_back((unsigned)D->getPropertyAttributes());
+ Record.push_back((unsigned)D->getPropertyAttributesAsWritten());
+ // FIXME: stable encoding
+ Record.push_back((unsigned)D->getPropertyImplementation());
+ Writer.AddDeclarationName(D->getGetterName(), Record);
+ Writer.AddDeclarationName(D->getSetterName(), Record);
+ Writer.AddDeclRef(D->getGetterMethodDecl(), Record);
+ Writer.AddDeclRef(D->getSetterMethodDecl(), Record);
+ Writer.AddDeclRef(D->getPropertyIvarDecl(), Record);
+ Code = pch::DECL_OBJC_PROPERTY;
+}
+
+void PCHDeclWriter::VisitObjCImplDecl(ObjCImplDecl *D) {
+ VisitObjCContainerDecl(D);
+ Writer.AddDeclRef(D->getClassInterface(), Record);
+ // Abstract class (no need to define a stable pch::DECL code).
+}
+
+void PCHDeclWriter::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) {
+ VisitObjCImplDecl(D);
+ Writer.AddIdentifierRef(D->getIdentifier(), Record);
+ Code = pch::DECL_OBJC_CATEGORY_IMPL;
+}
+
+void PCHDeclWriter::VisitObjCImplementationDecl(ObjCImplementationDecl *D) {
+ VisitObjCImplDecl(D);
+ Writer.AddDeclRef(D->getSuperClass(), Record);
+ // FIXME add writing of IvarInitializers and NumIvarInitializers.
+ Code = pch::DECL_OBJC_IMPLEMENTATION;
+}
+
+void PCHDeclWriter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) {
+ VisitDecl(D);
+ Writer.AddSourceLocation(D->getLocStart(), Record);
+ Writer.AddDeclRef(D->getPropertyDecl(), Record);
+ Writer.AddDeclRef(D->getPropertyIvarDecl(), Record);
+ // FIXME. write GetterCXXConstructor and SetterCXXAssignment.
+ Code = pch::DECL_OBJC_PROPERTY_IMPL;
+}
+
+void PCHDeclWriter::VisitFieldDecl(FieldDecl *D) {
+ VisitDeclaratorDecl(D);
+ Record.push_back(D->isMutable());
+ Record.push_back(D->getBitWidth()? 1 : 0);
+ if (D->getBitWidth())
+ Writer.AddStmt(D->getBitWidth());
+ if (!D->getDeclName())
+ Writer.AddDeclRef(Context.getInstantiatedFromUnnamedFieldDecl(D), Record);
+ Code = pch::DECL_FIELD;
+}
+
+void PCHDeclWriter::VisitVarDecl(VarDecl *D) {
+ VisitDeclaratorDecl(D);
+ Record.push_back(D->getStorageClass()); // FIXME: stable encoding
+ Record.push_back(D->getStorageClassAsWritten());
+ Record.push_back(D->isThreadSpecified());
+ Record.push_back(D->hasCXXDirectInitializer());
+ Record.push_back(D->isDeclaredInCondition());
+ Record.push_back(D->isExceptionVariable());
+ Record.push_back(D->isNRVOVariable());
+ Writer.AddDeclRef(D->getPreviousDeclaration(), Record);
+ Record.push_back(D->getInit() ? 1 : 0);
+ if (D->getInit())
+ Writer.AddStmt(D->getInit());
+
+ MemberSpecializationInfo *SpecInfo
+ = D->isStaticDataMember() ? D->getMemberSpecializationInfo() : 0;
+ Record.push_back(SpecInfo != 0);
+ if (SpecInfo) {
+ Writer.AddDeclRef(SpecInfo->getInstantiatedFrom(), Record);
+ Record.push_back(SpecInfo->getTemplateSpecializationKind());
+ Writer.AddSourceLocation(SpecInfo->getPointOfInstantiation(), Record);
+ }
+
+ Code = pch::DECL_VAR;
+}
+
+void PCHDeclWriter::VisitImplicitParamDecl(ImplicitParamDecl *D) {
+ VisitVarDecl(D);
+ Code = pch::DECL_IMPLICIT_PARAM;
+}
+
+void PCHDeclWriter::VisitParmVarDecl(ParmVarDecl *D) {
+ VisitVarDecl(D);
+ Record.push_back(D->getObjCDeclQualifier()); // FIXME: stable encoding
+ Record.push_back(D->hasInheritedDefaultArg());
+ Record.push_back(D->hasUninstantiatedDefaultArg());
+ if (D->hasUninstantiatedDefaultArg())
+ Writer.AddStmt(D->getUninstantiatedDefaultArg());
+ Code = pch::DECL_PARM_VAR;
+
+ // If the assumptions about the DECL_PARM_VAR abbrev are true, use it. Here
+ // we dynamically check for the properties that we optimize for, but don't
+ // know are true of all PARM_VAR_DECLs.
+ if (!D->getTypeSourceInfo() &&
+ !D->hasAttrs() &&
+ !D->isImplicit() &&
+ !D->isUsed(false) &&
+ D->getAccess() == AS_none &&
+ D->getPCHLevel() == 0 &&
+ D->getStorageClass() == 0 &&
+ !D->hasCXXDirectInitializer() && // Can params have this ever?
+ D->getObjCDeclQualifier() == 0 &&
+ !D->hasInheritedDefaultArg() &&
+ D->getInit() == 0 &&
+ !D->hasUninstantiatedDefaultArg()) // No default expr.
+ AbbrevToUse = Writer.getParmVarDeclAbbrev();
+
+ // Check things we know are true of *every* PARM_VAR_DECL, which is more than
+ // just us assuming it.
+ assert(!D->isInvalidDecl() && "Shouldn't emit invalid decls");
+ assert(!D->isThreadSpecified() && "PARM_VAR_DECL can't be __thread");
+ assert(D->getAccess() == AS_none && "PARM_VAR_DECL can't be public/private");
+ assert(!D->isDeclaredInCondition() && "PARM_VAR_DECL can't be in condition");
+ assert(!D->isExceptionVariable() && "PARM_VAR_DECL can't be exception var");
+ assert(D->getPreviousDeclaration() == 0 && "PARM_VAR_DECL can't be redecl");
+ assert(!D->isStaticDataMember() &&
+ "PARM_VAR_DECL can't be static data member");
+}
+
+void PCHDeclWriter::VisitFileScopeAsmDecl(FileScopeAsmDecl *D) {
+ VisitDecl(D);
+ Writer.AddStmt(D->getAsmString());
+ Code = pch::DECL_FILE_SCOPE_ASM;
+}
+
+void PCHDeclWriter::VisitBlockDecl(BlockDecl *D) {
+ VisitDecl(D);
+ Writer.AddStmt(D->getBody());
+ Writer.AddTypeSourceInfo(D->getSignatureAsWritten(), Record);
+ Record.push_back(D->param_size());
+ for (FunctionDecl::param_iterator P = D->param_begin(), PEnd = D->param_end();
+ P != PEnd; ++P)
+ Writer.AddDeclRef(*P, Record);
+ Code = pch::DECL_BLOCK;
+}
+
+void PCHDeclWriter::VisitLinkageSpecDecl(LinkageSpecDecl *D) {
+ VisitDecl(D);
+ // FIXME: It might be nice to serialize the brace locations for this
+ // declaration, which don't seem to be readily available in the AST.
+ Record.push_back(D->getLanguage());
+ Record.push_back(D->hasBraces());
+ Code = pch::DECL_LINKAGE_SPEC;
+}
+
+void PCHDeclWriter::VisitNamespaceDecl(NamespaceDecl *D) {
+ VisitNamedDecl(D);
+ Writer.AddSourceLocation(D->getLBracLoc(), Record);
+ Writer.AddSourceLocation(D->getRBracLoc(), Record);
+ Writer.AddDeclRef(D->getNextNamespace(), Record);
+
+ // Only write one reference--original or anonymous
+ Record.push_back(D->isOriginalNamespace());
+ if (D->isOriginalNamespace())
+ Writer.AddDeclRef(D->getAnonymousNamespace(), Record);
+ else
+ Writer.AddDeclRef(D->getOriginalNamespace(), Record);
+ Code = pch::DECL_NAMESPACE;
+}
+
+void PCHDeclWriter::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) {
+ VisitNamedDecl(D);
+ Writer.AddSourceLocation(D->getAliasLoc(), Record);
+ Writer.AddSourceRange(D->getQualifierRange(), Record);
+ Writer.AddNestedNameSpecifier(D->getQualifier(), Record);
+ Writer.AddSourceLocation(D->getTargetNameLoc(), Record);
+ Writer.AddDeclRef(D->getNamespace(), Record);
+ Code = pch::DECL_NAMESPACE_ALIAS;
+}
+
+void PCHDeclWriter::VisitUsingDecl(UsingDecl *D) {
+ VisitNamedDecl(D);
+ Writer.AddSourceRange(D->getNestedNameRange(), Record);
+ Writer.AddSourceLocation(D->getUsingLocation(), Record);
+ Writer.AddNestedNameSpecifier(D->getTargetNestedNameDecl(), Record);
+ Record.push_back(D->getNumShadowDecls());
+ for (UsingDecl::shadow_iterator P = D->shadow_begin(),
+ PEnd = D->shadow_end(); P != PEnd; ++P)
+ Writer.AddDeclRef(*P, Record);
+ Record.push_back(D->isTypeName());
+ Writer.AddDeclRef(Context.getInstantiatedFromUsingDecl(D), Record);
+ Code = pch::DECL_USING;
+}
+
+void PCHDeclWriter::VisitUsingShadowDecl(UsingShadowDecl *D) {
+ VisitNamedDecl(D);
+ Writer.AddDeclRef(D->getTargetDecl(), Record);
+ Writer.AddDeclRef(D->getUsingDecl(), Record);
+ Writer.AddDeclRef(Context.getInstantiatedFromUsingShadowDecl(D), Record);
+ Code = pch::DECL_USING_SHADOW;
+}
+
+void PCHDeclWriter::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) {
+ VisitNamedDecl(D);
+ Writer.AddSourceLocation(D->getNamespaceKeyLocation(), Record);
+ Writer.AddSourceRange(D->getQualifierRange(), Record);
+ Writer.AddNestedNameSpecifier(D->getQualifier(), Record);
+ Writer.AddSourceLocation(D->getIdentLocation(), Record);
+ Writer.AddDeclRef(D->getNominatedNamespace(), Record);
+ Writer.AddDeclRef(dyn_cast<Decl>(D->getCommonAncestor()), Record);
+ Code = pch::DECL_USING_DIRECTIVE;
+}
+
+void PCHDeclWriter::VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) {
+ VisitValueDecl(D);
+ Writer.AddSourceRange(D->getTargetNestedNameRange(), Record);
+ Writer.AddSourceLocation(D->getUsingLoc(), Record);
+ Writer.AddNestedNameSpecifier(D->getTargetNestedNameSpecifier(), Record);
+ Code = pch::DECL_UNRESOLVED_USING_VALUE;
+}
+
+void PCHDeclWriter::VisitUnresolvedUsingTypenameDecl(
+ UnresolvedUsingTypenameDecl *D) {
+ VisitTypeDecl(D);
+ Writer.AddSourceRange(D->getTargetNestedNameRange(), Record);
+ Writer.AddSourceLocation(D->getUsingLoc(), Record);
+ Writer.AddSourceLocation(D->getTypenameLoc(), Record);
+ Writer.AddNestedNameSpecifier(D->getTargetNestedNameSpecifier(), Record);
+ Code = pch::DECL_UNRESOLVED_USING_TYPENAME;
+}
+
+void PCHDeclWriter::VisitCXXRecordDecl(CXXRecordDecl *D) {
+ // See comments at PCHDeclReader::VisitCXXRecordDecl about why this happens
+ // before VisitRecordDecl.
+ enum { Data_NoDefData, Data_Owner, Data_NotOwner };
+ bool OwnsDefinitionData = false;
+ if (D->DefinitionData) {
+ assert(D->DefinitionData->Definition &&
+ "DefinitionData don't point to a definition decl!");
+ OwnsDefinitionData = D->DefinitionData->Definition == D;
+ if (OwnsDefinitionData) {
+ Record.push_back(Data_Owner);
+ } else {
+ Record.push_back(Data_NotOwner);
+ Writer.AddDeclRef(D->DefinitionData->Definition, Record);
+ }
+ } else
+ Record.push_back(Data_NoDefData);
+
+ VisitRecordDecl(D);
+
+ if (OwnsDefinitionData) {
+ assert(D->DefinitionData);
+ struct CXXRecordDecl::DefinitionData &Data = *D->DefinitionData;
+
+ Record.push_back(Data.UserDeclaredConstructor);
+ Record.push_back(Data.UserDeclaredCopyConstructor);
+ Record.push_back(Data.UserDeclaredCopyAssignment);
+ Record.push_back(Data.UserDeclaredDestructor);
+ Record.push_back(Data.Aggregate);
+ Record.push_back(Data.PlainOldData);
+ Record.push_back(Data.Empty);
+ Record.push_back(Data.Polymorphic);
+ Record.push_back(Data.Abstract);
+ Record.push_back(Data.HasTrivialConstructor);
+ Record.push_back(Data.HasTrivialCopyConstructor);
+ Record.push_back(Data.HasTrivialCopyAssignment);
+ Record.push_back(Data.HasTrivialDestructor);
+ Record.push_back(Data.ComputedVisibleConversions);
+ Record.push_back(Data.DeclaredDefaultConstructor);
+ Record.push_back(Data.DeclaredCopyConstructor);
+ Record.push_back(Data.DeclaredCopyAssignment);
+ Record.push_back(Data.DeclaredDestructor);
+
+ Record.push_back(D->getNumBases());
+ for (CXXRecordDecl::base_class_iterator I = D->bases_begin(),
+ E = D->bases_end(); I != E; ++I)
+ Writer.AddCXXBaseSpecifier(*I, Record);
+
+ // FIXME: Make VBases lazily computed when needed to avoid storing them.
+ Record.push_back(D->getNumVBases());
+ for (CXXRecordDecl::base_class_iterator I = D->vbases_begin(),
+ E = D->vbases_end(); I != E; ++I)
+ Writer.AddCXXBaseSpecifier(*I, Record);
+
+ Writer.AddUnresolvedSet(Data.Conversions, Record);
+ Writer.AddUnresolvedSet(Data.VisibleConversions, Record);
+ // Data.Definition is written at the top.
+ Writer.AddDeclRef(Data.FirstFriend, Record);
+ }
+
+ enum {
+ CXXRecNotTemplate = 0, CXXRecTemplate, CXXRecMemberSpecialization
+ };
+ if (ClassTemplateDecl *TemplD = D->getDescribedClassTemplate()) {
+ Record.push_back(CXXRecTemplate);
+ Writer.AddDeclRef(TemplD, Record);
+ } else if (MemberSpecializationInfo *MSInfo
+ = D->getMemberSpecializationInfo()) {
+ Record.push_back(CXXRecMemberSpecialization);
+ Writer.AddDeclRef(MSInfo->getInstantiatedFrom(), Record);
+ Record.push_back(MSInfo->getTemplateSpecializationKind());
+ Writer.AddSourceLocation(MSInfo->getPointOfInstantiation(), Record);
+ } else {
+ Record.push_back(CXXRecNotTemplate);
+ }
+
+ Code = pch::DECL_CXX_RECORD;
+}
+
+void PCHDeclWriter::VisitCXXMethodDecl(CXXMethodDecl *D) {
+ VisitFunctionDecl(D);
+ Record.push_back(D->size_overridden_methods());
+ for (CXXMethodDecl::method_iterator
+ I = D->begin_overridden_methods(), E = D->end_overridden_methods();
+ I != E; ++I)
+ Writer.AddDeclRef(*I, Record);
+ Code = pch::DECL_CXX_METHOD;
+}
+
+void PCHDeclWriter::VisitCXXConstructorDecl(CXXConstructorDecl *D) {
+ VisitCXXMethodDecl(D);
+
+ Record.push_back(D->IsExplicitSpecified);
+ Record.push_back(D->ImplicitlyDefined);
+
+ Record.push_back(D->NumBaseOrMemberInitializers);
+ for (unsigned i=0; i != D->NumBaseOrMemberInitializers; ++i) {
+ CXXBaseOrMemberInitializer *Init = D->BaseOrMemberInitializers[i];
+
+ Record.push_back(Init->isBaseInitializer());
+ if (Init->isBaseInitializer()) {
+ Writer.AddTypeSourceInfo(Init->getBaseClassInfo(), Record);
+ Record.push_back(Init->isBaseVirtual());
+ } else {
+ Writer.AddDeclRef(Init->getMember(), Record);
+ }
+ Writer.AddSourceLocation(Init->getMemberLocation(), Record);
+ Writer.AddStmt(Init->getInit());
+ Writer.AddDeclRef(Init->getAnonUnionMember(), Record);
+ Writer.AddSourceLocation(Init->getLParenLoc(), Record);
+ Writer.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)
+ Writer.AddDeclRef(Init->getArrayIndex(i), Record);
+ }
+ }
+
+ Code = pch::DECL_CXX_CONSTRUCTOR;
+}
+
+void PCHDeclWriter::VisitCXXDestructorDecl(CXXDestructorDecl *D) {
+ VisitCXXMethodDecl(D);
+
+ Record.push_back(D->ImplicitlyDefined);
+ Writer.AddDeclRef(D->OperatorDelete, Record);
+
+ Code = pch::DECL_CXX_DESTRUCTOR;
+}
+
+void PCHDeclWriter::VisitCXXConversionDecl(CXXConversionDecl *D) {
+ VisitCXXMethodDecl(D);
+ Record.push_back(D->IsExplicitSpecified);
+ Code = pch::DECL_CXX_CONVERSION;
+}
+
+void PCHDeclWriter::VisitAccessSpecDecl(AccessSpecDecl *D) {
+ VisitDecl(D);
+ Writer.AddSourceLocation(D->getColonLoc(), Record);
+ Code = pch::DECL_ACCESS_SPEC;
+}
+
+void PCHDeclWriter::VisitFriendDecl(FriendDecl *D) {
+ VisitDecl(D);
+ Record.push_back(D->Friend.is<TypeSourceInfo*>());
+ if (D->Friend.is<TypeSourceInfo*>())
+ Writer.AddTypeSourceInfo(D->Friend.get<TypeSourceInfo*>(), Record);
+ else
+ Writer.AddDeclRef(D->Friend.get<NamedDecl*>(), Record);
+ Writer.AddDeclRef(D->NextFriend, Record);
+ Writer.AddSourceLocation(D->FriendLoc, Record);
+ Code = pch::DECL_FRIEND;
+}
+
+void PCHDeclWriter::VisitFriendTemplateDecl(FriendTemplateDecl *D) {
+ assert(false && "cannot write FriendTemplateDecl");
+}
+
+void PCHDeclWriter::VisitTemplateDecl(TemplateDecl *D) {
+ VisitNamedDecl(D);
+
+ Writer.AddDeclRef(D->getTemplatedDecl(), Record);
+ Writer.AddTemplateParameterList(D->getTemplateParameters(), Record);
+}
+
+static bool IsKeptInFoldingSet(ClassTemplateSpecializationDecl *D) {
+ return D->getTypeForDecl()->getAsCXXRecordDecl() == D;
+}
+
+void PCHDeclWriter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
+ VisitTemplateDecl(D);
+
+ Record.push_back(D->getIdentifierNamespace());
+ Writer.AddDeclRef(D->getPreviousDeclaration(), Record);
+ if (D->getPreviousDeclaration() == 0) {
+ // This ClassTemplateDecl owns the CommonPtr; write it.
+ assert(D->isCanonicalDecl());
+
+ typedef llvm::FoldingSet<ClassTemplateSpecializationDecl> CTSDSetTy;
+ CTSDSetTy &CTSDSet = D->getSpecializations();
+ Record.push_back(CTSDSet.size());
+ for (CTSDSetTy::iterator I=CTSDSet.begin(), E = CTSDSet.end(); I!=E; ++I) {
+ assert(IsKeptInFoldingSet(&*I));
+ Writer.AddDeclRef(&*I, Record);
+ }
+
+ typedef llvm::FoldingSet<ClassTemplatePartialSpecializationDecl> CTPSDSetTy;
+ CTPSDSetTy &CTPSDSet = D->getPartialSpecializations();
+ Record.push_back(CTPSDSet.size());
+ for (CTPSDSetTy::iterator I=CTPSDSet.begin(), E=CTPSDSet.end(); I!=E; ++I) {
+ assert(IsKeptInFoldingSet(&*I));
+ Writer.AddDeclRef(&*I, Record);
+ }
+
+ // InjectedClassNameType is computed, no need to write it.
+
+ Writer.AddDeclRef(D->getInstantiatedFromMemberTemplate(), Record);
+ if (D->getInstantiatedFromMemberTemplate())
+ Record.push_back(D->isMemberSpecialization());
+ }
+ Code = pch::DECL_CLASS_TEMPLATE;
+}
+
+void PCHDeclWriter::VisitClassTemplateSpecializationDecl(
+ ClassTemplateSpecializationDecl *D) {
+ VisitCXXRecordDecl(D);
+
+ llvm::PointerUnion<ClassTemplateDecl *,
+ ClassTemplatePartialSpecializationDecl *> InstFrom
+ = D->getSpecializedTemplateOrPartial();
+ if (InstFrom.is<ClassTemplateDecl *>()) {
+ Writer.AddDeclRef(InstFrom.get<ClassTemplateDecl *>(), Record);
+ } else {
+ Writer.AddDeclRef(InstFrom.get<ClassTemplatePartialSpecializationDecl *>(),
+ Record);
+ Writer.AddTemplateArgumentList(&D->getTemplateInstantiationArgs(), Record);
+ }
+
+ // Explicit info.
+ Writer.AddTypeSourceInfo(D->getTypeAsWritten(), Record);
+ if (D->getTypeAsWritten()) {
+ Writer.AddSourceLocation(D->getExternLoc(), Record);
+ Writer.AddSourceLocation(D->getTemplateKeywordLoc(), Record);
+ }
+
+ Writer.AddTemplateArgumentList(&D->getTemplateArgs(), Record);
+ Writer.AddSourceLocation(D->getPointOfInstantiation(), Record);
+ Record.push_back(D->getSpecializationKind());
+
+ bool IsInInFoldingSet = IsKeptInFoldingSet(D);
+ Record.push_back(IsInInFoldingSet);
+ if (IsInInFoldingSet) {
+ // When reading, we'll add it to the folding set of this one.
+ Writer.AddDeclRef(D->getSpecializedTemplate()->getCanonicalDecl(), Record);
+ }
+
+ Code = pch::DECL_CLASS_TEMPLATE_SPECIALIZATION;
+}
+
+void PCHDeclWriter::VisitClassTemplatePartialSpecializationDecl(
+ ClassTemplatePartialSpecializationDecl *D) {
+ VisitClassTemplateSpecializationDecl(D);
+
+ Writer.AddTemplateParameterList(D->getTemplateParameters(), Record);
+
+ Record.push_back(D->getNumTemplateArgsAsWritten());
+ for (int i = 0, e = D->getNumTemplateArgsAsWritten(); i != e; ++i)
+ Writer.AddTemplateArgumentLoc(D->getTemplateArgsAsWritten()[i], Record);
+
+ Record.push_back(D->getSequenceNumber());
+
+ // These are read/set from/to the first declaration.
+ if (D->getPreviousDeclaration() == 0) {
+ Writer.AddDeclRef(D->getInstantiatedFromMember(), Record);
+ Record.push_back(D->isMemberSpecialization());
+ }
+
+ Code = pch::DECL_CLASS_TEMPLATE_PARTIAL_SPECIALIZATION;
+}
+
+void PCHDeclWriter::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
+ VisitTemplateDecl(D);
+
+ Record.push_back(D->getIdentifierNamespace());
+ Writer.AddDeclRef(D->getPreviousDeclaration(), Record);
+ if (D->getPreviousDeclaration() == 0) {
+ // This FunctionTemplateDecl owns the CommonPtr; write it.
+
+ // Write the function specialization declarations.
+ Record.push_back(D->getSpecializations().size());
+ for (llvm::FoldingSet<FunctionTemplateSpecializationInfo>::iterator
+ I = D->getSpecializations().begin(),
+ E = D->getSpecializations().end() ; I != E; ++I)
+ Writer.AddDeclRef(I->Function, Record);
+
+ Writer.AddDeclRef(D->getInstantiatedFromMemberTemplate(), Record);
+ if (D->getInstantiatedFromMemberTemplate())
+ Record.push_back(D->isMemberSpecialization());
+ }
+ Code = pch::DECL_FUNCTION_TEMPLATE;
+}
+
+void PCHDeclWriter::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) {
+ VisitTypeDecl(D);
+
+ Record.push_back(D->wasDeclaredWithTypename());
+ Record.push_back(D->isParameterPack());
+ Record.push_back(D->defaultArgumentWasInherited());
+ Writer.AddTypeSourceInfo(D->getDefaultArgumentInfo(), Record);
+
+ Code = pch::DECL_TEMPLATE_TYPE_PARM;
+}
+
+void PCHDeclWriter::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {
+ VisitVarDecl(D);
+ // TemplateParmPosition.
+ Record.push_back(D->getDepth());
+ Record.push_back(D->getPosition());
+ // Rest of NonTypeTemplateParmDecl.
+ Record.push_back(D->getDefaultArgument() != 0);
+ if (D->getDefaultArgument()) {
+ Writer.AddStmt(D->getDefaultArgument());
+ Record.push_back(D->defaultArgumentWasInherited());
+ }
+ Code = pch::DECL_NON_TYPE_TEMPLATE_PARM;
+}
+
+void PCHDeclWriter::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) {
+ VisitTemplateDecl(D);
+ // TemplateParmPosition.
+ Record.push_back(D->getDepth());
+ Record.push_back(D->getPosition());
+ // Rest of TemplateTemplateParmDecl.
+ Writer.AddTemplateArgumentLoc(D->getDefaultArgument(), Record);
+ Record.push_back(D->defaultArgumentWasInherited());
+ Code = pch::DECL_TEMPLATE_TEMPLATE_PARM;
+}
+
+void PCHDeclWriter::VisitStaticAssertDecl(StaticAssertDecl *D) {
+ assert(false && "cannot write StaticAssertDecl");
+}
+
+/// \brief Emit the DeclContext part of a declaration context decl.
+///
+/// \param LexicalOffset the offset at which the DECL_CONTEXT_LEXICAL
+/// block for this declaration context is stored. May be 0 to indicate
+/// that there are no declarations stored within this context.
+///
+/// \param VisibleOffset the offset at which the DECL_CONTEXT_VISIBLE
+/// block for this declaration context is stored. May be 0 to indicate
+/// that there are no declarations visible from this context. Note
+/// that this value will not be emitted for non-primary declaration
+/// contexts.
+void PCHDeclWriter::VisitDeclContext(DeclContext *DC, uint64_t LexicalOffset,
+ uint64_t VisibleOffset) {
+ Record.push_back(LexicalOffset);
+ Record.push_back(VisibleOffset);
+}
+
+
+//===----------------------------------------------------------------------===//
+// PCHWriter Implementation
+//===----------------------------------------------------------------------===//
+
+void PCHWriter::WriteDeclsBlockAbbrevs() {
+ using namespace llvm;
+ // Abbreviation for DECL_PARM_VAR.
+ BitCodeAbbrev *Abv = new BitCodeAbbrev();
+ Abv->Add(BitCodeAbbrevOp(pch::DECL_PARM_VAR));
+
+ // Decl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Location
+ Abv->Add(BitCodeAbbrevOp(0)); // isInvalidDecl (!?)
+ Abv->Add(BitCodeAbbrevOp(0)); // HasAttrs
+ Abv->Add(BitCodeAbbrevOp(0)); // isImplicit
+ Abv->Add(BitCodeAbbrevOp(0)); // isUsed
+ Abv->Add(BitCodeAbbrevOp(AS_none)); // C++ AccessSpecifier
+ Abv->Add(BitCodeAbbrevOp(0)); // PCH level
+
+ // NamedDecl
+ Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name
+ // ValueDecl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type
+ // DeclaratorDecl
+ Abv->Add(BitCodeAbbrevOp(pch::PREDEF_TYPE_NULL_ID)); // InfoType
+ // VarDecl
+ Abv->Add(BitCodeAbbrevOp(0)); // StorageClass
+ Abv->Add(BitCodeAbbrevOp(0)); // StorageClassAsWritten
+ Abv->Add(BitCodeAbbrevOp(0)); // isThreadSpecified
+ Abv->Add(BitCodeAbbrevOp(0)); // hasCXXDirectInitializer
+ Abv->Add(BitCodeAbbrevOp(0)); // isDeclaredInCondition
+ Abv->Add(BitCodeAbbrevOp(0)); // isExceptionVariable
+ Abv->Add(BitCodeAbbrevOp(0)); // isNRVOVariable
+ Abv->Add(BitCodeAbbrevOp(0)); // PrevDecl
+ Abv->Add(BitCodeAbbrevOp(0)); // HasInit
+ Abv->Add(BitCodeAbbrevOp(0)); // HasMemberSpecializationInfo
+ // ParmVarDecl
+ Abv->Add(BitCodeAbbrevOp(0)); // ObjCDeclQualifier
+ Abv->Add(BitCodeAbbrevOp(0)); // HasInheritedDefaultArg
+ Abv->Add(BitCodeAbbrevOp(0)); // HasUninstantiatedDefaultArg
+
+ ParmVarDeclAbbrev = Stream.EmitAbbrev(Abv);
+}
+
+/// isRequiredDecl - Check if this is a "required" Decl, which must be seen by
+/// consumers of the AST.
+///
+/// Such decls will always be deserialized from the PCH file, so we would like
+/// this to be as restrictive as possible. Currently the predicate is driven by
+/// code generation requirements, if other clients have a different notion of
+/// what is "required" then we may have to consider an alternate scheme where
+/// clients can iterate over the top-level decls and get information on them,
+/// without necessary deserializing them. We could explicitly require such
+/// clients to use a separate API call to "realize" the decl. This should be
+/// relatively painless since they would presumably only do it for top-level
+/// decls.
+//
+// FIXME: This predicate is essentially IRgen's predicate to determine whether a
+// declaration can be deferred. Merge them somehow.
+static bool isRequiredDecl(const Decl *D, ASTContext &Context) {
+ // File scoped assembly must be seen.
+ if (isa<FileScopeAsmDecl>(D))
+ return true;
+
+ // Otherwise if this isn't a function or a file scoped variable it doesn't
+ // need to be seen.
+ if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
+ if (!VD->isFileVarDecl())
+ return false;
+ } else if (!isa<FunctionDecl>(D))
+ return false;
+
+ // Aliases and used decls must be seen.
+ if (D->hasAttr<AliasAttr>() || D->hasAttr<UsedAttr>())
+ return true;
+
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ // Forward declarations don't need to be seen.
+ if (!FD->isThisDeclarationADefinition())
+ return false;
+
+ // Constructors and destructors must be seen.
+ if (FD->hasAttr<ConstructorAttr>() || FD->hasAttr<DestructorAttr>())
+ return true;
+
+ // Otherwise, this is required unless it is static.
+ //
+ // FIXME: Inlines.
+ return FD->getStorageClass() != FunctionDecl::Static;
+ } else {
+ const VarDecl *VD = cast<VarDecl>(D);
+
+ // In C++, this doesn't need to be seen if it is marked "extern".
+ if (Context.getLangOptions().CPlusPlus && !VD->getInit() &&
+ (VD->getStorageClass() == VarDecl::Extern ||
+ VD->isExternC()))
+ return false;
+
+ // In C, this doesn't need to be seen unless it is a definition.
+ if (!Context.getLangOptions().CPlusPlus && !VD->getInit())
+ return false;
+
+ // Otherwise, this is required unless it is static.
+ return VD->getStorageClass() != VarDecl::Static;
+ }
+}
+
+void PCHWriter::WriteDecl(ASTContext &Context, Decl *D) {
+ RecordData Record;
+ PCHDeclWriter W(*this, Context, Record);
+
+ // If this declaration is also a DeclContext, write blocks for the
+ // declarations that lexically stored inside its context and those
+ // declarations that are visible from its context. These blocks
+ // are written before the declaration itself so that we can put
+ // their offsets into the record for the declaration.
+ uint64_t LexicalOffset = 0;
+ uint64_t VisibleOffset = 0;
+ DeclContext *DC = dyn_cast<DeclContext>(D);
+ if (DC) {
+ LexicalOffset = WriteDeclContextLexicalBlock(Context, DC);
+ VisibleOffset = WriteDeclContextVisibleBlock(Context, DC);
+ }
+
+ // Determine the ID for this declaration
+ pch::DeclID &ID = DeclIDs[D];
+ if (ID == 0)
+ ID = DeclIDs.size();
+
+ unsigned Index = ID - 1;
+
+ // Record the offset for this declaration
+ if (DeclOffsets.size() == Index)
+ DeclOffsets.push_back(Stream.GetCurrentBitNo());
+ else if (DeclOffsets.size() < Index) {
+ DeclOffsets.resize(Index+1);
+ DeclOffsets[Index] = Stream.GetCurrentBitNo();
+ }
+
+ // Build and emit a record for this declaration
+ Record.clear();
+ W.Code = (pch::DeclCode)0;
+ W.AbbrevToUse = 0;
+ W.Visit(D);
+ if (DC) W.VisitDeclContext(DC, LexicalOffset, VisibleOffset);
+
+ if (!W.Code)
+ llvm::report_fatal_error(llvm::StringRef("unexpected declaration kind '") +
+ D->getDeclKindName() + "'");
+ Stream.EmitRecord(W.Code, Record, W.AbbrevToUse);
+
+ // If the declaration had any attributes, write them now.
+ if (D->hasAttrs())
+ WriteAttributeRecord(D->getAttrs());
+
+ // Flush any expressions that were written as part of this declaration.
+ FlushStmts();
+
+ // Note "external" declarations so that we can add them to a record in the
+ // PCH file later.
+ //
+ // FIXME: This should be renamed, the predicate is much more complicated.
+ if (isRequiredDecl(D, Context))
+ ExternalDefinitions.push_back(Index + 1);
+}
diff --git a/contrib/llvm/tools/clang/lib/Frontend/PCHWriterStmt.cpp b/contrib/llvm/tools/clang/lib/Frontend/PCHWriterStmt.cpp
new file mode 100644
index 0000000..7537728
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Frontend/PCHWriterStmt.cpp
@@ -0,0 +1,1345 @@
+//===--- PCHWriterStmt.cpp - Statement and Expression Serialization -------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements serialization for Statements and Expressions.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/PCHWriter.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/StmtVisitor.h"
+#include "llvm/Bitcode/BitstreamWriter.h"
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// Statement/expression serialization
+//===----------------------------------------------------------------------===//
+
+namespace clang {
+ class PCHStmtWriter : public StmtVisitor<PCHStmtWriter, void> {
+ PCHWriter &Writer;
+ PCHWriter::RecordData &Record;
+
+ public:
+ pch::StmtCode Code;
+
+ PCHStmtWriter(PCHWriter &Writer, PCHWriter::RecordData &Record)
+ : Writer(Writer), Record(Record) { }
+
+ void
+ AddExplicitTemplateArgumentList(const ExplicitTemplateArgumentList &Args);
+
+ void VisitStmt(Stmt *S);
+ void VisitNullStmt(NullStmt *S);
+ void VisitCompoundStmt(CompoundStmt *S);
+ void VisitSwitchCase(SwitchCase *S);
+ void VisitCaseStmt(CaseStmt *S);
+ void VisitDefaultStmt(DefaultStmt *S);
+ void VisitLabelStmt(LabelStmt *S);
+ void VisitIfStmt(IfStmt *S);
+ void VisitSwitchStmt(SwitchStmt *S);
+ void VisitWhileStmt(WhileStmt *S);
+ void VisitDoStmt(DoStmt *S);
+ void VisitForStmt(ForStmt *S);
+ void VisitGotoStmt(GotoStmt *S);
+ void VisitIndirectGotoStmt(IndirectGotoStmt *S);
+ void VisitContinueStmt(ContinueStmt *S);
+ void VisitBreakStmt(BreakStmt *S);
+ void VisitReturnStmt(ReturnStmt *S);
+ void VisitDeclStmt(DeclStmt *S);
+ void VisitAsmStmt(AsmStmt *S);
+ void VisitExpr(Expr *E);
+ void VisitPredefinedExpr(PredefinedExpr *E);
+ void VisitDeclRefExpr(DeclRefExpr *E);
+ void VisitIntegerLiteral(IntegerLiteral *E);
+ void VisitFloatingLiteral(FloatingLiteral *E);
+ void VisitImaginaryLiteral(ImaginaryLiteral *E);
+ void VisitStringLiteral(StringLiteral *E);
+ void VisitCharacterLiteral(CharacterLiteral *E);
+ void VisitParenExpr(ParenExpr *E);
+ void VisitParenListExpr(ParenListExpr *E);
+ void VisitUnaryOperator(UnaryOperator *E);
+ void VisitOffsetOfExpr(OffsetOfExpr *E);
+ void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E);
+ void VisitArraySubscriptExpr(ArraySubscriptExpr *E);
+ void VisitCallExpr(CallExpr *E);
+ void VisitMemberExpr(MemberExpr *E);
+ void VisitCastExpr(CastExpr *E);
+ void VisitBinaryOperator(BinaryOperator *E);
+ void VisitCompoundAssignOperator(CompoundAssignOperator *E);
+ void VisitConditionalOperator(ConditionalOperator *E);
+ void VisitImplicitCastExpr(ImplicitCastExpr *E);
+ void VisitExplicitCastExpr(ExplicitCastExpr *E);
+ void VisitCStyleCastExpr(CStyleCastExpr *E);
+ void VisitCompoundLiteralExpr(CompoundLiteralExpr *E);
+ void VisitExtVectorElementExpr(ExtVectorElementExpr *E);
+ void VisitInitListExpr(InitListExpr *E);
+ void VisitDesignatedInitExpr(DesignatedInitExpr *E);
+ void VisitImplicitValueInitExpr(ImplicitValueInitExpr *E);
+ void VisitVAArgExpr(VAArgExpr *E);
+ void VisitAddrLabelExpr(AddrLabelExpr *E);
+ void VisitStmtExpr(StmtExpr *E);
+ void VisitTypesCompatibleExpr(TypesCompatibleExpr *E);
+ void VisitChooseExpr(ChooseExpr *E);
+ void VisitGNUNullExpr(GNUNullExpr *E);
+ void VisitShuffleVectorExpr(ShuffleVectorExpr *E);
+ void VisitBlockExpr(BlockExpr *E);
+ void VisitBlockDeclRefExpr(BlockDeclRefExpr *E);
+
+ // Objective-C Expressions
+ void VisitObjCStringLiteral(ObjCStringLiteral *E);
+ void VisitObjCEncodeExpr(ObjCEncodeExpr *E);
+ void VisitObjCSelectorExpr(ObjCSelectorExpr *E);
+ void VisitObjCProtocolExpr(ObjCProtocolExpr *E);
+ void VisitObjCIvarRefExpr(ObjCIvarRefExpr *E);
+ void VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E);
+ void VisitObjCImplicitSetterGetterRefExpr(
+ ObjCImplicitSetterGetterRefExpr *E);
+ void VisitObjCMessageExpr(ObjCMessageExpr *E);
+ void VisitObjCSuperExpr(ObjCSuperExpr *E);
+ void VisitObjCIsaExpr(ObjCIsaExpr *E);
+
+ // Objective-C Statements
+ void VisitObjCForCollectionStmt(ObjCForCollectionStmt *);
+ void VisitObjCAtCatchStmt(ObjCAtCatchStmt *);
+ void VisitObjCAtFinallyStmt(ObjCAtFinallyStmt *);
+ void VisitObjCAtTryStmt(ObjCAtTryStmt *);
+ void VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *);
+ void VisitObjCAtThrowStmt(ObjCAtThrowStmt *);
+
+ // C++ Statements
+ void VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E);
+ void VisitCXXMemberCallExpr(CXXMemberCallExpr *E);
+ void VisitCXXConstructExpr(CXXConstructExpr *E);
+ void VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *E);
+ void VisitCXXNamedCastExpr(CXXNamedCastExpr *E);
+ void VisitCXXStaticCastExpr(CXXStaticCastExpr *E);
+ void VisitCXXDynamicCastExpr(CXXDynamicCastExpr *E);
+ void VisitCXXReinterpretCastExpr(CXXReinterpretCastExpr *E);
+ void VisitCXXConstCastExpr(CXXConstCastExpr *E);
+ void VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E);
+ void VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E);
+ void VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *E);
+ void VisitCXXTypeidExpr(CXXTypeidExpr *E);
+ void VisitCXXThisExpr(CXXThisExpr *E);
+ void VisitCXXThrowExpr(CXXThrowExpr *E);
+ void VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E);
+ void VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E);
+ void VisitCXXBindReferenceExpr(CXXBindReferenceExpr *E);
+
+ void VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E);
+ void VisitCXXNewExpr(CXXNewExpr *E);
+ void VisitCXXDeleteExpr(CXXDeleteExpr *E);
+ void VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E);
+
+ void VisitCXXExprWithTemporaries(CXXExprWithTemporaries *E);
+ void VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E);
+ void VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E);
+ void VisitCXXUnresolvedConstructExpr(CXXUnresolvedConstructExpr *E);
+
+ void VisitOverloadExpr(OverloadExpr *E);
+ void VisitUnresolvedMemberExpr(UnresolvedMemberExpr *E);
+ void VisitUnresolvedLookupExpr(UnresolvedLookupExpr *E);
+
+ void VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *E);
+ };
+}
+
+void PCHStmtWriter::
+AddExplicitTemplateArgumentList(const ExplicitTemplateArgumentList &Args) {
+ Writer.AddSourceLocation(Args.LAngleLoc, Record);
+ Writer.AddSourceLocation(Args.RAngleLoc, Record);
+ for (unsigned i=0; i != Args.NumTemplateArgs; ++i)
+ Writer.AddTemplateArgumentLoc(Args.getTemplateArgs()[i], Record);
+}
+
+void PCHStmtWriter::VisitStmt(Stmt *S) {
+}
+
+void PCHStmtWriter::VisitNullStmt(NullStmt *S) {
+ VisitStmt(S);
+ Writer.AddSourceLocation(S->getSemiLoc(), Record);
+ Code = pch::STMT_NULL;
+}
+
+void PCHStmtWriter::VisitCompoundStmt(CompoundStmt *S) {
+ VisitStmt(S);
+ Record.push_back(S->size());
+ for (CompoundStmt::body_iterator CS = S->body_begin(), CSEnd = S->body_end();
+ CS != CSEnd; ++CS)
+ Writer.AddStmt(*CS);
+ Writer.AddSourceLocation(S->getLBracLoc(), Record);
+ Writer.AddSourceLocation(S->getRBracLoc(), Record);
+ Code = pch::STMT_COMPOUND;
+}
+
+void PCHStmtWriter::VisitSwitchCase(SwitchCase *S) {
+ VisitStmt(S);
+ Record.push_back(Writer.getSwitchCaseID(S));
+}
+
+void PCHStmtWriter::VisitCaseStmt(CaseStmt *S) {
+ VisitSwitchCase(S);
+ Writer.AddStmt(S->getLHS());
+ Writer.AddStmt(S->getRHS());
+ Writer.AddStmt(S->getSubStmt());
+ Writer.AddSourceLocation(S->getCaseLoc(), Record);
+ Writer.AddSourceLocation(S->getEllipsisLoc(), Record);
+ Writer.AddSourceLocation(S->getColonLoc(), Record);
+ Code = pch::STMT_CASE;
+}
+
+void PCHStmtWriter::VisitDefaultStmt(DefaultStmt *S) {
+ VisitSwitchCase(S);
+ Writer.AddStmt(S->getSubStmt());
+ Writer.AddSourceLocation(S->getDefaultLoc(), Record);
+ Writer.AddSourceLocation(S->getColonLoc(), Record);
+ Code = pch::STMT_DEFAULT;
+}
+
+void PCHStmtWriter::VisitLabelStmt(LabelStmt *S) {
+ VisitStmt(S);
+ Writer.AddIdentifierRef(S->getID(), Record);
+ Writer.AddStmt(S->getSubStmt());
+ Writer.AddSourceLocation(S->getIdentLoc(), Record);
+ Record.push_back(Writer.GetLabelID(S));
+ Code = pch::STMT_LABEL;
+}
+
+void PCHStmtWriter::VisitIfStmt(IfStmt *S) {
+ VisitStmt(S);
+ Writer.AddDeclRef(S->getConditionVariable(), Record);
+ Writer.AddStmt(S->getCond());
+ Writer.AddStmt(S->getThen());
+ Writer.AddStmt(S->getElse());
+ Writer.AddSourceLocation(S->getIfLoc(), Record);
+ Writer.AddSourceLocation(S->getElseLoc(), Record);
+ Code = pch::STMT_IF;
+}
+
+void PCHStmtWriter::VisitSwitchStmt(SwitchStmt *S) {
+ VisitStmt(S);
+ Writer.AddDeclRef(S->getConditionVariable(), Record);
+ Writer.AddStmt(S->getCond());
+ Writer.AddStmt(S->getBody());
+ Writer.AddSourceLocation(S->getSwitchLoc(), Record);
+ for (SwitchCase *SC = S->getSwitchCaseList(); SC;
+ SC = SC->getNextSwitchCase())
+ Record.push_back(Writer.RecordSwitchCaseID(SC));
+ Code = pch::STMT_SWITCH;
+}
+
+void PCHStmtWriter::VisitWhileStmt(WhileStmt *S) {
+ VisitStmt(S);
+ Writer.AddDeclRef(S->getConditionVariable(), Record);
+ Writer.AddStmt(S->getCond());
+ Writer.AddStmt(S->getBody());
+ Writer.AddSourceLocation(S->getWhileLoc(), Record);
+ Code = pch::STMT_WHILE;
+}
+
+void PCHStmtWriter::VisitDoStmt(DoStmt *S) {
+ VisitStmt(S);
+ Writer.AddStmt(S->getCond());
+ Writer.AddStmt(S->getBody());
+ Writer.AddSourceLocation(S->getDoLoc(), Record);
+ Writer.AddSourceLocation(S->getWhileLoc(), Record);
+ Writer.AddSourceLocation(S->getRParenLoc(), Record);
+ Code = pch::STMT_DO;
+}
+
+void PCHStmtWriter::VisitForStmt(ForStmt *S) {
+ VisitStmt(S);
+ Writer.AddStmt(S->getInit());
+ Writer.AddStmt(S->getCond());
+ Writer.AddDeclRef(S->getConditionVariable(), Record);
+ Writer.AddStmt(S->getInc());
+ Writer.AddStmt(S->getBody());
+ Writer.AddSourceLocation(S->getForLoc(), Record);
+ Writer.AddSourceLocation(S->getLParenLoc(), Record);
+ Writer.AddSourceLocation(S->getRParenLoc(), Record);
+ Code = pch::STMT_FOR;
+}
+
+void PCHStmtWriter::VisitGotoStmt(GotoStmt *S) {
+ VisitStmt(S);
+ Record.push_back(Writer.GetLabelID(S->getLabel()));
+ Writer.AddSourceLocation(S->getGotoLoc(), Record);
+ Writer.AddSourceLocation(S->getLabelLoc(), Record);
+ Code = pch::STMT_GOTO;
+}
+
+void PCHStmtWriter::VisitIndirectGotoStmt(IndirectGotoStmt *S) {
+ VisitStmt(S);
+ Writer.AddSourceLocation(S->getGotoLoc(), Record);
+ Writer.AddSourceLocation(S->getStarLoc(), Record);
+ Writer.AddStmt(S->getTarget());
+ Code = pch::STMT_INDIRECT_GOTO;
+}
+
+void PCHStmtWriter::VisitContinueStmt(ContinueStmt *S) {
+ VisitStmt(S);
+ Writer.AddSourceLocation(S->getContinueLoc(), Record);
+ Code = pch::STMT_CONTINUE;
+}
+
+void PCHStmtWriter::VisitBreakStmt(BreakStmt *S) {
+ VisitStmt(S);
+ Writer.AddSourceLocation(S->getBreakLoc(), Record);
+ Code = pch::STMT_BREAK;
+}
+
+void PCHStmtWriter::VisitReturnStmt(ReturnStmt *S) {
+ VisitStmt(S);
+ Writer.AddStmt(S->getRetValue());
+ Writer.AddSourceLocation(S->getReturnLoc(), Record);
+ Writer.AddDeclRef(S->getNRVOCandidate(), Record);
+ Code = pch::STMT_RETURN;
+}
+
+void PCHStmtWriter::VisitDeclStmt(DeclStmt *S) {
+ VisitStmt(S);
+ Writer.AddSourceLocation(S->getStartLoc(), Record);
+ Writer.AddSourceLocation(S->getEndLoc(), Record);
+ DeclGroupRef DG = S->getDeclGroup();
+ for (DeclGroupRef::iterator D = DG.begin(), DEnd = DG.end(); D != DEnd; ++D)
+ Writer.AddDeclRef(*D, Record);
+ Code = pch::STMT_DECL;
+}
+
+void PCHStmtWriter::VisitAsmStmt(AsmStmt *S) {
+ VisitStmt(S);
+ Record.push_back(S->getNumOutputs());
+ Record.push_back(S->getNumInputs());
+ Record.push_back(S->getNumClobbers());
+ Writer.AddSourceLocation(S->getAsmLoc(), Record);
+ Writer.AddSourceLocation(S->getRParenLoc(), Record);
+ Record.push_back(S->isVolatile());
+ Record.push_back(S->isSimple());
+ Record.push_back(S->isMSAsm());
+ Writer.AddStmt(S->getAsmString());
+
+ // Outputs
+ for (unsigned I = 0, N = S->getNumOutputs(); I != N; ++I) {
+ Writer.AddIdentifierRef(S->getOutputIdentifier(I), Record);
+ Writer.AddStmt(S->getOutputConstraintLiteral(I));
+ Writer.AddStmt(S->getOutputExpr(I));
+ }
+
+ // Inputs
+ for (unsigned I = 0, N = S->getNumInputs(); I != N; ++I) {
+ Writer.AddIdentifierRef(S->getInputIdentifier(I), Record);
+ Writer.AddStmt(S->getInputConstraintLiteral(I));
+ Writer.AddStmt(S->getInputExpr(I));
+ }
+
+ // Clobbers
+ for (unsigned I = 0, N = S->getNumClobbers(); I != N; ++I)
+ Writer.AddStmt(S->getClobber(I));
+
+ Code = pch::STMT_ASM;
+}
+
+void PCHStmtWriter::VisitExpr(Expr *E) {
+ VisitStmt(E);
+ Writer.AddTypeRef(E->getType(), Record);
+ Record.push_back(E->isTypeDependent());
+ Record.push_back(E->isValueDependent());
+}
+
+void PCHStmtWriter::VisitPredefinedExpr(PredefinedExpr *E) {
+ VisitExpr(E);
+ Writer.AddSourceLocation(E->getLocation(), Record);
+ Record.push_back(E->getIdentType()); // FIXME: stable encoding
+ Code = pch::EXPR_PREDEFINED;
+}
+
+void PCHStmtWriter::VisitDeclRefExpr(DeclRefExpr *E) {
+ VisitExpr(E);
+
+ Record.push_back(E->hasQualifier());
+ unsigned NumTemplateArgs = E->getNumTemplateArgs();
+ assert((NumTemplateArgs != 0) == E->hasExplicitTemplateArgumentList() &&
+ "Template args list with no args ?");
+ Record.push_back(NumTemplateArgs);
+
+ if (E->hasQualifier()) {
+ Writer.AddNestedNameSpecifier(E->getQualifier(), Record);
+ Writer.AddSourceRange(E->getQualifierRange(), Record);
+ }
+
+ if (NumTemplateArgs)
+ AddExplicitTemplateArgumentList(*E->getExplicitTemplateArgumentList());
+
+ Writer.AddDeclRef(E->getDecl(), Record);
+ Writer.AddSourceLocation(E->getLocation(), Record);
+ Code = pch::EXPR_DECL_REF;
+}
+
+void PCHStmtWriter::VisitIntegerLiteral(IntegerLiteral *E) {
+ VisitExpr(E);
+ Writer.AddSourceLocation(E->getLocation(), Record);
+ Writer.AddAPInt(E->getValue(), Record);
+ Code = pch::EXPR_INTEGER_LITERAL;
+}
+
+void PCHStmtWriter::VisitFloatingLiteral(FloatingLiteral *E) {
+ VisitExpr(E);
+ Writer.AddAPFloat(E->getValue(), Record);
+ Record.push_back(E->isExact());
+ Writer.AddSourceLocation(E->getLocation(), Record);
+ Code = pch::EXPR_FLOATING_LITERAL;
+}
+
+void PCHStmtWriter::VisitImaginaryLiteral(ImaginaryLiteral *E) {
+ VisitExpr(E);
+ Writer.AddStmt(E->getSubExpr());
+ Code = pch::EXPR_IMAGINARY_LITERAL;
+}
+
+void PCHStmtWriter::VisitStringLiteral(StringLiteral *E) {
+ VisitExpr(E);
+ Record.push_back(E->getByteLength());
+ Record.push_back(E->getNumConcatenated());
+ Record.push_back(E->isWide());
+ // FIXME: String data should be stored as a blob at the end of the
+ // StringLiteral. However, we can't do so now because we have no
+ // provision for coping with abbreviations when we're jumping around
+ // the PCH file during deserialization.
+ Record.insert(Record.end(),
+ E->getStrData(), E->getStrData() + E->getByteLength());
+ for (unsigned I = 0, N = E->getNumConcatenated(); I != N; ++I)
+ Writer.AddSourceLocation(E->getStrTokenLoc(I), Record);
+ Code = pch::EXPR_STRING_LITERAL;
+}
+
+void PCHStmtWriter::VisitCharacterLiteral(CharacterLiteral *E) {
+ VisitExpr(E);
+ Record.push_back(E->getValue());
+ Writer.AddSourceLocation(E->getLocation(), Record);
+ Record.push_back(E->isWide());
+ Code = pch::EXPR_CHARACTER_LITERAL;
+}
+
+void PCHStmtWriter::VisitParenExpr(ParenExpr *E) {
+ VisitExpr(E);
+ Writer.AddSourceLocation(E->getLParen(), Record);
+ Writer.AddSourceLocation(E->getRParen(), Record);
+ Writer.AddStmt(E->getSubExpr());
+ Code = pch::EXPR_PAREN;
+}
+
+void PCHStmtWriter::VisitParenListExpr(ParenListExpr *E) {
+ VisitExpr(E);
+ Record.push_back(E->NumExprs);
+ for (unsigned i=0; i != E->NumExprs; ++i)
+ Writer.AddStmt(E->Exprs[i]);
+ Writer.AddSourceLocation(E->LParenLoc, Record);
+ Writer.AddSourceLocation(E->RParenLoc, Record);
+ Code = pch::EXPR_PAREN_LIST;
+}
+
+void PCHStmtWriter::VisitUnaryOperator(UnaryOperator *E) {
+ VisitExpr(E);
+ Writer.AddStmt(E->getSubExpr());
+ Record.push_back(E->getOpcode()); // FIXME: stable encoding
+ Writer.AddSourceLocation(E->getOperatorLoc(), Record);
+ Code = pch::EXPR_UNARY_OPERATOR;
+}
+
+void PCHStmtWriter::VisitOffsetOfExpr(OffsetOfExpr *E) {
+ VisitExpr(E);
+ Record.push_back(E->getNumComponents());
+ Record.push_back(E->getNumExpressions());
+ Writer.AddSourceLocation(E->getOperatorLoc(), Record);
+ Writer.AddSourceLocation(E->getRParenLoc(), Record);
+ Writer.AddTypeSourceInfo(E->getTypeSourceInfo(), Record);
+ for (unsigned I = 0, N = E->getNumComponents(); I != N; ++I) {
+ const OffsetOfExpr::OffsetOfNode &ON = E->getComponent(I);
+ Record.push_back(ON.getKind()); // FIXME: Stable encoding
+ Writer.AddSourceLocation(ON.getRange().getBegin(), Record);
+ Writer.AddSourceLocation(ON.getRange().getEnd(), Record);
+ switch (ON.getKind()) {
+ case OffsetOfExpr::OffsetOfNode::Array:
+ Record.push_back(ON.getArrayExprIndex());
+ break;
+
+ case OffsetOfExpr::OffsetOfNode::Field:
+ Writer.AddDeclRef(ON.getField(), Record);
+ break;
+
+ case OffsetOfExpr::OffsetOfNode::Identifier:
+ Writer.AddIdentifierRef(ON.getFieldName(), Record);
+ break;
+
+ case OffsetOfExpr::OffsetOfNode::Base:
+ // FIXME: Implement this!
+ llvm_unreachable("PCH for offsetof(base-specifier) not implemented");
+ break;
+ }
+ }
+ for (unsigned I = 0, N = E->getNumExpressions(); I != N; ++I)
+ Writer.AddStmt(E->getIndexExpr(I));
+ Code = pch::EXPR_OFFSETOF;
+}
+
+void PCHStmtWriter::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) {
+ VisitExpr(E);
+ Record.push_back(E->isSizeOf());
+ if (E->isArgumentType())
+ Writer.AddTypeSourceInfo(E->getArgumentTypeInfo(), Record);
+ else {
+ Record.push_back(0);
+ Writer.AddStmt(E->getArgumentExpr());
+ }
+ Writer.AddSourceLocation(E->getOperatorLoc(), Record);
+ Writer.AddSourceLocation(E->getRParenLoc(), Record);
+ Code = pch::EXPR_SIZEOF_ALIGN_OF;
+}
+
+void PCHStmtWriter::VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
+ VisitExpr(E);
+ Writer.AddStmt(E->getLHS());
+ Writer.AddStmt(E->getRHS());
+ Writer.AddSourceLocation(E->getRBracketLoc(), Record);
+ Code = pch::EXPR_ARRAY_SUBSCRIPT;
+}
+
+void PCHStmtWriter::VisitCallExpr(CallExpr *E) {
+ VisitExpr(E);
+ Record.push_back(E->getNumArgs());
+ Writer.AddSourceLocation(E->getRParenLoc(), Record);
+ Writer.AddStmt(E->getCallee());
+ for (CallExpr::arg_iterator Arg = E->arg_begin(), ArgEnd = E->arg_end();
+ Arg != ArgEnd; ++Arg)
+ Writer.AddStmt(*Arg);
+ Code = pch::EXPR_CALL;
+}
+
+void PCHStmtWriter::VisitMemberExpr(MemberExpr *E) {
+ // Don't call VisitExpr, we'll write everything here.
+
+ Record.push_back(E->hasQualifier());
+ if (E->hasQualifier()) {
+ Writer.AddNestedNameSpecifier(E->getQualifier(), Record);
+ Writer.AddSourceRange(E->getQualifierRange(), Record);
+ }
+
+ unsigned NumTemplateArgs = E->getNumTemplateArgs();
+ assert((NumTemplateArgs != 0) == E->hasExplicitTemplateArgumentList() &&
+ "Template args list with no args ?");
+ Record.push_back(NumTemplateArgs);
+ if (NumTemplateArgs) {
+ Writer.AddSourceLocation(E->getLAngleLoc(), Record);
+ Writer.AddSourceLocation(E->getRAngleLoc(), Record);
+ for (unsigned i=0; i != NumTemplateArgs; ++i)
+ Writer.AddTemplateArgumentLoc(E->getTemplateArgs()[i], Record);
+ }
+
+ DeclAccessPair FoundDecl = E->getFoundDecl();
+ Writer.AddDeclRef(FoundDecl.getDecl(), Record);
+ Record.push_back(FoundDecl.getAccess());
+
+ Writer.AddTypeRef(E->getType(), Record);
+ Writer.AddStmt(E->getBase());
+ Writer.AddDeclRef(E->getMemberDecl(), Record);
+ Writer.AddSourceLocation(E->getMemberLoc(), Record);
+ Record.push_back(E->isArrow());
+ Code = pch::EXPR_MEMBER;
+}
+
+void PCHStmtWriter::VisitObjCIsaExpr(ObjCIsaExpr *E) {
+ VisitExpr(E);
+ Writer.AddStmt(E->getBase());
+ Writer.AddSourceLocation(E->getIsaMemberLoc(), Record);
+ Record.push_back(E->isArrow());
+ Code = pch::EXPR_OBJC_ISA;
+}
+
+void PCHStmtWriter::VisitCastExpr(CastExpr *E) {
+ VisitExpr(E);
+ Writer.AddStmt(E->getSubExpr());
+ Record.push_back(E->getCastKind()); // FIXME: stable encoding
+ CXXBaseSpecifierArray &BasePath = E->getBasePath();
+ Record.push_back(BasePath.size());
+ for (CXXBaseSpecifierArray::iterator I = BasePath.begin(), E = BasePath.end();
+ I != E; ++I)
+ Writer.AddCXXBaseSpecifier(**I, Record);
+}
+
+void PCHStmtWriter::VisitBinaryOperator(BinaryOperator *E) {
+ VisitExpr(E);
+ Writer.AddStmt(E->getLHS());
+ Writer.AddStmt(E->getRHS());
+ Record.push_back(E->getOpcode()); // FIXME: stable encoding
+ Writer.AddSourceLocation(E->getOperatorLoc(), Record);
+ Code = pch::EXPR_BINARY_OPERATOR;
+}
+
+void PCHStmtWriter::VisitCompoundAssignOperator(CompoundAssignOperator *E) {
+ VisitBinaryOperator(E);
+ Writer.AddTypeRef(E->getComputationLHSType(), Record);
+ Writer.AddTypeRef(E->getComputationResultType(), Record);
+ Code = pch::EXPR_COMPOUND_ASSIGN_OPERATOR;
+}
+
+void PCHStmtWriter::VisitConditionalOperator(ConditionalOperator *E) {
+ VisitExpr(E);
+ Writer.AddStmt(E->getCond());
+ Writer.AddStmt(E->getLHS());
+ Writer.AddStmt(E->getRHS());
+ Writer.AddSourceLocation(E->getQuestionLoc(), Record);
+ Writer.AddSourceLocation(E->getColonLoc(), Record);
+ Code = pch::EXPR_CONDITIONAL_OPERATOR;
+}
+
+void PCHStmtWriter::VisitImplicitCastExpr(ImplicitCastExpr *E) {
+ VisitCastExpr(E);
+ Record.push_back(E->isLvalueCast());
+ Code = pch::EXPR_IMPLICIT_CAST;
+}
+
+void PCHStmtWriter::VisitExplicitCastExpr(ExplicitCastExpr *E) {
+ VisitCastExpr(E);
+ Writer.AddTypeSourceInfo(E->getTypeInfoAsWritten(), Record);
+}
+
+void PCHStmtWriter::VisitCStyleCastExpr(CStyleCastExpr *E) {
+ VisitExplicitCastExpr(E);
+ Writer.AddSourceLocation(E->getLParenLoc(), Record);
+ Writer.AddSourceLocation(E->getRParenLoc(), Record);
+ Code = pch::EXPR_CSTYLE_CAST;
+}
+
+void PCHStmtWriter::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) {
+ VisitExpr(E);
+ Writer.AddSourceLocation(E->getLParenLoc(), Record);
+ Writer.AddTypeSourceInfo(E->getTypeSourceInfo(), Record);
+ Writer.AddStmt(E->getInitializer());
+ Record.push_back(E->isFileScope());
+ Code = pch::EXPR_COMPOUND_LITERAL;
+}
+
+void PCHStmtWriter::VisitExtVectorElementExpr(ExtVectorElementExpr *E) {
+ VisitExpr(E);
+ Writer.AddStmt(E->getBase());
+ Writer.AddIdentifierRef(&E->getAccessor(), Record);
+ Writer.AddSourceLocation(E->getAccessorLoc(), Record);
+ Code = pch::EXPR_EXT_VECTOR_ELEMENT;
+}
+
+void PCHStmtWriter::VisitInitListExpr(InitListExpr *E) {
+ VisitExpr(E);
+ Record.push_back(E->getNumInits());
+ for (unsigned I = 0, N = E->getNumInits(); I != N; ++I)
+ Writer.AddStmt(E->getInit(I));
+ Writer.AddStmt(E->getSyntacticForm());
+ Writer.AddSourceLocation(E->getLBraceLoc(), Record);
+ Writer.AddSourceLocation(E->getRBraceLoc(), Record);
+ Writer.AddDeclRef(E->getInitializedFieldInUnion(), Record);
+ Record.push_back(E->hadArrayRangeDesignator());
+ Code = pch::EXPR_INIT_LIST;
+}
+
+void PCHStmtWriter::VisitDesignatedInitExpr(DesignatedInitExpr *E) {
+ VisitExpr(E);
+ Record.push_back(E->getNumSubExprs());
+ for (unsigned I = 0, N = E->getNumSubExprs(); I != N; ++I)
+ Writer.AddStmt(E->getSubExpr(I));
+ Writer.AddSourceLocation(E->getEqualOrColonLoc(), Record);
+ Record.push_back(E->usesGNUSyntax());
+ for (DesignatedInitExpr::designators_iterator D = E->designators_begin(),
+ DEnd = E->designators_end();
+ D != DEnd; ++D) {
+ if (D->isFieldDesignator()) {
+ if (FieldDecl *Field = D->getField()) {
+ Record.push_back(pch::DESIG_FIELD_DECL);
+ Writer.AddDeclRef(Field, Record);
+ } else {
+ Record.push_back(pch::DESIG_FIELD_NAME);
+ Writer.AddIdentifierRef(D->getFieldName(), Record);
+ }
+ Writer.AddSourceLocation(D->getDotLoc(), Record);
+ Writer.AddSourceLocation(D->getFieldLoc(), Record);
+ } else if (D->isArrayDesignator()) {
+ Record.push_back(pch::DESIG_ARRAY);
+ Record.push_back(D->getFirstExprIndex());
+ Writer.AddSourceLocation(D->getLBracketLoc(), Record);
+ Writer.AddSourceLocation(D->getRBracketLoc(), Record);
+ } else {
+ assert(D->isArrayRangeDesignator() && "Unknown designator");
+ Record.push_back(pch::DESIG_ARRAY_RANGE);
+ Record.push_back(D->getFirstExprIndex());
+ Writer.AddSourceLocation(D->getLBracketLoc(), Record);
+ Writer.AddSourceLocation(D->getEllipsisLoc(), Record);
+ Writer.AddSourceLocation(D->getRBracketLoc(), Record);
+ }
+ }
+ Code = pch::EXPR_DESIGNATED_INIT;
+}
+
+void PCHStmtWriter::VisitImplicitValueInitExpr(ImplicitValueInitExpr *E) {
+ VisitExpr(E);
+ Code = pch::EXPR_IMPLICIT_VALUE_INIT;
+}
+
+void PCHStmtWriter::VisitVAArgExpr(VAArgExpr *E) {
+ VisitExpr(E);
+ Writer.AddStmt(E->getSubExpr());
+ Writer.AddSourceLocation(E->getBuiltinLoc(), Record);
+ Writer.AddSourceLocation(E->getRParenLoc(), Record);
+ Code = pch::EXPR_VA_ARG;
+}
+
+void PCHStmtWriter::VisitAddrLabelExpr(AddrLabelExpr *E) {
+ VisitExpr(E);
+ Writer.AddSourceLocation(E->getAmpAmpLoc(), Record);
+ Writer.AddSourceLocation(E->getLabelLoc(), Record);
+ Record.push_back(Writer.GetLabelID(E->getLabel()));
+ Code = pch::EXPR_ADDR_LABEL;
+}
+
+void PCHStmtWriter::VisitStmtExpr(StmtExpr *E) {
+ VisitExpr(E);
+ Writer.AddStmt(E->getSubStmt());
+ Writer.AddSourceLocation(E->getLParenLoc(), Record);
+ Writer.AddSourceLocation(E->getRParenLoc(), Record);
+ Code = pch::EXPR_STMT;
+}
+
+void PCHStmtWriter::VisitTypesCompatibleExpr(TypesCompatibleExpr *E) {
+ VisitExpr(E);
+ Writer.AddTypeRef(E->getArgType1(), Record);
+ Writer.AddTypeRef(E->getArgType2(), Record);
+ Writer.AddSourceLocation(E->getBuiltinLoc(), Record);
+ Writer.AddSourceLocation(E->getRParenLoc(), Record);
+ Code = pch::EXPR_TYPES_COMPATIBLE;
+}
+
+void PCHStmtWriter::VisitChooseExpr(ChooseExpr *E) {
+ VisitExpr(E);
+ Writer.AddStmt(E->getCond());
+ Writer.AddStmt(E->getLHS());
+ Writer.AddStmt(E->getRHS());
+ Writer.AddSourceLocation(E->getBuiltinLoc(), Record);
+ Writer.AddSourceLocation(E->getRParenLoc(), Record);
+ Code = pch::EXPR_CHOOSE;
+}
+
+void PCHStmtWriter::VisitGNUNullExpr(GNUNullExpr *E) {
+ VisitExpr(E);
+ Writer.AddSourceLocation(E->getTokenLocation(), Record);
+ Code = pch::EXPR_GNU_NULL;
+}
+
+void PCHStmtWriter::VisitShuffleVectorExpr(ShuffleVectorExpr *E) {
+ VisitExpr(E);
+ Record.push_back(E->getNumSubExprs());
+ for (unsigned I = 0, N = E->getNumSubExprs(); I != N; ++I)
+ Writer.AddStmt(E->getExpr(I));
+ Writer.AddSourceLocation(E->getBuiltinLoc(), Record);
+ Writer.AddSourceLocation(E->getRParenLoc(), Record);
+ Code = pch::EXPR_SHUFFLE_VECTOR;
+}
+
+void PCHStmtWriter::VisitBlockExpr(BlockExpr *E) {
+ VisitExpr(E);
+ Writer.AddDeclRef(E->getBlockDecl(), Record);
+ Record.push_back(E->hasBlockDeclRefExprs());
+ Code = pch::EXPR_BLOCK;
+}
+
+void PCHStmtWriter::VisitBlockDeclRefExpr(BlockDeclRefExpr *E) {
+ VisitExpr(E);
+ Writer.AddDeclRef(E->getDecl(), Record);
+ Writer.AddSourceLocation(E->getLocation(), Record);
+ Record.push_back(E->isByRef());
+ Record.push_back(E->isConstQualAdded());
+ Writer.AddStmt(E->getCopyConstructorExpr());
+ Code = pch::EXPR_BLOCK_DECL_REF;
+}
+
+//===----------------------------------------------------------------------===//
+// Objective-C Expressions and Statements.
+//===----------------------------------------------------------------------===//
+
+void PCHStmtWriter::VisitObjCStringLiteral(ObjCStringLiteral *E) {
+ VisitExpr(E);
+ Writer.AddStmt(E->getString());
+ Writer.AddSourceLocation(E->getAtLoc(), Record);
+ Code = pch::EXPR_OBJC_STRING_LITERAL;
+}
+
+void PCHStmtWriter::VisitObjCEncodeExpr(ObjCEncodeExpr *E) {
+ VisitExpr(E);
+ Writer.AddTypeSourceInfo(E->getEncodedTypeSourceInfo(), Record);
+ Writer.AddSourceLocation(E->getAtLoc(), Record);
+ Writer.AddSourceLocation(E->getRParenLoc(), Record);
+ Code = pch::EXPR_OBJC_ENCODE;
+}
+
+void PCHStmtWriter::VisitObjCSelectorExpr(ObjCSelectorExpr *E) {
+ VisitExpr(E);
+ Writer.AddSelectorRef(E->getSelector(), Record);
+ Writer.AddSourceLocation(E->getAtLoc(), Record);
+ Writer.AddSourceLocation(E->getRParenLoc(), Record);
+ Code = pch::EXPR_OBJC_SELECTOR_EXPR;
+}
+
+void PCHStmtWriter::VisitObjCProtocolExpr(ObjCProtocolExpr *E) {
+ VisitExpr(E);
+ Writer.AddDeclRef(E->getProtocol(), Record);
+ Writer.AddSourceLocation(E->getAtLoc(), Record);
+ Writer.AddSourceLocation(E->getRParenLoc(), Record);
+ Code = pch::EXPR_OBJC_PROTOCOL_EXPR;
+}
+
+void PCHStmtWriter::VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) {
+ VisitExpr(E);
+ Writer.AddDeclRef(E->getDecl(), Record);
+ Writer.AddSourceLocation(E->getLocation(), Record);
+ Writer.AddStmt(E->getBase());
+ Record.push_back(E->isArrow());
+ Record.push_back(E->isFreeIvar());
+ Code = pch::EXPR_OBJC_IVAR_REF_EXPR;
+}
+
+void PCHStmtWriter::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E) {
+ VisitExpr(E);
+ Writer.AddDeclRef(E->getProperty(), Record);
+ Writer.AddSourceLocation(E->getLocation(), Record);
+ Writer.AddStmt(E->getBase());
+ Code = pch::EXPR_OBJC_PROPERTY_REF_EXPR;
+}
+
+void PCHStmtWriter::VisitObjCImplicitSetterGetterRefExpr(
+ ObjCImplicitSetterGetterRefExpr *E) {
+ VisitExpr(E);
+ Writer.AddDeclRef(E->getGetterMethod(), Record);
+ Writer.AddDeclRef(E->getSetterMethod(), Record);
+
+ // NOTE: InterfaceDecl and Base are mutually exclusive.
+ Writer.AddDeclRef(E->getInterfaceDecl(), Record);
+ Writer.AddStmt(E->getBase());
+ Writer.AddSourceLocation(E->getLocation(), Record);
+ Writer.AddSourceLocation(E->getClassLoc(), Record);
+ Code = pch::EXPR_OBJC_KVC_REF_EXPR;
+}
+
+void PCHStmtWriter::VisitObjCMessageExpr(ObjCMessageExpr *E) {
+ VisitExpr(E);
+ Record.push_back(E->getNumArgs());
+ Record.push_back((unsigned)E->getReceiverKind()); // FIXME: stable encoding
+ switch (E->getReceiverKind()) {
+ case ObjCMessageExpr::Instance:
+ Writer.AddStmt(E->getInstanceReceiver());
+ break;
+
+ case ObjCMessageExpr::Class:
+ Writer.AddTypeSourceInfo(E->getClassReceiverTypeInfo(), Record);
+ break;
+
+ case ObjCMessageExpr::SuperClass:
+ case ObjCMessageExpr::SuperInstance:
+ Writer.AddTypeRef(E->getSuperType(), Record);
+ Writer.AddSourceLocation(E->getSuperLoc(), Record);
+ break;
+ }
+
+ if (E->getMethodDecl()) {
+ Record.push_back(1);
+ Writer.AddDeclRef(E->getMethodDecl(), Record);
+ } else {
+ Record.push_back(0);
+ Writer.AddSelectorRef(E->getSelector(), Record);
+ }
+
+ Writer.AddSourceLocation(E->getLeftLoc(), Record);
+ Writer.AddSourceLocation(E->getRightLoc(), Record);
+
+ for (CallExpr::arg_iterator Arg = E->arg_begin(), ArgEnd = E->arg_end();
+ Arg != ArgEnd; ++Arg)
+ Writer.AddStmt(*Arg);
+ Code = pch::EXPR_OBJC_MESSAGE_EXPR;
+}
+
+void PCHStmtWriter::VisitObjCSuperExpr(ObjCSuperExpr *E) {
+ VisitExpr(E);
+ Writer.AddSourceLocation(E->getLoc(), Record);
+ Code = pch::EXPR_OBJC_SUPER_EXPR;
+}
+
+void PCHStmtWriter::VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) {
+ VisitStmt(S);
+ Writer.AddStmt(S->getElement());
+ Writer.AddStmt(S->getCollection());
+ Writer.AddStmt(S->getBody());
+ Writer.AddSourceLocation(S->getForLoc(), Record);
+ Writer.AddSourceLocation(S->getRParenLoc(), Record);
+ Code = pch::STMT_OBJC_FOR_COLLECTION;
+}
+
+void PCHStmtWriter::VisitObjCAtCatchStmt(ObjCAtCatchStmt *S) {
+ Writer.AddStmt(S->getCatchBody());
+ Writer.AddDeclRef(S->getCatchParamDecl(), Record);
+ Writer.AddSourceLocation(S->getAtCatchLoc(), Record);
+ Writer.AddSourceLocation(S->getRParenLoc(), Record);
+ Code = pch::STMT_OBJC_CATCH;
+}
+
+void PCHStmtWriter::VisitObjCAtFinallyStmt(ObjCAtFinallyStmt *S) {
+ Writer.AddStmt(S->getFinallyBody());
+ Writer.AddSourceLocation(S->getAtFinallyLoc(), Record);
+ Code = pch::STMT_OBJC_FINALLY;
+}
+
+void PCHStmtWriter::VisitObjCAtTryStmt(ObjCAtTryStmt *S) {
+ Record.push_back(S->getNumCatchStmts());
+ Record.push_back(S->getFinallyStmt() != 0);
+ Writer.AddStmt(S->getTryBody());
+ for (unsigned I = 0, N = S->getNumCatchStmts(); I != N; ++I)
+ Writer.AddStmt(S->getCatchStmt(I));
+ if (S->getFinallyStmt())
+ Writer.AddStmt(S->getFinallyStmt());
+ Writer.AddSourceLocation(S->getAtTryLoc(), Record);
+ Code = pch::STMT_OBJC_AT_TRY;
+}
+
+void PCHStmtWriter::VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *S) {
+ Writer.AddStmt(S->getSynchExpr());
+ Writer.AddStmt(S->getSynchBody());
+ Writer.AddSourceLocation(S->getAtSynchronizedLoc(), Record);
+ Code = pch::STMT_OBJC_AT_SYNCHRONIZED;
+}
+
+void PCHStmtWriter::VisitObjCAtThrowStmt(ObjCAtThrowStmt *S) {
+ Writer.AddStmt(S->getThrowExpr());
+ Writer.AddSourceLocation(S->getThrowLoc(), Record);
+ Code = pch::STMT_OBJC_AT_THROW;
+}
+
+//===----------------------------------------------------------------------===//
+// C++ Expressions and Statements.
+//===----------------------------------------------------------------------===//
+
+void PCHStmtWriter::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
+ VisitCallExpr(E);
+ Record.push_back(E->getOperator());
+ Code = pch::EXPR_CXX_OPERATOR_CALL;
+}
+
+void PCHStmtWriter::VisitCXXMemberCallExpr(CXXMemberCallExpr *E) {
+ VisitCallExpr(E);
+ Code = pch::EXPR_CXX_MEMBER_CALL;
+}
+
+void PCHStmtWriter::VisitCXXConstructExpr(CXXConstructExpr *E) {
+ VisitExpr(E);
+ Record.push_back(E->getNumArgs());
+ for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I)
+ Writer.AddStmt(E->getArg(I));
+ Writer.AddDeclRef(E->getConstructor(), Record);
+ Writer.AddSourceLocation(E->getLocation(), Record);
+ Record.push_back(E->isElidable());
+ Record.push_back(E->requiresZeroInitialization());
+ Record.push_back(E->getConstructionKind()); // FIXME: stable encoding
+ Code = pch::EXPR_CXX_CONSTRUCT;
+}
+
+void PCHStmtWriter::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *E) {
+ VisitCXXConstructExpr(E);
+ Writer.AddSourceLocation(E->getTypeBeginLoc(), Record);
+ Writer.AddSourceLocation(E->getRParenLoc(), Record);
+ Code = pch::EXPR_CXX_TEMPORARY_OBJECT;
+}
+
+void PCHStmtWriter::VisitCXXNamedCastExpr(CXXNamedCastExpr *E) {
+ VisitExplicitCastExpr(E);
+ Writer.AddSourceLocation(E->getOperatorLoc(), Record);
+}
+
+void PCHStmtWriter::VisitCXXStaticCastExpr(CXXStaticCastExpr *E) {
+ VisitCXXNamedCastExpr(E);
+ Code = pch::EXPR_CXX_STATIC_CAST;
+}
+
+void PCHStmtWriter::VisitCXXDynamicCastExpr(CXXDynamicCastExpr *E) {
+ VisitCXXNamedCastExpr(E);
+ Code = pch::EXPR_CXX_DYNAMIC_CAST;
+}
+
+void PCHStmtWriter::VisitCXXReinterpretCastExpr(CXXReinterpretCastExpr *E) {
+ VisitCXXNamedCastExpr(E);
+ Code = pch::EXPR_CXX_REINTERPRET_CAST;
+}
+
+void PCHStmtWriter::VisitCXXConstCastExpr(CXXConstCastExpr *E) {
+ VisitCXXNamedCastExpr(E);
+ Code = pch::EXPR_CXX_CONST_CAST;
+}
+
+void PCHStmtWriter::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E) {
+ VisitExplicitCastExpr(E);
+ Writer.AddSourceLocation(E->getTypeBeginLoc(), Record);
+ Writer.AddSourceLocation(E->getRParenLoc(), Record);
+ Code = pch::EXPR_CXX_FUNCTIONAL_CAST;
+}
+
+void PCHStmtWriter::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E) {
+ VisitExpr(E);
+ Record.push_back(E->getValue());
+ Writer.AddSourceLocation(E->getLocation(), Record);
+ Code = pch::EXPR_CXX_BOOL_LITERAL;
+}
+
+void PCHStmtWriter::VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *E) {
+ VisitExpr(E);
+ Writer.AddSourceLocation(E->getLocation(), Record);
+ Code = pch::EXPR_CXX_NULL_PTR_LITERAL;
+}
+
+void PCHStmtWriter::VisitCXXTypeidExpr(CXXTypeidExpr *E) {
+ VisitExpr(E);
+ Writer.AddSourceRange(E->getSourceRange(), Record);
+ if (E->isTypeOperand()) {
+ Writer.AddTypeSourceInfo(E->getTypeOperandSourceInfo(), Record);
+ Code = pch::EXPR_CXX_TYPEID_TYPE;
+ } else {
+ Writer.AddStmt(E->getExprOperand());
+ Code = pch::EXPR_CXX_TYPEID_EXPR;
+ }
+}
+
+void PCHStmtWriter::VisitCXXThisExpr(CXXThisExpr *E) {
+ VisitExpr(E);
+ Writer.AddSourceLocation(E->getLocation(), Record);
+ Record.push_back(E->isImplicit());
+ Code = pch::EXPR_CXX_THIS;
+}
+
+void PCHStmtWriter::VisitCXXThrowExpr(CXXThrowExpr *E) {
+ VisitExpr(E);
+ Writer.AddSourceLocation(E->getThrowLoc(), Record);
+ Writer.AddStmt(E->getSubExpr());
+ Code = pch::EXPR_CXX_THROW;
+}
+
+void PCHStmtWriter::VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) {
+ VisitExpr(E);
+
+ bool HasOtherExprStored = E->Param.getInt();
+ // Store these first, the reader reads them before creation.
+ Record.push_back(HasOtherExprStored);
+ if (HasOtherExprStored)
+ Writer.AddStmt(E->getExpr());
+ Writer.AddDeclRef(E->getParam(), Record);
+ Writer.AddSourceLocation(E->getUsedLocation(), Record);
+
+ Code = pch::EXPR_CXX_DEFAULT_ARG;
+}
+
+void PCHStmtWriter::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) {
+ VisitExpr(E);
+ Writer.AddCXXTemporary(E->getTemporary(), Record);
+ Writer.AddStmt(E->getSubExpr());
+ Code = pch::EXPR_CXX_BIND_TEMPORARY;
+}
+
+void PCHStmtWriter::VisitCXXBindReferenceExpr(CXXBindReferenceExpr *E) {
+ VisitExpr(E);
+ Writer.AddStmt(E->getSubExpr());
+ Record.push_back(E->extendsLifetime());
+ Record.push_back(E->requiresTemporaryCopy());
+ Code = pch::EXPR_CXX_BIND_REFERENCE;
+}
+
+void PCHStmtWriter::VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E) {
+ VisitExpr(E);
+ Writer.AddSourceLocation(E->getTypeBeginLoc(), Record);
+ Writer.AddSourceLocation(E->getRParenLoc(), Record);
+ Code = pch::EXPR_CXX_SCALAR_VALUE_INIT;
+}
+
+void PCHStmtWriter::VisitCXXNewExpr(CXXNewExpr *E) {
+ VisitExpr(E);
+ Record.push_back(E->isGlobalNew());
+ Record.push_back(E->hasInitializer());
+ Record.push_back(E->isArray());
+ Record.push_back(E->getNumPlacementArgs());
+ Record.push_back(E->getNumConstructorArgs());
+ Writer.AddDeclRef(E->getOperatorNew(), Record);
+ Writer.AddDeclRef(E->getOperatorDelete(), Record);
+ Writer.AddDeclRef(E->getConstructor(), Record);
+ Writer.AddSourceRange(E->getTypeIdParens(), Record);
+ Writer.AddSourceLocation(E->getStartLoc(), Record);
+ Writer.AddSourceLocation(E->getEndLoc(), Record);
+ for (CXXNewExpr::arg_iterator I = E->raw_arg_begin(), e = E->raw_arg_end();
+ I != e; ++I)
+ Writer.AddStmt(*I);
+
+ Code = pch::EXPR_CXX_NEW;
+}
+
+void PCHStmtWriter::VisitCXXDeleteExpr(CXXDeleteExpr *E) {
+ VisitExpr(E);
+ Record.push_back(E->isGlobalDelete());
+ Record.push_back(E->isArrayForm());
+ Writer.AddDeclRef(E->getOperatorDelete(), Record);
+ Writer.AddStmt(E->getArgument());
+ Writer.AddSourceLocation(E->getSourceRange().getBegin(), Record);
+
+ Code = pch::EXPR_CXX_DELETE;
+}
+
+void PCHStmtWriter::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E) {
+ VisitExpr(E);
+
+ Writer.AddStmt(E->getBase());
+ Record.push_back(E->isArrow());
+ Writer.AddSourceLocation(E->getOperatorLoc(), Record);
+ Writer.AddNestedNameSpecifier(E->getQualifier(), Record);
+ Writer.AddSourceRange(E->getQualifierRange(), Record);
+ Writer.AddTypeSourceInfo(E->getScopeTypeInfo(), Record);
+ Writer.AddSourceLocation(E->getColonColonLoc(), Record);
+ Writer.AddSourceLocation(E->getTildeLoc(), Record);
+
+ // PseudoDestructorTypeStorage.
+ Writer.AddIdentifierRef(E->getDestroyedTypeIdentifier(), Record);
+ if (E->getDestroyedTypeIdentifier())
+ Writer.AddSourceLocation(E->getDestroyedTypeLoc(), Record);
+ else
+ Writer.AddTypeSourceInfo(E->getDestroyedTypeInfo(), Record);
+
+ Code = pch::EXPR_CXX_PSEUDO_DESTRUCTOR;
+}
+
+void PCHStmtWriter::VisitCXXExprWithTemporaries(CXXExprWithTemporaries *E) {
+ VisitExpr(E);
+ Record.push_back(E->getNumTemporaries());
+ for (unsigned i = 0, e = E->getNumTemporaries(); i != e; ++i)
+ Writer.AddCXXTemporary(E->getTemporary(i), Record);
+
+ Writer.AddStmt(E->getSubExpr());
+ Code = pch::EXPR_CXX_EXPR_WITH_TEMPORARIES;
+}
+
+void
+PCHStmtWriter::VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E){
+ VisitExpr(E);
+
+ // Don't emit anything here, NumTemplateArgs must be emitted first.
+
+ if (E->hasExplicitTemplateArgs()) {
+ const ExplicitTemplateArgumentList &Args
+ = *E->getExplicitTemplateArgumentList();
+ assert(Args.NumTemplateArgs &&
+ "Num of template args was zero! PCH reading will mess up!");
+ Record.push_back(Args.NumTemplateArgs);
+ AddExplicitTemplateArgumentList(Args);
+ } else {
+ Record.push_back(0);
+ }
+
+ if (!E->isImplicitAccess())
+ Writer.AddStmt(E->getBase());
+ else
+ Writer.AddStmt(0);
+ Writer.AddTypeRef(E->getBaseType(), Record);
+ Record.push_back(E->isArrow());
+ Writer.AddSourceLocation(E->getOperatorLoc(), Record);
+ Writer.AddNestedNameSpecifier(E->getQualifier(), Record);
+ Writer.AddSourceRange(E->getQualifierRange(), Record);
+ Writer.AddDeclRef(E->getFirstQualifierFoundInScope(), Record);
+ Writer.AddDeclarationName(E->getMember(), Record);
+ Writer.AddSourceLocation(E->getMemberLoc(), Record);
+ Code = pch::EXPR_CXX_DEPENDENT_SCOPE_MEMBER;
+}
+
+void
+PCHStmtWriter::VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E) {
+ VisitExpr(E);
+
+ // Don't emit anything here, NumTemplateArgs must be emitted first.
+
+ if (E->hasExplicitTemplateArgs()) {
+ const ExplicitTemplateArgumentList &Args = E->getExplicitTemplateArgs();
+ assert(Args.NumTemplateArgs &&
+ "Num of template args was zero! PCH reading will mess up!");
+ Record.push_back(Args.NumTemplateArgs);
+ AddExplicitTemplateArgumentList(Args);
+ } else {
+ Record.push_back(0);
+ }
+
+ Writer.AddDeclarationName(E->getDeclName(), Record);
+ Writer.AddSourceLocation(E->getLocation(), Record);
+ Writer.AddSourceRange(E->getQualifierRange(), Record);
+ Writer.AddNestedNameSpecifier(E->getQualifier(), Record);
+ Code = pch::EXPR_CXX_DEPENDENT_SCOPE_DECL_REF;
+}
+
+void
+PCHStmtWriter::VisitCXXUnresolvedConstructExpr(CXXUnresolvedConstructExpr *E) {
+ VisitExpr(E);
+ Record.push_back(E->arg_size());
+ for (CXXUnresolvedConstructExpr::arg_iterator
+ ArgI = E->arg_begin(), ArgE = E->arg_end(); ArgI != ArgE; ++ArgI)
+ Writer.AddStmt(*ArgI);
+ Writer.AddSourceLocation(E->getTypeBeginLoc(), Record);
+ Writer.AddTypeRef(E->getTypeAsWritten(), Record);
+ Writer.AddSourceLocation(E->getLParenLoc(), Record);
+ Writer.AddSourceLocation(E->getRParenLoc(), Record);
+ Code = pch::EXPR_CXX_UNRESOLVED_CONSTRUCT;
+}
+
+void PCHStmtWriter::VisitOverloadExpr(OverloadExpr *E) {
+ VisitExpr(E);
+
+ // Don't emit anything here, NumTemplateArgs must be emitted first.
+
+ if (E->hasExplicitTemplateArgs()) {
+ const ExplicitTemplateArgumentList &Args = E->getExplicitTemplateArgs();
+ assert(Args.NumTemplateArgs &&
+ "Num of template args was zero! PCH reading will mess up!");
+ Record.push_back(Args.NumTemplateArgs);
+ AddExplicitTemplateArgumentList(Args);
+ } else {
+ Record.push_back(0);
+ }
+
+ Record.push_back(E->getNumDecls());
+ for (OverloadExpr::decls_iterator
+ OvI = E->decls_begin(), OvE = E->decls_end(); OvI != OvE; ++OvI) {
+ Writer.AddDeclRef(OvI.getDecl(), Record);
+ Record.push_back(OvI.getAccess());
+ }
+
+ Writer.AddDeclarationName(E->getName(), Record);
+ Writer.AddNestedNameSpecifier(E->getQualifier(), Record);
+ Writer.AddSourceRange(E->getQualifierRange(), Record);
+ Writer.AddSourceLocation(E->getNameLoc(), Record);
+}
+
+void PCHStmtWriter::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *E) {
+ VisitOverloadExpr(E);
+ Record.push_back(E->isArrow());
+ Record.push_back(E->hasUnresolvedUsing());
+ Writer.AddStmt(!E->isImplicitAccess() ? E->getBase() : 0);
+ Writer.AddTypeRef(E->getBaseType(), Record);
+ Writer.AddSourceLocation(E->getOperatorLoc(), Record);
+ Code = pch::EXPR_CXX_UNRESOLVED_MEMBER;
+}
+
+void PCHStmtWriter::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *E) {
+ VisitOverloadExpr(E);
+ Record.push_back(E->requiresADL());
+ Record.push_back(E->isOverloaded());
+ Writer.AddDeclRef(E->getNamingClass(), Record);
+ Code = pch::EXPR_CXX_UNRESOLVED_LOOKUP;
+}
+
+void PCHStmtWriter::VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *E) {
+ VisitExpr(E);
+ Record.push_back(E->getTrait());
+ Writer.AddSourceRange(E->getSourceRange(), Record);
+ Writer.AddTypeRef(E->getQueriedType(), Record);
+ Code = pch::EXPR_CXX_UNARY_TYPE_TRAIT;
+}
+
+//===----------------------------------------------------------------------===//
+// PCHWriter Implementation
+//===----------------------------------------------------------------------===//
+
+unsigned PCHWriter::RecordSwitchCaseID(SwitchCase *S) {
+ assert(SwitchCaseIDs.find(S) == SwitchCaseIDs.end() &&
+ "SwitchCase recorded twice");
+ unsigned NextID = SwitchCaseIDs.size();
+ SwitchCaseIDs[S] = NextID;
+ return NextID;
+}
+
+unsigned PCHWriter::getSwitchCaseID(SwitchCase *S) {
+ assert(SwitchCaseIDs.find(S) != SwitchCaseIDs.end() &&
+ "SwitchCase hasn't been seen yet");
+ return SwitchCaseIDs[S];
+}
+
+/// \brief Retrieve the ID for the given label statement, which may
+/// or may not have been emitted yet.
+unsigned PCHWriter::GetLabelID(LabelStmt *S) {
+ std::map<LabelStmt *, unsigned>::iterator Pos = LabelIDs.find(S);
+ if (Pos != LabelIDs.end())
+ return Pos->second;
+
+ unsigned NextID = LabelIDs.size();
+ LabelIDs[S] = NextID;
+ return NextID;
+}
+
+/// \brief Write the given substatement or subexpression to the
+/// bitstream.
+void PCHWriter::WriteSubStmt(Stmt *S) {
+ RecordData Record;
+ PCHStmtWriter Writer(*this, Record);
+ ++NumStatements;
+
+ if (!S) {
+ Stream.EmitRecord(pch::STMT_NULL_PTR, Record);
+ return;
+ }
+
+ // Redirect PCHWriter::AddStmt to collect sub stmts.
+ llvm::SmallVector<Stmt *, 16> SubStmts;
+ CollectedStmts = &SubStmts;
+
+ Writer.Code = pch::STMT_NULL_PTR;
+ Writer.Visit(S);
+
+#ifndef NDEBUG
+ if (Writer.Code == pch::STMT_NULL_PTR) {
+ SourceManager &SrcMgr
+ = DeclIDs.begin()->first->getASTContext().getSourceManager();
+ S->dump(SrcMgr);
+ assert(0 && "Unhandled sub statement writing PCH file");
+ }
+#endif
+
+ // Revert PCHWriter::AddStmt.
+ CollectedStmts = &StmtsToEmit;
+
+ // Write the sub stmts in reverse order, last to first. When reading them back
+ // we will read them in correct order by "pop"ing them from the Stmts stack.
+ // This simplifies reading and allows to store a variable number of sub stmts
+ // without knowing it in advance.
+ while (!SubStmts.empty())
+ WriteSubStmt(SubStmts.pop_back_val());
+
+ Stream.EmitRecord(Writer.Code, Record);
+}
+
+/// \brief Flush all of the statements that have been added to the
+/// queue via AddStmt().
+void PCHWriter::FlushStmts() {
+ RecordData Record;
+
+ for (unsigned I = 0, N = StmtsToEmit.size(); I != N; ++I) {
+ WriteSubStmt(StmtsToEmit[I]);
+
+ assert(N == StmtsToEmit.size() &&
+ "Substatement writen via AddStmt rather than WriteSubStmt!");
+
+ // Note that we are at the end of a full expression. Any
+ // expression records that follow this one are part of a different
+ // expression.
+ Stream.EmitRecord(pch::STMT_STOP, Record);
+ }
+
+ StmtsToEmit.clear();
+}
diff --git a/contrib/llvm/tools/clang/lib/Frontend/PrintParserCallbacks.cpp b/contrib/llvm/tools/clang/lib/Frontend/PrintParserCallbacks.cpp
new file mode 100644
index 0000000..9220677
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Frontend/PrintParserCallbacks.cpp
@@ -0,0 +1,852 @@
+//===--- PrintParserActions.cpp - Implement -parse-print-callbacks mode ---===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This code simply runs the preprocessor on the input file and prints out the
+// result. This is the traditional behavior of the -E option.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/Utils.h"
+#include "clang/Parse/Action.h"
+#include "clang/Parse/DeclSpec.h"
+#include "llvm/Support/raw_ostream.h"
+using namespace clang;
+
+namespace {
+ class ParserPrintActions : public MinimalAction {
+ llvm::raw_ostream& Out;
+
+ public:
+ ParserPrintActions(Preprocessor &PP, llvm::raw_ostream& OS)
+ : MinimalAction(PP), Out(OS) {}
+
+ // Printing Functions which also must call MinimalAction
+
+ /// ActOnDeclarator - This callback is invoked when a declarator is parsed
+ /// and 'Init' specifies the initializer if any. This is for things like:
+ /// "int X = 4" or "typedef int foo".
+ virtual DeclPtrTy ActOnDeclarator(Scope *S, Declarator &D) {
+ Out << __FUNCTION__ << " ";
+ if (IdentifierInfo *II = D.getIdentifier()) {
+ Out << "'" << II->getName() << "'";
+ } else {
+ Out << "<anon>";
+ }
+ Out << "\n";
+
+ // Pass up to EmptyActions so that the symbol table is maintained right.
+ return MinimalAction::ActOnDeclarator(S, D);
+ }
+ /// ActOnPopScope - This callback is called immediately before the specified
+ /// scope is popped and deleted.
+ virtual void ActOnPopScope(SourceLocation Loc, Scope *S) {
+ Out << __FUNCTION__ << "\n";
+ return MinimalAction::ActOnPopScope(Loc, S);
+ }
+
+ /// ActOnTranslationUnitScope - This callback is called once, immediately
+ /// after creating the translation unit scope (in Parser::Initialize).
+ virtual void ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) {
+ Out << __FUNCTION__ << "\n";
+ MinimalAction::ActOnTranslationUnitScope(Loc, S);
+ }
+
+
+ Action::DeclPtrTy ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
+ IdentifierInfo *ClassName,
+ SourceLocation ClassLoc,
+ IdentifierInfo *SuperName,
+ SourceLocation SuperLoc,
+ const DeclPtrTy *ProtoRefs,
+ unsigned NumProtocols,
+ const SourceLocation *ProtoLocs,
+ SourceLocation EndProtoLoc,
+ AttributeList *AttrList) {
+ Out << __FUNCTION__ << "\n";
+ return MinimalAction::ActOnStartClassInterface(AtInterfaceLoc,
+ ClassName, ClassLoc,
+ SuperName, SuperLoc,
+ ProtoRefs, NumProtocols,
+ ProtoLocs, EndProtoLoc,
+ AttrList);
+ }
+
+ /// ActOnForwardClassDeclaration -
+ /// Scope will always be top level file scope.
+ Action::DeclPtrTy ActOnForwardClassDeclaration(SourceLocation AtClassLoc,
+ IdentifierInfo **IdentList,
+ SourceLocation *IdentLocs,
+ unsigned NumElts) {
+ Out << __FUNCTION__ << "\n";
+ return MinimalAction::ActOnForwardClassDeclaration(AtClassLoc, IdentList,
+ IdentLocs, NumElts);
+ }
+
+ // Pure Printing
+
+ /// ActOnParamDeclarator - This callback is invoked when a parameter
+ /// declarator is parsed. This callback only occurs for functions
+ /// with prototypes. S is the function prototype scope for the
+ /// parameters (C++ [basic.scope.proto]).
+ virtual DeclPtrTy ActOnParamDeclarator(Scope *S, Declarator &D) {
+ Out << __FUNCTION__ << " ";
+ if (IdentifierInfo *II = D.getIdentifier()) {
+ Out << "'" << II->getName() << "'";
+ } else {
+ Out << "<anon>";
+ }
+ Out << "\n";
+ return DeclPtrTy();
+ }
+
+ /// AddInitializerToDecl - This action is called immediately after
+ /// ParseDeclarator (when an initializer is present). The code is factored
+ /// this way to make sure we are able to handle the following:
+ /// void func() { int xx = xx; }
+ /// This allows ActOnDeclarator to register "xx" prior to parsing the
+ /// initializer. The declaration above should still result in a warning,
+ /// since the reference to "xx" is uninitialized.
+ virtual void AddInitializerToDecl(DeclPtrTy Dcl, ExprArg Init) {
+ Out << __FUNCTION__ << "\n";
+ }
+
+ /// FinalizeDeclaratorGroup - After a sequence of declarators are parsed,
+ /// this gives the actions implementation a chance to process the group as
+ /// a whole.
+ virtual DeclGroupPtrTy FinalizeDeclaratorGroup(Scope *S, const DeclSpec& DS,
+ DeclPtrTy *Group,
+ unsigned NumDecls) {
+ Out << __FUNCTION__ << "\n";
+ return DeclGroupPtrTy();
+ }
+
+ /// ActOnStartOfFunctionDef - This is called at the start of a function
+ /// definition, instead of calling ActOnDeclarator. The Declarator includes
+ /// information about formal arguments that are part of this function.
+ virtual DeclPtrTy ActOnStartOfFunctionDef(Scope *FnBodyScope,
+ Declarator &D){
+ Out << __FUNCTION__ << "\n";
+ return DeclPtrTy();
+ }
+
+ /// ActOnStartOfFunctionDef - This is called at the start of a function
+ /// definition, after the FunctionDecl has already been created.
+ virtual DeclPtrTy ActOnStartOfFunctionDef(Scope *FnBodyScope, DeclPtrTy D) {
+ Out << __FUNCTION__ << "\n";
+ return DeclPtrTy();
+ }
+
+ virtual void ActOnStartOfObjCMethodDef(Scope *FnBodyScope, DeclPtrTy D) {
+ Out << __FUNCTION__ << "\n";
+ }
+
+ /// ActOnFunctionDefBody - This is called when a function body has completed
+ /// parsing. Decl is the DeclTy returned by ParseStartOfFunctionDef.
+ virtual DeclPtrTy ActOnFinishFunctionBody(DeclPtrTy Decl, StmtArg Body) {
+ Out << __FUNCTION__ << "\n";
+ return DeclPtrTy();
+ }
+
+ virtual DeclPtrTy ActOnFileScopeAsmDecl(SourceLocation Loc,
+ ExprArg AsmString) {
+ Out << __FUNCTION__ << "\n";
+ return DeclPtrTy();
+ }
+
+ /// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with
+ /// no declarator (e.g. "struct foo;") is parsed.
+ virtual DeclPtrTy ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
+ DeclSpec &DS) {
+ Out << __FUNCTION__ << "\n";
+ return DeclPtrTy();
+ }
+
+ /// ActOnLinkageSpec - Parsed a C++ linkage-specification that
+ /// contained braces. Lang/StrSize contains the language string that
+ /// was parsed at location Loc. Decls/NumDecls provides the
+ /// declarations parsed inside the linkage specification.
+ virtual DeclPtrTy ActOnLinkageSpec(SourceLocation Loc,
+ SourceLocation LBrace,
+ SourceLocation RBrace, const char *Lang,
+ unsigned StrSize,
+ DeclPtrTy *Decls, unsigned NumDecls) {
+ Out << __FUNCTION__ << "\n";
+ return DeclPtrTy();
+ }
+
+ /// ActOnLinkageSpec - Parsed a C++ linkage-specification without
+ /// braces. Lang/StrSize contains the language string that was
+ /// parsed at location Loc. D is the declaration parsed.
+ virtual DeclPtrTy ActOnLinkageSpec(SourceLocation Loc, const char *Lang,
+ unsigned StrSize, DeclPtrTy D) {
+ return DeclPtrTy();
+ }
+
+ //===------------------------------------------------------------------===//
+ // Type Parsing Callbacks.
+ //===------------------------------------------------------------------===//
+
+ virtual TypeResult ActOnTypeName(Scope *S, Declarator &D) {
+ Out << __FUNCTION__ << "\n";
+ return TypeResult();
+ }
+
+ virtual DeclPtrTy ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
+ SourceLocation KWLoc, CXXScopeSpec &SS,
+ IdentifierInfo *Name, SourceLocation NameLoc,
+ AttributeList *Attr, AccessSpecifier AS,
+ MultiTemplateParamsArg TemplateParameterLists,
+ bool &OwnedDecl, bool &IsDependent) {
+ // TagType is an instance of DeclSpec::TST, indicating what kind of tag this
+ // is (struct/union/enum/class).
+ Out << __FUNCTION__ << "\n";
+ return DeclPtrTy();
+ }
+
+ /// Act on @defs() element found when parsing a structure. ClassName is the
+ /// name of the referenced class.
+ virtual void ActOnDefs(Scope *S, DeclPtrTy TagD, SourceLocation DeclStart,
+ IdentifierInfo *ClassName,
+ llvm::SmallVectorImpl<DeclPtrTy> &Decls) {
+ Out << __FUNCTION__ << "\n";
+ }
+
+ virtual DeclPtrTy ActOnField(Scope *S, DeclPtrTy TagD,
+ SourceLocation DeclStart,
+ Declarator &D, ExprTy *BitfieldWidth) {
+ Out << __FUNCTION__ << "\n";
+ return DeclPtrTy();
+ }
+
+ virtual DeclPtrTy ActOnIvar(Scope *S, SourceLocation DeclStart,
+ DeclPtrTy IntfDecl,
+ Declarator &D, ExprTy *BitfieldWidth,
+ tok::ObjCKeywordKind visibility) {
+ Out << __FUNCTION__ << "\n";
+ return DeclPtrTy();
+ }
+
+ virtual void ActOnFields(Scope* S, SourceLocation RecLoc, DeclPtrTy TagDecl,
+ DeclPtrTy *Fields, unsigned NumFields,
+ SourceLocation LBrac, SourceLocation RBrac,
+ AttributeList *AttrList) {
+ Out << __FUNCTION__ << "\n";
+ }
+
+ virtual DeclPtrTy ActOnEnumConstant(Scope *S, DeclPtrTy EnumDecl,
+ DeclPtrTy LastEnumConstant,
+ SourceLocation IdLoc,IdentifierInfo *Id,
+ SourceLocation EqualLoc, ExprTy *Val) {
+ Out << __FUNCTION__ << "\n";
+ return DeclPtrTy();
+ }
+
+ virtual void ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
+ SourceLocation RBraceLoc, DeclPtrTy EnumDecl,
+ DeclPtrTy *Elements, unsigned NumElements,
+ Scope *S, AttributeList *AttrList) {
+ Out << __FUNCTION__ << "\n";
+ }
+
+ //===------------------------------------------------------------------===//
+ // Statement Parsing Callbacks.
+ //===------------------------------------------------------------------===//
+
+ virtual OwningStmtResult ActOnNullStmt(SourceLocation SemiLoc) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+
+ virtual OwningStmtResult ActOnCompoundStmt(SourceLocation L,
+ SourceLocation R,
+ MultiStmtArg Elts,
+ bool isStmtExpr) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+ virtual OwningStmtResult ActOnDeclStmt(DeclGroupPtrTy Decl,
+ SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+
+ virtual OwningStmtResult ActOnExprStmt(FullExprArg Expr) {
+ Out << __FUNCTION__ << "\n";
+ return OwningStmtResult(*this, Expr->release());
+ }
+
+ /// ActOnCaseStmt - Note that this handles the GNU 'case 1 ... 4' extension,
+ /// which can specify an RHS value.
+ virtual OwningStmtResult ActOnCaseStmt(SourceLocation CaseLoc,
+ ExprArg LHSVal,
+ SourceLocation DotDotDotLoc,
+ ExprArg RHSVal,
+ SourceLocation ColonLoc) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+ virtual OwningStmtResult ActOnDefaultStmt(SourceLocation DefaultLoc,
+ SourceLocation ColonLoc,
+ StmtArg SubStmt, Scope *CurScope){
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+
+ virtual OwningStmtResult ActOnLabelStmt(SourceLocation IdentLoc,
+ IdentifierInfo *II,
+ SourceLocation ColonLoc,
+ StmtArg SubStmt) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+
+ virtual OwningStmtResult ActOnIfStmt(SourceLocation IfLoc,
+ FullExprArg CondVal, DeclPtrTy CondVar,
+ StmtArg ThenVal,
+ SourceLocation ElseLoc,
+ StmtArg ElseVal) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+
+ virtual OwningStmtResult ActOnStartOfSwitchStmt(SourceLocation SwitchLoc,
+ ExprArg Cond,
+ DeclPtrTy CondVar) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+
+ virtual OwningStmtResult ActOnFinishSwitchStmt(SourceLocation SwitchLoc,
+ StmtArg Switch,
+ StmtArg Body) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+
+ virtual OwningStmtResult ActOnWhileStmt(SourceLocation WhileLoc,
+ FullExprArg Cond, DeclPtrTy CondVar,
+ StmtArg Body) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+ virtual OwningStmtResult ActOnDoStmt(SourceLocation DoLoc, StmtArg Body,
+ SourceLocation WhileLoc,
+ SourceLocation LPLoc, ExprArg Cond,
+ SourceLocation RPLoc){
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+ virtual OwningStmtResult ActOnForStmt(SourceLocation ForLoc,
+ SourceLocation LParenLoc,
+ StmtArg First, FullExprArg Second,
+ DeclPtrTy SecondVar,
+ FullExprArg Third,
+ SourceLocation RParenLoc,
+ StmtArg Body) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+ virtual OwningStmtResult ActOnObjCForCollectionStmt(
+ SourceLocation ForColLoc,
+ SourceLocation LParenLoc,
+ StmtArg First, ExprArg Second,
+ SourceLocation RParenLoc, StmtArg Body) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+ virtual OwningStmtResult ActOnGotoStmt(SourceLocation GotoLoc,
+ SourceLocation LabelLoc,
+ IdentifierInfo *LabelII) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+ virtual OwningStmtResult ActOnIndirectGotoStmt(SourceLocation GotoLoc,
+ SourceLocation StarLoc,
+ ExprArg DestExp) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+ virtual OwningStmtResult ActOnContinueStmt(SourceLocation ContinueLoc,
+ Scope *CurScope) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+ virtual OwningStmtResult ActOnBreakStmt(SourceLocation GotoLoc,
+ Scope *CurScope) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+ virtual OwningStmtResult ActOnReturnStmt(SourceLocation ReturnLoc,
+ ExprArg RetValExp) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+ virtual OwningStmtResult ActOnAsmStmt(SourceLocation AsmLoc,
+ bool IsSimple,
+ bool IsVolatile,
+ unsigned NumOutputs,
+ unsigned NumInputs,
+ IdentifierInfo **Names,
+ MultiExprArg Constraints,
+ MultiExprArg Exprs,
+ ExprArg AsmString,
+ MultiExprArg Clobbers,
+ SourceLocation RParenLoc,
+ bool MSAsm) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+
+ // Objective-c statements
+ virtual OwningStmtResult ActOnObjCAtCatchStmt(SourceLocation AtLoc,
+ SourceLocation RParen,
+ DeclPtrTy Parm,
+ StmtArg Body) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+
+ virtual OwningStmtResult ActOnObjCAtFinallyStmt(SourceLocation AtLoc,
+ StmtArg Body) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+
+ virtual OwningStmtResult ActOnObjCAtTryStmt(SourceLocation AtLoc,
+ StmtArg Try,
+ MultiStmtArg CatchStmts,
+ StmtArg Finally) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+
+ virtual OwningStmtResult ActOnObjCAtThrowStmt(SourceLocation AtLoc,
+ ExprArg Throw,
+ Scope *CurScope) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+
+ virtual OwningStmtResult ActOnObjCAtSynchronizedStmt(SourceLocation AtLoc,
+ ExprArg SynchExpr,
+ StmtArg SynchBody) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+
+ // C++ Statements
+ virtual DeclPtrTy ActOnExceptionDeclarator(Scope *S, Declarator &D) {
+ Out << __FUNCTION__ << "\n";
+ return DeclPtrTy();
+ }
+
+ virtual OwningStmtResult ActOnCXXCatchBlock(SourceLocation CatchLoc,
+ DeclPtrTy ExceptionDecl,
+ StmtArg HandlerBlock) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+
+ virtual OwningStmtResult ActOnCXXTryBlock(SourceLocation TryLoc,
+ StmtArg TryBlock,
+ MultiStmtArg Handlers) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+
+ //===------------------------------------------------------------------===//
+ // Expression Parsing Callbacks.
+ //===------------------------------------------------------------------===//
+
+ // Primary Expressions.
+
+ /// ActOnIdentifierExpr - Parse an identifier in expression context.
+ /// 'HasTrailingLParen' indicates whether or not the identifier has a '('
+ /// token immediately after it.
+ virtual OwningExprResult ActOnIdentifierExpr(Scope *S, SourceLocation Loc,
+ IdentifierInfo &II,
+ bool HasTrailingLParen,
+ const CXXScopeSpec *SS,
+ bool isAddressOfOperand) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnCXXOperatorFunctionIdExpr(
+ Scope *S, SourceLocation OperatorLoc,
+ OverloadedOperatorKind Op,
+ bool HasTrailingLParen, const CXXScopeSpec &SS,
+ bool isAddressOfOperand) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnCXXConversionFunctionExpr(
+ Scope *S, SourceLocation OperatorLoc,
+ TypeTy *Type, bool HasTrailingLParen,
+ const CXXScopeSpec &SS,bool isAddressOfOperand) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnPredefinedExpr(SourceLocation Loc,
+ tok::TokenKind Kind) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnCharacterConstant(const Token &) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnNumericConstant(const Token &) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ /// ActOnStringLiteral - The specified tokens were lexed as pasted string
+ /// fragments (e.g. "foo" "bar" L"baz").
+ virtual OwningExprResult ActOnStringLiteral(const Token *Toks,
+ unsigned NumToks) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnParenExpr(SourceLocation L, SourceLocation R,
+ ExprArg Val) {
+ Out << __FUNCTION__ << "\n";
+ return move(Val); // Default impl returns operand.
+ }
+
+ // Postfix Expressions.
+ virtual OwningExprResult ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc,
+ tok::TokenKind Kind,
+ ExprArg Input) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+ virtual OwningExprResult ActOnArraySubscriptExpr(Scope *S, ExprArg Base,
+ SourceLocation LLoc,
+ ExprArg Idx,
+ SourceLocation RLoc) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+ virtual OwningExprResult ActOnMemberReferenceExpr(Scope *S, ExprArg Base,
+ SourceLocation OpLoc,
+ tok::TokenKind OpKind,
+ SourceLocation MemberLoc,
+ IdentifierInfo &Member,
+ DeclPtrTy ImplDecl,
+ const CXXScopeSpec *SS=0) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnCallExpr(Scope *S, ExprArg Fn,
+ SourceLocation LParenLoc,
+ MultiExprArg Args,
+ SourceLocation *CommaLocs,
+ SourceLocation RParenLoc) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ // Unary Operators. 'Tok' is the token for the operator.
+ virtual OwningExprResult ActOnUnaryOp(Scope *S, SourceLocation OpLoc,
+ tok::TokenKind Op, ExprArg Input) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+ virtual OwningExprResult
+ ActOnSizeOfAlignOfExpr(SourceLocation OpLoc, bool isSizeof, bool isType,
+ void *TyOrEx, const SourceRange &ArgRange) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnCompoundLiteral(SourceLocation LParen,
+ TypeTy *Ty,
+ SourceLocation RParen,
+ ExprArg Op) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+ virtual OwningExprResult ActOnInitList(SourceLocation LParenLoc,
+ MultiExprArg InitList,
+ SourceLocation RParenLoc) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+ virtual OwningExprResult ActOnCastExpr(Scope *S, SourceLocation LParenLoc,
+ TypeTy *Ty, SourceLocation RParenLoc,
+ ExprArg Op) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnBinOp(Scope *S, SourceLocation TokLoc,
+ tok::TokenKind Kind,
+ ExprArg LHS, ExprArg RHS) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ /// ActOnConditionalOp - Parse a ?: operation. Note that 'LHS' may be null
+ /// in the case of a the GNU conditional expr extension.
+ virtual OwningExprResult ActOnConditionalOp(SourceLocation QuestionLoc,
+ SourceLocation ColonLoc,
+ ExprArg Cond, ExprArg LHS,
+ ExprArg RHS) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ //===--------------------- GNU Extension Expressions ------------------===//
+
+ virtual OwningExprResult ActOnAddrLabel(SourceLocation OpLoc,
+ SourceLocation LabLoc,
+ IdentifierInfo *LabelII) {// "&&foo"
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnStmtExpr(SourceLocation LPLoc,
+ StmtArg SubStmt,
+ SourceLocation RPLoc) { // "({..})"
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnBuiltinOffsetOf(Scope *S,
+ SourceLocation BuiltinLoc,
+ SourceLocation TypeLoc,
+ TypeTy *Arg1,
+ OffsetOfComponent *CompPtr,
+ unsigned NumComponents,
+ SourceLocation RParenLoc) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ // __builtin_types_compatible_p(type1, type2)
+ virtual OwningExprResult ActOnTypesCompatibleExpr(SourceLocation BuiltinLoc,
+ TypeTy *arg1,TypeTy *arg2,
+ SourceLocation RPLoc) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+ // __builtin_choose_expr(constExpr, expr1, expr2)
+ virtual OwningExprResult ActOnChooseExpr(SourceLocation BuiltinLoc,
+ ExprArg cond, ExprArg expr1,
+ ExprArg expr2,
+ SourceLocation RPLoc) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ // __builtin_va_arg(expr, type)
+ virtual OwningExprResult ActOnVAArg(SourceLocation BuiltinLoc,
+ ExprArg expr, TypeTy *type,
+ SourceLocation RPLoc) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnGNUNullExpr(SourceLocation TokenLoc) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual void ActOnBlockStart(SourceLocation CaretLoc, Scope *CurScope) {
+ Out << __FUNCTION__ << "\n";
+ }
+
+ virtual void ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) {
+ Out << __FUNCTION__ << "\n";
+ }
+
+ virtual void ActOnBlockError(SourceLocation CaretLoc, Scope *CurScope) {
+ Out << __FUNCTION__ << "\n";
+ }
+
+ virtual OwningExprResult ActOnBlockStmtExpr(SourceLocation CaretLoc,
+ StmtArg Body,
+ Scope *CurScope) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual DeclPtrTy ActOnStartNamespaceDef(Scope *S, SourceLocation IdentLoc,
+ IdentifierInfo *Ident,
+ SourceLocation LBrace,
+ AttributeList *AttrList) {
+ Out << __FUNCTION__ << "\n";
+ return DeclPtrTy();
+ }
+
+ virtual void ActOnFinishNamespaceDef(DeclPtrTy Dcl, SourceLocation RBrace) {
+ Out << __FUNCTION__ << "\n";
+ return;
+ }
+
+#if 0
+ // FIXME: AttrList should be deleted by this function, but the definition
+ // would have to be available.
+ virtual DeclPtrTy ActOnUsingDirective(Scope *CurScope,
+ SourceLocation UsingLoc,
+ SourceLocation NamespcLoc,
+ const CXXScopeSpec &SS,
+ SourceLocation IdentLoc,
+ IdentifierInfo *NamespcName,
+ AttributeList *AttrList) {
+ Out << __FUNCTION__ << "\n";
+ return DeclPtrTy();
+ }
+#endif
+
+ virtual void ActOnParamDefaultArgument(DeclPtrTy param,
+ SourceLocation EqualLoc,
+ ExprArg defarg) {
+ Out << __FUNCTION__ << "\n";
+ }
+
+ virtual void ActOnParamUnparsedDefaultArgument(DeclPtrTy param,
+ SourceLocation EqualLoc,
+ SourceLocation ArgLoc) {
+ Out << __FUNCTION__ << "\n";
+ }
+
+ virtual void ActOnParamDefaultArgumentError(DeclPtrTy param) {
+ Out << __FUNCTION__ << "\n";
+ }
+
+ virtual void AddCXXDirectInitializerToDecl(DeclPtrTy Dcl,
+ SourceLocation LParenLoc,
+ MultiExprArg Exprs,
+ SourceLocation *CommaLocs,
+ SourceLocation RParenLoc) {
+ Out << __FUNCTION__ << "\n";
+ return;
+ }
+
+ virtual void ActOnStartDelayedCXXMethodDeclaration(Scope *S,
+ DeclPtrTy Method) {
+ Out << __FUNCTION__ << "\n";
+ }
+
+ virtual void ActOnDelayedCXXMethodParameter(Scope *S, DeclPtrTy Param) {
+ Out << __FUNCTION__ << "\n";
+ }
+
+ virtual void ActOnFinishDelayedCXXMethodDeclaration(Scope *S,
+ DeclPtrTy Method) {
+ Out << __FUNCTION__ << "\n";
+ }
+
+ virtual DeclPtrTy ActOnStaticAssertDeclaration(SourceLocation AssertLoc,
+ ExprArg AssertExpr,
+ ExprArg AssertMessageExpr) {
+ Out << __FUNCTION__ << "\n";
+ return DeclPtrTy();
+ }
+
+ virtual OwningExprResult ActOnCXXNamedCast(SourceLocation OpLoc,
+ tok::TokenKind Kind,
+ SourceLocation LAngleBracketLoc,
+ TypeTy *Ty,
+ SourceLocation RAngleBracketLoc,
+ SourceLocation LParenLoc,
+ ExprArg Op,
+ SourceLocation RParenLoc) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnCXXTypeid(SourceLocation OpLoc,
+ SourceLocation LParenLoc,
+ bool isType, void *TyOrExpr,
+ SourceLocation RParenLoc) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnCXXThis(SourceLocation ThisLoc) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnCXXBoolLiteral(SourceLocation OpLoc,
+ tok::TokenKind Kind) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnCXXThrow(SourceLocation OpLoc, ExprArg Op) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnCXXTypeConstructExpr(SourceRange TypeRange,
+ TypeTy *TypeRep,
+ SourceLocation LParenLoc,
+ MultiExprArg Exprs,
+ SourceLocation *CommaLocs,
+ SourceLocation RParenLoc) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnCXXConditionDeclarationExpr(Scope *S,
+ SourceLocation StartLoc,
+ Declarator &D,
+ SourceLocation EqualLoc,
+ ExprArg AssignExprVal) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnCXXNew(SourceLocation StartLoc,
+ bool UseGlobal,
+ SourceLocation PlacementLParen,
+ MultiExprArg PlacementArgs,
+ SourceLocation PlacementRParen,
+ SourceRange TypeIdParens,
+ Declarator &D,
+ SourceLocation ConstructorLParen,
+ MultiExprArg ConstructorArgs,
+ SourceLocation ConstructorRParen) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnCXXDelete(SourceLocation StartLoc,
+ bool UseGlobal, bool ArrayForm,
+ ExprArg Operand) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnUnaryTypeTrait(UnaryTypeTrait OTT,
+ SourceLocation KWLoc,
+ SourceLocation LParen,
+ TypeTy *Ty,
+ SourceLocation RParen) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+ };
+}
+
+MinimalAction *clang::CreatePrintParserActionsAction(Preprocessor &PP,
+ llvm::raw_ostream* OS) {
+ return new ParserPrintActions(PP, *OS);
+}
diff --git a/contrib/llvm/tools/clang/lib/Frontend/PrintPreprocessedOutput.cpp b/contrib/llvm/tools/clang/lib/Frontend/PrintPreprocessedOutput.cpp
new file mode 100644
index 0000000..73bca9a
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Frontend/PrintPreprocessedOutput.cpp
@@ -0,0 +1,543 @@
+//===--- PrintPreprocessedOutput.cpp - Implement the -E mode --------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This code simply runs the preprocessor on the input file and prints out the
+// result. This is the traditional behavior of the -E option.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/Utils.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Frontend/PreprocessorOutputOptions.h"
+#include "clang/Lex/MacroInfo.h"
+#include "clang/Lex/PPCallbacks.h"
+#include "clang/Lex/Pragma.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/TokenConcatenation.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Config/config.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cstdio>
+using namespace clang;
+
+/// PrintMacroDefinition - Print a macro definition in a form that will be
+/// properly accepted back as a definition.
+static void PrintMacroDefinition(const IdentifierInfo &II, const MacroInfo &MI,
+ Preprocessor &PP, llvm::raw_ostream &OS) {
+ OS << "#define " << II.getName();
+
+ if (MI.isFunctionLike()) {
+ OS << '(';
+ if (!MI.arg_empty()) {
+ MacroInfo::arg_iterator AI = MI.arg_begin(), E = MI.arg_end();
+ for (; AI+1 != E; ++AI) {
+ OS << (*AI)->getName();
+ OS << ',';
+ }
+
+ // Last argument.
+ if ((*AI)->getName() == "__VA_ARGS__")
+ OS << "...";
+ else
+ OS << (*AI)->getName();
+ }
+
+ if (MI.isGNUVarargs())
+ OS << "..."; // #define foo(x...)
+
+ OS << ')';
+ }
+
+ // GCC always emits a space, even if the macro body is empty. However, do not
+ // want to emit two spaces if the first token has a leading space.
+ if (MI.tokens_empty() || !MI.tokens_begin()->hasLeadingSpace())
+ OS << ' ';
+
+ llvm::SmallString<128> SpellingBuffer;
+ for (MacroInfo::tokens_iterator I = MI.tokens_begin(), E = MI.tokens_end();
+ I != E; ++I) {
+ if (I->hasLeadingSpace())
+ OS << ' ';
+
+ OS << PP.getSpelling(*I, SpellingBuffer);
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// Preprocessed token printer
+//===----------------------------------------------------------------------===//
+
+namespace {
+class PrintPPOutputPPCallbacks : public PPCallbacks {
+ Preprocessor &PP;
+ SourceManager &SM;
+ TokenConcatenation ConcatInfo;
+public:
+ llvm::raw_ostream &OS;
+private:
+ unsigned CurLine;
+ bool EmittedTokensOnThisLine;
+ bool EmittedMacroOnThisLine;
+ SrcMgr::CharacteristicKind FileType;
+ llvm::SmallString<512> CurFilename;
+ bool Initialized;
+ bool DisableLineMarkers;
+ bool DumpDefines;
+ bool UseLineDirective;
+public:
+ PrintPPOutputPPCallbacks(Preprocessor &pp, llvm::raw_ostream &os,
+ bool lineMarkers, bool defines)
+ : PP(pp), SM(PP.getSourceManager()),
+ ConcatInfo(PP), OS(os), DisableLineMarkers(lineMarkers),
+ DumpDefines(defines) {
+ CurLine = 0;
+ CurFilename += "<uninit>";
+ EmittedTokensOnThisLine = false;
+ EmittedMacroOnThisLine = false;
+ FileType = SrcMgr::C_User;
+ Initialized = false;
+
+ // If we're in microsoft mode, use normal #line instead of line markers.
+ UseLineDirective = PP.getLangOptions().Microsoft;
+ }
+
+ void SetEmittedTokensOnThisLine() { EmittedTokensOnThisLine = true; }
+ bool hasEmittedTokensOnThisLine() const { return EmittedTokensOnThisLine; }
+
+ virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason,
+ SrcMgr::CharacteristicKind FileType);
+ virtual void Ident(SourceLocation Loc, const std::string &str);
+ virtual void PragmaComment(SourceLocation Loc, const IdentifierInfo *Kind,
+ const std::string &Str);
+ virtual void PragmaMessage(SourceLocation Loc, llvm::StringRef Str);
+
+ bool HandleFirstTokOnLine(Token &Tok);
+ bool MoveToLine(SourceLocation Loc) {
+ return MoveToLine(SM.getPresumedLoc(Loc).getLine());
+ }
+ bool MoveToLine(unsigned LineNo);
+
+ bool AvoidConcat(const Token &PrevPrevTok, const Token &PrevTok,
+ const Token &Tok) {
+ return ConcatInfo.AvoidConcat(PrevPrevTok, PrevTok, Tok);
+ }
+ void WriteLineInfo(unsigned LineNo, const char *Extra=0, unsigned ExtraLen=0);
+
+ void HandleNewlinesInToken(const char *TokStr, unsigned Len);
+
+ /// MacroDefined - This hook is called whenever a macro definition is seen.
+ void MacroDefined(const IdentifierInfo *II, const MacroInfo *MI);
+
+};
+} // end anonymous namespace
+
+void PrintPPOutputPPCallbacks::WriteLineInfo(unsigned LineNo,
+ const char *Extra,
+ unsigned ExtraLen) {
+ if (EmittedTokensOnThisLine || EmittedMacroOnThisLine) {
+ OS << '\n';
+ EmittedTokensOnThisLine = false;
+ EmittedMacroOnThisLine = false;
+ }
+
+ // Emit #line directives or GNU line markers depending on what mode we're in.
+ if (UseLineDirective) {
+ OS << "#line" << ' ' << LineNo << ' ' << '"';
+ OS.write(&CurFilename[0], CurFilename.size());
+ OS << '"';
+ } else {
+ OS << '#' << ' ' << LineNo << ' ' << '"';
+ OS.write(&CurFilename[0], CurFilename.size());
+ OS << '"';
+
+ if (ExtraLen)
+ OS.write(Extra, ExtraLen);
+
+ if (FileType == SrcMgr::C_System)
+ OS.write(" 3", 2);
+ else if (FileType == SrcMgr::C_ExternCSystem)
+ OS.write(" 3 4", 4);
+ }
+ OS << '\n';
+}
+
+/// MoveToLine - Move the output to the source line specified by the location
+/// object. We can do this by emitting some number of \n's, or be emitting a
+/// #line directive. This returns false if already at the specified line, true
+/// if some newlines were emitted.
+bool PrintPPOutputPPCallbacks::MoveToLine(unsigned LineNo) {
+ // If this line is "close enough" to the original line, just print newlines,
+ // otherwise print a #line directive.
+ if (LineNo-CurLine <= 8) {
+ if (LineNo-CurLine == 1)
+ OS << '\n';
+ else if (LineNo == CurLine)
+ return false; // Spelling line moved, but instantiation line didn't.
+ else {
+ const char *NewLines = "\n\n\n\n\n\n\n\n";
+ OS.write(NewLines, LineNo-CurLine);
+ }
+ } else if (!DisableLineMarkers) {
+ // Emit a #line or line marker.
+ WriteLineInfo(LineNo, 0, 0);
+ } else {
+ // Okay, we're in -P mode, which turns off line markers. However, we still
+ // need to emit a newline between tokens on different lines.
+ if (EmittedTokensOnThisLine || EmittedMacroOnThisLine) {
+ OS << '\n';
+ EmittedTokensOnThisLine = false;
+ EmittedMacroOnThisLine = false;
+ }
+ }
+
+ CurLine = LineNo;
+ return true;
+}
+
+
+/// FileChanged - Whenever the preprocessor enters or exits a #include file
+/// it invokes this handler. Update our conception of the current source
+/// position.
+void PrintPPOutputPPCallbacks::FileChanged(SourceLocation Loc,
+ FileChangeReason Reason,
+ SrcMgr::CharacteristicKind NewFileType) {
+ // Unless we are exiting a #include, make sure to skip ahead to the line the
+ // #include directive was at.
+ SourceManager &SourceMgr = SM;
+
+ PresumedLoc UserLoc = SourceMgr.getPresumedLoc(Loc);
+ unsigned NewLine = UserLoc.getLine();
+
+ if (Reason == PPCallbacks::EnterFile) {
+ SourceLocation IncludeLoc = SourceMgr.getPresumedLoc(Loc).getIncludeLoc();
+ if (IncludeLoc.isValid())
+ MoveToLine(IncludeLoc);
+ } else if (Reason == PPCallbacks::SystemHeaderPragma) {
+ MoveToLine(NewLine);
+
+ // TODO GCC emits the # directive for this directive on the line AFTER the
+ // directive and emits a bunch of spaces that aren't needed. Emulate this
+ // strange behavior.
+ }
+
+ CurLine = NewLine;
+
+ if (DisableLineMarkers) return;
+
+ CurFilename.clear();
+ CurFilename += UserLoc.getFilename();
+ Lexer::Stringify(CurFilename);
+ FileType = NewFileType;
+
+ if (!Initialized) {
+ WriteLineInfo(CurLine);
+ Initialized = true;
+ }
+
+ switch (Reason) {
+ case PPCallbacks::EnterFile:
+ WriteLineInfo(CurLine, " 1", 2);
+ break;
+ case PPCallbacks::ExitFile:
+ WriteLineInfo(CurLine, " 2", 2);
+ break;
+ case PPCallbacks::SystemHeaderPragma:
+ case PPCallbacks::RenameFile:
+ WriteLineInfo(CurLine);
+ break;
+ }
+}
+
+/// Ident - Handle #ident directives when read by the preprocessor.
+///
+void PrintPPOutputPPCallbacks::Ident(SourceLocation Loc, const std::string &S) {
+ MoveToLine(Loc);
+
+ OS.write("#ident ", strlen("#ident "));
+ OS.write(&S[0], S.size());
+ EmittedTokensOnThisLine = true;
+}
+
+/// MacroDefined - This hook is called whenever a macro definition is seen.
+void PrintPPOutputPPCallbacks::MacroDefined(const IdentifierInfo *II,
+ const MacroInfo *MI) {
+ // Only print out macro definitions in -dD mode.
+ if (!DumpDefines ||
+ // Ignore __FILE__ etc.
+ MI->isBuiltinMacro()) return;
+
+ MoveToLine(MI->getDefinitionLoc());
+ PrintMacroDefinition(*II, *MI, PP, OS);
+ EmittedMacroOnThisLine = true;
+}
+
+
+void PrintPPOutputPPCallbacks::PragmaComment(SourceLocation Loc,
+ const IdentifierInfo *Kind,
+ const std::string &Str) {
+ MoveToLine(Loc);
+ OS << "#pragma comment(" << Kind->getName();
+
+ if (!Str.empty()) {
+ OS << ", \"";
+
+ for (unsigned i = 0, e = Str.size(); i != e; ++i) {
+ unsigned char Char = Str[i];
+ if (isprint(Char) && Char != '\\' && Char != '"')
+ OS << (char)Char;
+ else // Output anything hard as an octal escape.
+ OS << '\\'
+ << (char)('0'+ ((Char >> 6) & 7))
+ << (char)('0'+ ((Char >> 3) & 7))
+ << (char)('0'+ ((Char >> 0) & 7));
+ }
+ OS << '"';
+ }
+
+ OS << ')';
+ EmittedTokensOnThisLine = true;
+}
+
+void PrintPPOutputPPCallbacks::PragmaMessage(SourceLocation Loc,
+ llvm::StringRef Str) {
+ MoveToLine(Loc);
+ OS << "#pragma message(";
+
+ OS << '"';
+
+ for (unsigned i = 0, e = Str.size(); i != e; ++i) {
+ unsigned char Char = Str[i];
+ if (isprint(Char) && Char != '\\' && Char != '"')
+ OS << (char)Char;
+ else // Output anything hard as an octal escape.
+ OS << '\\'
+ << (char)('0'+ ((Char >> 6) & 7))
+ << (char)('0'+ ((Char >> 3) & 7))
+ << (char)('0'+ ((Char >> 0) & 7));
+ }
+ OS << '"';
+
+ OS << ')';
+ EmittedTokensOnThisLine = true;
+}
+
+
+/// HandleFirstTokOnLine - When emitting a preprocessed file in -E mode, this
+/// is called for the first token on each new line. If this really is the start
+/// of a new logical line, handle it and return true, otherwise return false.
+/// This may not be the start of a logical line because the "start of line"
+/// marker is set for spelling lines, not instantiation ones.
+bool PrintPPOutputPPCallbacks::HandleFirstTokOnLine(Token &Tok) {
+ // Figure out what line we went to and insert the appropriate number of
+ // newline characters.
+ if (!MoveToLine(Tok.getLocation()))
+ return false;
+
+ // Print out space characters so that the first token on a line is
+ // indented for easy reading.
+ unsigned ColNo = SM.getInstantiationColumnNumber(Tok.getLocation());
+
+ // This hack prevents stuff like:
+ // #define HASH #
+ // HASH define foo bar
+ // From having the # character end up at column 1, which makes it so it
+ // is not handled as a #define next time through the preprocessor if in
+ // -fpreprocessed mode.
+ if (ColNo <= 1 && Tok.is(tok::hash))
+ OS << ' ';
+
+ // Otherwise, indent the appropriate number of spaces.
+ for (; ColNo > 1; --ColNo)
+ OS << ' ';
+
+ return true;
+}
+
+void PrintPPOutputPPCallbacks::HandleNewlinesInToken(const char *TokStr,
+ unsigned Len) {
+ unsigned NumNewlines = 0;
+ for (; Len; --Len, ++TokStr) {
+ if (*TokStr != '\n' &&
+ *TokStr != '\r')
+ continue;
+
+ ++NumNewlines;
+
+ // If we have \n\r or \r\n, skip both and count as one line.
+ if (Len != 1 &&
+ (TokStr[1] == '\n' || TokStr[1] == '\r') &&
+ TokStr[0] != TokStr[1])
+ ++TokStr, --Len;
+ }
+
+ if (NumNewlines == 0) return;
+
+ CurLine += NumNewlines;
+}
+
+
+namespace {
+struct UnknownPragmaHandler : public PragmaHandler {
+ const char *Prefix;
+ PrintPPOutputPPCallbacks *Callbacks;
+
+ UnknownPragmaHandler(const char *prefix, PrintPPOutputPPCallbacks *callbacks)
+ : Prefix(prefix), Callbacks(callbacks) {}
+ virtual void HandlePragma(Preprocessor &PP, Token &PragmaTok) {
+ // Figure out what line we went to and insert the appropriate number of
+ // newline characters.
+ Callbacks->MoveToLine(PragmaTok.getLocation());
+ Callbacks->OS.write(Prefix, strlen(Prefix));
+
+ // Read and print all of the pragma tokens.
+ while (PragmaTok.isNot(tok::eom)) {
+ if (PragmaTok.hasLeadingSpace())
+ Callbacks->OS << ' ';
+ std::string TokSpell = PP.getSpelling(PragmaTok);
+ Callbacks->OS.write(&TokSpell[0], TokSpell.size());
+ PP.LexUnexpandedToken(PragmaTok);
+ }
+ Callbacks->OS << '\n';
+ }
+};
+} // end anonymous namespace
+
+
+static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok,
+ PrintPPOutputPPCallbacks *Callbacks,
+ llvm::raw_ostream &OS) {
+ char Buffer[256];
+ Token PrevPrevTok, PrevTok;
+ PrevPrevTok.startToken();
+ PrevTok.startToken();
+ while (1) {
+
+ // If this token is at the start of a line, emit newlines if needed.
+ if (Tok.isAtStartOfLine() && Callbacks->HandleFirstTokOnLine(Tok)) {
+ // done.
+ } else if (Tok.hasLeadingSpace() ||
+ // If we haven't emitted a token on this line yet, PrevTok isn't
+ // useful to look at and no concatenation could happen anyway.
+ (Callbacks->hasEmittedTokensOnThisLine() &&
+ // Don't print "-" next to "-", it would form "--".
+ Callbacks->AvoidConcat(PrevPrevTok, PrevTok, Tok))) {
+ OS << ' ';
+ }
+
+ if (IdentifierInfo *II = Tok.getIdentifierInfo()) {
+ OS << II->getName();
+ } else if (Tok.isLiteral() && !Tok.needsCleaning() &&
+ Tok.getLiteralData()) {
+ OS.write(Tok.getLiteralData(), Tok.getLength());
+ } else if (Tok.getLength() < 256) {
+ const char *TokPtr = Buffer;
+ unsigned Len = PP.getSpelling(Tok, TokPtr);
+ OS.write(TokPtr, Len);
+
+ // Tokens that can contain embedded newlines need to adjust our current
+ // line number.
+ if (Tok.getKind() == tok::comment)
+ Callbacks->HandleNewlinesInToken(TokPtr, Len);
+ } else {
+ std::string S = PP.getSpelling(Tok);
+ OS.write(&S[0], S.size());
+
+ // Tokens that can contain embedded newlines need to adjust our current
+ // line number.
+ if (Tok.getKind() == tok::comment)
+ Callbacks->HandleNewlinesInToken(&S[0], S.size());
+ }
+ Callbacks->SetEmittedTokensOnThisLine();
+
+ if (Tok.is(tok::eof)) break;
+
+ PrevPrevTok = PrevTok;
+ PrevTok = Tok;
+ PP.Lex(Tok);
+ }
+}
+
+typedef std::pair<IdentifierInfo*, MacroInfo*> id_macro_pair;
+static int MacroIDCompare(const void* a, const void* b) {
+ const id_macro_pair *LHS = static_cast<const id_macro_pair*>(a);
+ const id_macro_pair *RHS = static_cast<const id_macro_pair*>(b);
+ return LHS->first->getName().compare(RHS->first->getName());
+}
+
+static void DoPrintMacros(Preprocessor &PP, llvm::raw_ostream *OS) {
+ // Ignore unknown pragmas.
+ PP.AddPragmaHandler(new EmptyPragmaHandler());
+
+ // -dM mode just scans and ignores all tokens in the files, then dumps out
+ // the macro table at the end.
+ PP.EnterMainSourceFile();
+
+ Token Tok;
+ do PP.Lex(Tok);
+ while (Tok.isNot(tok::eof));
+
+ llvm::SmallVector<id_macro_pair, 128>
+ MacrosByID(PP.macro_begin(), PP.macro_end());
+ llvm::array_pod_sort(MacrosByID.begin(), MacrosByID.end(), MacroIDCompare);
+
+ for (unsigned i = 0, e = MacrosByID.size(); i != e; ++i) {
+ MacroInfo &MI = *MacrosByID[i].second;
+ // Ignore computed macros like __LINE__ and friends.
+ if (MI.isBuiltinMacro()) continue;
+
+ PrintMacroDefinition(*MacrosByID[i].first, MI, PP, *OS);
+ *OS << '\n';
+ }
+}
+
+/// DoPrintPreprocessedInput - This implements -E mode.
+///
+void clang::DoPrintPreprocessedInput(Preprocessor &PP, llvm::raw_ostream *OS,
+ const PreprocessorOutputOptions &Opts) {
+ // Show macros with no output is handled specially.
+ if (!Opts.ShowCPP) {
+ assert(Opts.ShowMacros && "Not yet implemented!");
+ DoPrintMacros(PP, OS);
+ return;
+ }
+
+ // Inform the preprocessor whether we want it to retain comments or not, due
+ // to -C or -CC.
+ PP.SetCommentRetentionState(Opts.ShowComments, Opts.ShowMacroComments);
+
+ PrintPPOutputPPCallbacks *Callbacks =
+ new PrintPPOutputPPCallbacks(PP, *OS, !Opts.ShowLineMarkers,
+ Opts.ShowMacros);
+ PP.AddPragmaHandler(new UnknownPragmaHandler("#pragma", Callbacks));
+ PP.AddPragmaHandler("GCC", new UnknownPragmaHandler("#pragma GCC",
+ Callbacks));
+
+ PP.addPPCallbacks(Callbacks);
+
+ // After we have configured the preprocessor, enter the main file.
+ PP.EnterMainSourceFile();
+
+ // Consume all of the tokens that come from the predefines buffer. Those
+ // should not be emitted into the output and are guaranteed to be at the
+ // start.
+ const SourceManager &SourceMgr = PP.getSourceManager();
+ Token Tok;
+ do PP.Lex(Tok);
+ while (Tok.isNot(tok::eof) && Tok.getLocation().isFileID() &&
+ !strcmp(SourceMgr.getPresumedLoc(Tok.getLocation()).getFilename(),
+ "<built-in>"));
+
+ // Read all the preprocessed tokens, printing them out to the stream.
+ PrintPreprocessedTokens(PP, Tok, Callbacks, *OS);
+ *OS << '\n';
+}
+
diff --git a/contrib/llvm/tools/clang/lib/Frontend/StmtXML.cpp b/contrib/llvm/tools/clang/lib/Frontend/StmtXML.cpp
new file mode 100644
index 0000000..21dc0ba
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Frontend/StmtXML.cpp
@@ -0,0 +1,453 @@
+//===--- StmtXML.cpp - XML implementation for Stmt ASTs ------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the Stmt::dumpXML methods, which dump out the
+// AST to an XML document.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/DocumentXML.h"
+#include "clang/AST/StmtVisitor.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/Basic/SourceManager.h"
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// StmtXML Visitor
+//===----------------------------------------------------------------------===//
+
+namespace {
+ class StmtXML : public StmtVisitor<StmtXML> {
+ DocumentXML& Doc;
+
+ //static const char *getOpcodeStr(UnaryOperator::Opcode Op);
+ //static const char *getOpcodeStr(BinaryOperator::Opcode Op);
+
+
+ void addSpecialAttribute(const char* pName, StringLiteral* Str) {
+ Doc.addAttribute(pName, Doc.escapeString(Str->getStrData(), Str->getByteLength()));
+ }
+
+ void addSpecialAttribute(const char* pName, SizeOfAlignOfExpr* S) {
+ if (S->isArgumentType())
+ Doc.addAttribute(pName, S->getArgumentType());
+ }
+
+ void addSpecialAttribute(const char* pName, CXXTypeidExpr* S) {
+ if (S->isTypeOperand())
+ Doc.addAttribute(pName, S->getTypeOperand());
+ }
+
+
+ public:
+ StmtXML(DocumentXML& doc)
+ : Doc(doc) {
+ }
+
+ void DumpSubTree(Stmt *S) {
+ if (S) {
+ Visit(S);
+ if (DeclStmt* DS = dyn_cast<DeclStmt>(S)) {
+ for (DeclStmt::decl_iterator DI = DS->decl_begin(),
+ DE = DS->decl_end(); DI != DE; ++DI) {
+ Doc.PrintDecl(*DI);
+ }
+ } else {
+ for (Stmt::child_iterator i = S->child_begin(), e = S->child_end();
+ i != e; ++i)
+ DumpSubTree(*i);
+ }
+ Doc.toParent();
+ } else {
+ Doc.addSubNode("NULL").toParent();
+ }
+ }
+
+
+#define NODE_XML( CLASS, NAME ) \
+ void Visit##CLASS(CLASS* S) \
+ { \
+ typedef CLASS tStmtType; \
+ Doc.addSubNode(NAME);
+
+#define ATTRIBUTE_XML( FN, NAME ) Doc.addAttribute(NAME, S->FN);
+#define TYPE_ATTRIBUTE_XML( FN ) ATTRIBUTE_XML(FN, "type")
+#define ATTRIBUTE_OPT_XML( FN, NAME ) Doc.addAttributeOptional(NAME, S->FN);
+#define ATTRIBUTE_SPECIAL_XML( FN, NAME ) addSpecialAttribute(NAME, S);
+#define ATTRIBUTE_FILE_LOCATION_XML Doc.addLocationRange(S->getSourceRange());
+
+
+#define ATTRIBUTE_ENUM_XML( FN, NAME ) \
+ { \
+ const char* pAttributeName = NAME; \
+ const bool optional = false; \
+ switch (S->FN) { \
+ default: assert(0 && "unknown enum value");
+
+#define ATTRIBUTE_ENUM_OPT_XML( FN, NAME ) \
+ { \
+ const char* pAttributeName = NAME; \
+ const bool optional = true; \
+ switch (S->FN) { \
+ default: assert(0 && "unknown enum value");
+
+#define ENUM_XML( VALUE, NAME ) case VALUE: if ((!optional) || NAME[0]) Doc.addAttribute(pAttributeName, NAME); break;
+#define END_ENUM_XML } }
+#define END_NODE_XML }
+
+#define ID_ATTRIBUTE_XML Doc.addAttribute("id", S);
+#define SUB_NODE_XML( CLASS )
+#define SUB_NODE_SEQUENCE_XML( CLASS )
+#define SUB_NODE_OPT_XML( CLASS )
+
+#include "clang/Frontend/StmtXML.def"
+
+#if (0)
+ // Stmts.
+ void VisitStmt(Stmt *Node);
+ void VisitDeclStmt(DeclStmt *Node);
+ void VisitLabelStmt(LabelStmt *Node);
+ void VisitGotoStmt(GotoStmt *Node);
+
+ // Exprs
+ void VisitExpr(Expr *Node);
+ void VisitDeclRefExpr(DeclRefExpr *Node);
+ void VisitPredefinedExpr(PredefinedExpr *Node);
+ void VisitCharacterLiteral(CharacterLiteral *Node);
+ void VisitIntegerLiteral(IntegerLiteral *Node);
+ void VisitFloatingLiteral(FloatingLiteral *Node);
+ void VisitStringLiteral(StringLiteral *Str);
+ void VisitUnaryOperator(UnaryOperator *Node);
+ void VisitOffsetOfExpr(OffsetOfExpr *Node);
+ void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node);
+ void VisitMemberExpr(MemberExpr *Node);
+ void VisitExtVectorElementExpr(ExtVectorElementExpr *Node);
+ void VisitBinaryOperator(BinaryOperator *Node);
+ void VisitCompoundAssignOperator(CompoundAssignOperator *Node);
+ void VisitAddrLabelExpr(AddrLabelExpr *Node);
+ void VisitTypesCompatibleExpr(TypesCompatibleExpr *Node);
+
+ // C++
+ void VisitCXXNamedCastExpr(CXXNamedCastExpr *Node);
+ void VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node);
+ void VisitCXXThisExpr(CXXThisExpr *Node);
+ void VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *Node);
+
+ // ObjC
+ void VisitObjCEncodeExpr(ObjCEncodeExpr *Node);
+ void VisitObjCMessageExpr(ObjCMessageExpr* Node);
+ void VisitObjCSelectorExpr(ObjCSelectorExpr *Node);
+ void VisitObjCProtocolExpr(ObjCProtocolExpr *Node);
+ void VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node);
+ void VisitObjCImplicitSetterGetterRefExpr(
+ ObjCImplicitSetterGetterRefExpr *Node);
+ void VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node);
+ void VisitObjCSuperExpr(ObjCSuperExpr *Node);
+#endif
+ };
+}
+
+//===----------------------------------------------------------------------===//
+// Stmt printing methods.
+//===----------------------------------------------------------------------===//
+#if (0)
+void StmtXML::VisitStmt(Stmt *Node) {
+ // nothing special to do
+}
+
+void StmtXML::VisitDeclStmt(DeclStmt *Node) {
+ for (DeclStmt::decl_iterator DI = Node->decl_begin(), DE = Node->decl_end();
+ DI != DE; ++DI) {
+ Doc.PrintDecl(*DI);
+ }
+}
+
+void StmtXML::VisitLabelStmt(LabelStmt *Node) {
+ Doc.addAttribute("name", Node->getName());
+}
+
+void StmtXML::VisitGotoStmt(GotoStmt *Node) {
+ Doc.addAttribute("name", Node->getLabel()->getName());
+}
+
+//===----------------------------------------------------------------------===//
+// Expr printing methods.
+//===----------------------------------------------------------------------===//
+
+void StmtXML::VisitExpr(Expr *Node) {
+ DumpExpr(Node);
+}
+
+void StmtXML::VisitDeclRefExpr(DeclRefExpr *Node) {
+ DumpExpr(Node);
+
+ const char* pKind;
+ switch (Node->getDecl()->getKind()) {
+ case Decl::Function: pKind = "FunctionDecl"; break;
+ case Decl::Var: pKind = "Var"; break;
+ case Decl::ParmVar: pKind = "ParmVar"; break;
+ case Decl::EnumConstant: pKind = "EnumConstant"; break;
+ case Decl::Typedef: pKind = "Typedef"; break;
+ case Decl::Record: pKind = "Record"; break;
+ case Decl::Enum: pKind = "Enum"; break;
+ case Decl::CXXRecord: pKind = "CXXRecord"; break;
+ case Decl::ObjCInterface: pKind = "ObjCInterface"; break;
+ case Decl::ObjCClass: pKind = "ObjCClass"; break;
+ default: pKind = "Decl"; break;
+ }
+
+ Doc.addAttribute("kind", pKind);
+ Doc.addAttribute("name", Node->getDecl()->getNameAsString());
+ Doc.addRefAttribute(Node->getDecl());
+}
+
+void StmtXML::VisitPredefinedExpr(PredefinedExpr *Node) {
+ DumpExpr(Node);
+ switch (Node->getIdentType()) {
+ default: assert(0 && "unknown case");
+ case PredefinedExpr::Func: Doc.addAttribute("predefined", " __func__"); break;
+ case PredefinedExpr::Function: Doc.addAttribute("predefined", " __FUNCTION__"); break;
+ case PredefinedExpr::PrettyFunction: Doc.addAttribute("predefined", " __PRETTY_FUNCTION__");break;
+ }
+}
+
+void StmtXML::VisitCharacterLiteral(CharacterLiteral *Node) {
+ DumpExpr(Node);
+ Doc.addAttribute("value", Node->getValue());
+}
+
+void StmtXML::VisitIntegerLiteral(IntegerLiteral *Node) {
+ DumpExpr(Node);
+ bool isSigned = Node->getType()->isSignedIntegerType();
+ Doc.addAttribute("value", Node->getValue().toString(10, isSigned));
+}
+
+void StmtXML::VisitFloatingLiteral(FloatingLiteral *Node) {
+ DumpExpr(Node);
+ // FIXME: output float as written in source (no approximation or the like)
+ //Doc.addAttribute("value", Node->getValueAsApproximateDouble()));
+ Doc.addAttribute("value", "FIXME");
+}
+
+void StmtXML::VisitStringLiteral(StringLiteral *Str) {
+ DumpExpr(Str);
+ if (Str->isWide())
+ Doc.addAttribute("is_wide", "1");
+
+ Doc.addAttribute("value", Doc.escapeString(Str->getStrData(), Str->getByteLength()));
+}
+
+
+const char *StmtXML::getOpcodeStr(UnaryOperator::Opcode Op) {
+ switch (Op) {
+ default: assert(0 && "Unknown unary operator");
+ case UnaryOperator::PostInc: return "postinc";
+ case UnaryOperator::PostDec: return "postdec";
+ case UnaryOperator::PreInc: return "preinc";
+ case UnaryOperator::PreDec: return "predec";
+ case UnaryOperator::AddrOf: return "addrof";
+ case UnaryOperator::Deref: return "deref";
+ case UnaryOperator::Plus: return "plus";
+ case UnaryOperator::Minus: return "minus";
+ case UnaryOperator::Not: return "not";
+ case UnaryOperator::LNot: return "lnot";
+ case UnaryOperator::Real: return "__real";
+ case UnaryOperator::Imag: return "__imag";
+ case UnaryOperator::Extension: return "__extension__";
+ case UnaryOperator::OffsetOf: return "__builtin_offsetof";
+ }
+}
+
+
+const char *StmtXML::getOpcodeStr(BinaryOperator::Opcode Op) {
+ switch (Op) {
+ default: assert(0 && "Unknown binary operator");
+ case BinaryOperator::PtrMemD: return "ptrmemd";
+ case BinaryOperator::PtrMemI: return "ptrmemi";
+ case BinaryOperator::Mul: return "mul";
+ case BinaryOperator::Div: return "div";
+ case BinaryOperator::Rem: return "rem";
+ case BinaryOperator::Add: return "add";
+ case BinaryOperator::Sub: return "sub";
+ case BinaryOperator::Shl: return "shl";
+ case BinaryOperator::Shr: return "shr";
+ case BinaryOperator::LT: return "lt";
+ case BinaryOperator::GT: return "gt";
+ case BinaryOperator::LE: return "le";
+ case BinaryOperator::GE: return "ge";
+ case BinaryOperator::EQ: return "eq";
+ case BinaryOperator::NE: return "ne";
+ case BinaryOperator::And: return "and";
+ case BinaryOperator::Xor: return "xor";
+ case BinaryOperator::Or: return "or";
+ case BinaryOperator::LAnd: return "land";
+ case BinaryOperator::LOr: return "lor";
+ case BinaryOperator::Assign: return "assign";
+ case BinaryOperator::MulAssign: return "mulassign";
+ case BinaryOperator::DivAssign: return "divassign";
+ case BinaryOperator::RemAssign: return "remassign";
+ case BinaryOperator::AddAssign: return "addassign";
+ case BinaryOperator::SubAssign: return "subassign";
+ case BinaryOperator::ShlAssign: return "shlassign";
+ case BinaryOperator::ShrAssign: return "shrassign";
+ case BinaryOperator::AndAssign: return "andassign";
+ case BinaryOperator::XorAssign: return "xorassign";
+ case BinaryOperator::OrAssign: return "orassign";
+ case BinaryOperator::Comma: return "comma";
+ }
+}
+
+void StmtXML::VisitUnaryOperator(UnaryOperator *Node) {
+ DumpExpr(Node);
+ Doc.addAttribute("op_code", getOpcodeStr(Node->getOpcode()));
+}
+
+void StmtXML::OffsetOfExpr(OffsetOfExpr *Node) {
+ DumpExpr(Node);
+}
+
+void StmtXML::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node) {
+ DumpExpr(Node);
+ Doc.addAttribute("is_sizeof", Node->isSizeOf() ? "sizeof" : "alignof");
+ Doc.addAttribute("is_type", Node->isArgumentType() ? "1" : "0");
+ if (Node->isArgumentType())
+ DumpTypeExpr(Node->getArgumentType());
+}
+
+void StmtXML::VisitMemberExpr(MemberExpr *Node) {
+ DumpExpr(Node);
+ Doc.addAttribute("is_deref", Node->isArrow() ? "1" : "0");
+ Doc.addAttribute("name", Node->getMemberDecl()->getNameAsString());
+ Doc.addRefAttribute(Node->getMemberDecl());
+}
+
+void StmtXML::VisitExtVectorElementExpr(ExtVectorElementExpr *Node) {
+ DumpExpr(Node);
+ Doc.addAttribute("name", Node->getAccessor().getName());
+}
+
+void StmtXML::VisitBinaryOperator(BinaryOperator *Node) {
+ DumpExpr(Node);
+ Doc.addAttribute("op_code", getOpcodeStr(Node->getOpcode()));
+}
+
+void StmtXML::VisitCompoundAssignOperator(CompoundAssignOperator *Node) {
+ VisitBinaryOperator(Node);
+/* FIXME: is this needed in the AST?
+ DumpExpr(Node);
+ CurrentNode = CurrentNode->addSubNode("ComputeLHSTy");
+ DumpType(Node->getComputationLHSType());
+ CurrentNode = CurrentNode->Parent->addSubNode("ComputeResultTy");
+ DumpType(Node->getComputationResultType());
+ Doc.toParent();
+*/
+}
+
+// GNU extensions.
+
+void StmtXML::VisitAddrLabelExpr(AddrLabelExpr *Node) {
+ DumpExpr(Node);
+ Doc.addAttribute("name", Node->getLabel()->getName());
+}
+
+void StmtXML::VisitTypesCompatibleExpr(TypesCompatibleExpr *Node) {
+ DumpExpr(Node);
+ DumpTypeExpr(Node->getArgType1());
+ DumpTypeExpr(Node->getArgType2());
+}
+
+//===----------------------------------------------------------------------===//
+// C++ Expressions
+//===----------------------------------------------------------------------===//
+
+void StmtXML::VisitCXXNamedCastExpr(CXXNamedCastExpr *Node) {
+ DumpExpr(Node);
+ Doc.addAttribute("kind", Node->getCastName());
+ DumpTypeExpr(Node->getTypeAsWritten());
+}
+
+void StmtXML::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node) {
+ DumpExpr(Node);
+ Doc.addAttribute("value", Node->getValue() ? "true" : "false");
+}
+
+void StmtXML::VisitCXXThisExpr(CXXThisExpr *Node) {
+ DumpExpr(Node);
+}
+
+void StmtXML::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *Node) {
+ DumpExpr(Node);
+ DumpTypeExpr(Node->getTypeAsWritten());
+}
+
+//===----------------------------------------------------------------------===//
+// Obj-C Expressions
+//===----------------------------------------------------------------------===//
+
+void StmtXML::VisitObjCMessageExpr(ObjCMessageExpr* Node) {
+ DumpExpr(Node);
+ Doc.addAttribute("selector", Node->getSelector().getAsString());
+ IdentifierInfo* clsName = Node->getClassName();
+ if (clsName)
+ Doc.addAttribute("class", clsName->getName());
+}
+
+void StmtXML::VisitObjCEncodeExpr(ObjCEncodeExpr *Node) {
+ DumpExpr(Node);
+ DumpTypeExpr(Node->getEncodedType());
+}
+
+void StmtXML::VisitObjCSelectorExpr(ObjCSelectorExpr *Node) {
+ DumpExpr(Node);
+ Doc.addAttribute("selector", Node->getSelector().getAsString());
+}
+
+void StmtXML::VisitObjCProtocolExpr(ObjCProtocolExpr *Node) {
+ DumpExpr(Node);
+ Doc.addAttribute("protocol", Node->getProtocol()->getNameAsString());
+}
+
+void StmtXML::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node) {
+ DumpExpr(Node);
+ Doc.addAttribute("property", Node->getProperty()->getNameAsString());
+}
+
+void StmtXML::VisitObjCImplicitSetterGetterRefExpr(
+ ObjCImplicitSetterGetterRefExpr *Node) {
+ DumpExpr(Node);
+ ObjCMethodDecl *Getter = Node->getGetterMethod();
+ ObjCMethodDecl *Setter = Node->getSetterMethod();
+ Doc.addAttribute("Getter", Getter->getSelector().getAsString());
+ Doc.addAttribute("Setter", Setter ? Setter->getSelector().getAsString().c_str() : "(null)");
+}
+
+void StmtXML::VisitObjCSuperExpr(ObjCSuperExpr *Node) {
+ DumpExpr(Node);
+ Doc.addAttribute("super", "1");
+}
+
+void StmtXML::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) {
+ DumpExpr(Node);
+ Doc.addAttribute("kind", Node->getDecl()->getDeclKindName());
+ Doc.addAttribute("decl", Node->getDecl()->getNameAsString());
+ if (Node->isFreeIvar())
+ Doc.addAttribute("isFreeIvar", "1");
+}
+#endif
+//===----------------------------------------------------------------------===//
+// Stmt method implementations
+//===----------------------------------------------------------------------===//
+
+/// dumpAll - This does a dump of the specified AST fragment and all subtrees.
+void DocumentXML::PrintStmt(const Stmt *S) {
+ StmtXML P(*this);
+ P.DumpSubTree(const_cast<Stmt*>(S));
+}
+
diff --git a/contrib/llvm/tools/clang/lib/Frontend/TextDiagnosticBuffer.cpp b/contrib/llvm/tools/clang/lib/Frontend/TextDiagnosticBuffer.cpp
new file mode 100644
index 0000000..fdf2ec8
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Frontend/TextDiagnosticBuffer.cpp
@@ -0,0 +1,48 @@
+//===--- TextDiagnosticBuffer.cpp - Buffer Text Diagnostics ---------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This is a concrete diagnostic client, which buffers the diagnostic messages.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/TextDiagnosticBuffer.h"
+#include "llvm/ADT/SmallString.h"
+using namespace clang;
+
+/// HandleDiagnostic - Store the errors, warnings, and notes that are
+/// reported.
+///
+void TextDiagnosticBuffer::HandleDiagnostic(Diagnostic::Level Level,
+ const DiagnosticInfo &Info) {
+ llvm::SmallString<100> Buf;
+ Info.FormatDiagnostic(Buf);
+ switch (Level) {
+ default: assert(0 && "Diagnostic not handled during diagnostic buffering!");
+ case Diagnostic::Note:
+ Notes.push_back(std::make_pair(Info.getLocation(), Buf.str()));
+ break;
+ case Diagnostic::Warning:
+ Warnings.push_back(std::make_pair(Info.getLocation(), Buf.str()));
+ break;
+ case Diagnostic::Error:
+ case Diagnostic::Fatal:
+ Errors.push_back(std::make_pair(Info.getLocation(), Buf.str()));
+ break;
+ }
+}
+
+void TextDiagnosticBuffer::FlushDiagnostics(Diagnostic &Diags) const {
+ // FIXME: Flush the diagnostics in order.
+ for (const_iterator it = err_begin(), ie = err_end(); it != ie; ++it)
+ Diags.Report(Diags.getCustomDiagID(Diagnostic::Error, it->second.c_str()));
+ for (const_iterator it = warn_begin(), ie = warn_end(); it != ie; ++it)
+ Diags.Report(Diags.getCustomDiagID(Diagnostic::Warning,it->second.c_str()));
+ for (const_iterator it = note_begin(), ie = note_end(); it != ie; ++it)
+ Diags.Report(Diags.getCustomDiagID(Diagnostic::Note, it->second.c_str()));
+}
diff --git a/contrib/llvm/tools/clang/lib/Frontend/TextDiagnosticPrinter.cpp b/contrib/llvm/tools/clang/lib/Frontend/TextDiagnosticPrinter.cpp
new file mode 100644
index 0000000..1b5b7e2
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Frontend/TextDiagnosticPrinter.cpp
@@ -0,0 +1,957 @@
+//===--- TextDiagnosticPrinter.cpp - Diagnostic Printer -------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This diagnostic client prints out their diagnostic messages.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Frontend/DiagnosticOptions.h"
+#include "clang/Lex/Lexer.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringExtras.h"
+#include <algorithm>
+using namespace clang;
+
+static const enum llvm::raw_ostream::Colors noteColor =
+ llvm::raw_ostream::BLACK;
+static const enum llvm::raw_ostream::Colors fixitColor =
+ llvm::raw_ostream::GREEN;
+static const enum llvm::raw_ostream::Colors caretColor =
+ llvm::raw_ostream::GREEN;
+static const enum llvm::raw_ostream::Colors warningColor =
+ llvm::raw_ostream::MAGENTA;
+static const enum llvm::raw_ostream::Colors errorColor = llvm::raw_ostream::RED;
+static const enum llvm::raw_ostream::Colors fatalColor = llvm::raw_ostream::RED;
+// Used for changing only the bold attribute.
+static const enum llvm::raw_ostream::Colors savedColor =
+ llvm::raw_ostream::SAVEDCOLOR;
+
+/// \brief Number of spaces to indent when word-wrapping.
+const unsigned WordWrapIndentation = 6;
+
+TextDiagnosticPrinter::TextDiagnosticPrinter(llvm::raw_ostream &os,
+ const DiagnosticOptions &diags,
+ bool _OwnsOutputStream)
+ : OS(os), LangOpts(0), DiagOpts(&diags),
+ LastCaretDiagnosticWasNote(0),
+ OwnsOutputStream(_OwnsOutputStream) {
+}
+
+TextDiagnosticPrinter::~TextDiagnosticPrinter() {
+ if (OwnsOutputStream)
+ delete &OS;
+}
+
+void TextDiagnosticPrinter::
+PrintIncludeStack(SourceLocation Loc, const SourceManager &SM) {
+ if (Loc.isInvalid()) return;
+
+ PresumedLoc PLoc = SM.getPresumedLoc(Loc);
+
+ // Print out the other include frames first.
+ PrintIncludeStack(PLoc.getIncludeLoc(), SM);
+
+ if (DiagOpts->ShowLocation)
+ OS << "In file included from " << PLoc.getFilename()
+ << ':' << PLoc.getLine() << ":\n";
+ else
+ OS << "In included file:\n";
+}
+
+/// HighlightRange - Given a SourceRange and a line number, highlight (with ~'s)
+/// any characters in LineNo that intersect the SourceRange.
+void TextDiagnosticPrinter::HighlightRange(const CharSourceRange &R,
+ const SourceManager &SM,
+ unsigned LineNo, FileID FID,
+ std::string &CaretLine,
+ const std::string &SourceLine) {
+ assert(CaretLine.size() == SourceLine.size() &&
+ "Expect a correspondence between source and caret line!");
+ if (!R.isValid()) return;
+
+ SourceLocation Begin = SM.getInstantiationLoc(R.getBegin());
+ SourceLocation End = SM.getInstantiationLoc(R.getEnd());
+
+ // If the End location and the start location are the same and are a macro
+ // location, then the range was something that came from a macro expansion
+ // or _Pragma. If this is an object-like macro, the best we can do is to
+ // highlight the range. If this is a function-like macro, we'd also like to
+ // highlight the arguments.
+ if (Begin == End && R.getEnd().isMacroID())
+ End = SM.getInstantiationRange(R.getEnd()).second;
+
+ unsigned StartLineNo = SM.getInstantiationLineNumber(Begin);
+ if (StartLineNo > LineNo || SM.getFileID(Begin) != FID)
+ return; // No intersection.
+
+ unsigned EndLineNo = SM.getInstantiationLineNumber(End);
+ if (EndLineNo < LineNo || SM.getFileID(End) != FID)
+ return; // No intersection.
+
+ // Compute the column number of the start.
+ unsigned StartColNo = 0;
+ if (StartLineNo == LineNo) {
+ StartColNo = SM.getInstantiationColumnNumber(Begin);
+ if (StartColNo) --StartColNo; // Zero base the col #.
+ }
+
+ // Compute the column number of the end.
+ unsigned EndColNo = CaretLine.size();
+ if (EndLineNo == LineNo) {
+ EndColNo = SM.getInstantiationColumnNumber(End);
+ if (EndColNo) {
+ --EndColNo; // Zero base the col #.
+
+ // Add in the length of the token, so that we cover multi-char tokens if
+ // this is a token range.
+ if (R.isTokenRange())
+ EndColNo += Lexer::MeasureTokenLength(End, SM, *LangOpts);
+ } else {
+ EndColNo = CaretLine.size();
+ }
+ }
+
+ assert(StartColNo <= EndColNo && "Invalid range!");
+
+ // Check that a token range does not highlight only whitespace.
+ if (R.isTokenRange()) {
+ // Pick the first non-whitespace column.
+ while (StartColNo < SourceLine.size() &&
+ (SourceLine[StartColNo] == ' ' || SourceLine[StartColNo] == '\t'))
+ ++StartColNo;
+
+ // Pick the last non-whitespace column.
+ if (EndColNo > SourceLine.size())
+ EndColNo = SourceLine.size();
+ while (EndColNo-1 &&
+ (SourceLine[EndColNo-1] == ' ' || SourceLine[EndColNo-1] == '\t'))
+ --EndColNo;
+
+ // If the start/end passed each other, then we are trying to highlight a range
+ // that just exists in whitespace, which must be some sort of other bug.
+ assert(StartColNo <= EndColNo && "Trying to highlight whitespace??");
+ }
+
+ // Fill the range with ~'s.
+ for (unsigned i = StartColNo; i < EndColNo; ++i)
+ CaretLine[i] = '~';
+}
+
+/// \brief When the source code line we want to print is too long for
+/// the terminal, select the "interesting" region.
+static void SelectInterestingSourceRegion(std::string &SourceLine,
+ std::string &CaretLine,
+ std::string &FixItInsertionLine,
+ unsigned EndOfCaretToken,
+ unsigned Columns) {
+ unsigned MaxSize = std::max(SourceLine.size(),
+ std::max(CaretLine.size(),
+ FixItInsertionLine.size()));
+ if (MaxSize > SourceLine.size())
+ SourceLine.resize(MaxSize, ' ');
+ if (MaxSize > CaretLine.size())
+ CaretLine.resize(MaxSize, ' ');
+ if (!FixItInsertionLine.empty() && MaxSize > FixItInsertionLine.size())
+ FixItInsertionLine.resize(MaxSize, ' ');
+
+ // Find the slice that we need to display the full caret line
+ // correctly.
+ unsigned CaretStart = 0, CaretEnd = CaretLine.size();
+ for (; CaretStart != CaretEnd; ++CaretStart)
+ if (!isspace(CaretLine[CaretStart]))
+ break;
+
+ for (; CaretEnd != CaretStart; --CaretEnd)
+ if (!isspace(CaretLine[CaretEnd - 1]))
+ break;
+
+ // Make sure we don't chop the string shorter than the caret token
+ // itself.
+ if (CaretEnd < EndOfCaretToken)
+ CaretEnd = EndOfCaretToken;
+
+ // If we have a fix-it line, make sure the slice includes all of the
+ // fix-it information.
+ if (!FixItInsertionLine.empty()) {
+ unsigned FixItStart = 0, FixItEnd = FixItInsertionLine.size();
+ for (; FixItStart != FixItEnd; ++FixItStart)
+ if (!isspace(FixItInsertionLine[FixItStart]))
+ break;
+
+ for (; FixItEnd != FixItStart; --FixItEnd)
+ if (!isspace(FixItInsertionLine[FixItEnd - 1]))
+ break;
+
+ if (FixItStart < CaretStart)
+ CaretStart = FixItStart;
+ if (FixItEnd > CaretEnd)
+ CaretEnd = FixItEnd;
+ }
+
+ // CaretLine[CaretStart, CaretEnd) contains all of the interesting
+ // parts of the caret line. While this slice is smaller than the
+ // number of columns we have, try to grow the slice to encompass
+ // more context.
+
+ // If the end of the interesting region comes before we run out of
+ // space in the terminal, start at the beginning of the line.
+ if (Columns > 3 && CaretEnd < Columns - 3)
+ CaretStart = 0;
+
+ unsigned TargetColumns = Columns;
+ if (TargetColumns > 8)
+ TargetColumns -= 8; // Give us extra room for the ellipses.
+ unsigned SourceLength = SourceLine.size();
+ while ((CaretEnd - CaretStart) < TargetColumns) {
+ bool ExpandedRegion = false;
+ // Move the start of the interesting region left until we've
+ // pulled in something else interesting.
+ if (CaretStart == 1)
+ CaretStart = 0;
+ else if (CaretStart > 1) {
+ unsigned NewStart = CaretStart - 1;
+
+ // Skip over any whitespace we see here; we're looking for
+ // another bit of interesting text.
+ while (NewStart && isspace(SourceLine[NewStart]))
+ --NewStart;
+
+ // Skip over this bit of "interesting" text.
+ while (NewStart && !isspace(SourceLine[NewStart]))
+ --NewStart;
+
+ // Move up to the non-whitespace character we just saw.
+ if (NewStart)
+ ++NewStart;
+
+ // If we're still within our limit, update the starting
+ // position within the source/caret line.
+ if (CaretEnd - NewStart <= TargetColumns) {
+ CaretStart = NewStart;
+ ExpandedRegion = true;
+ }
+ }
+
+ // Move the end of the interesting region right until we've
+ // pulled in something else interesting.
+ if (CaretEnd != SourceLength) {
+ assert(CaretEnd < SourceLength && "Unexpected caret position!");
+ unsigned NewEnd = CaretEnd;
+
+ // Skip over any whitespace we see here; we're looking for
+ // another bit of interesting text.
+ while (NewEnd != SourceLength && isspace(SourceLine[NewEnd - 1]))
+ ++NewEnd;
+
+ // Skip over this bit of "interesting" text.
+ while (NewEnd != SourceLength && !isspace(SourceLine[NewEnd - 1]))
+ ++NewEnd;
+
+ if (NewEnd - CaretStart <= TargetColumns) {
+ CaretEnd = NewEnd;
+ ExpandedRegion = true;
+ }
+ }
+
+ if (!ExpandedRegion)
+ break;
+ }
+
+ // [CaretStart, CaretEnd) is the slice we want. Update the various
+ // output lines to show only this slice, with two-space padding
+ // before the lines so that it looks nicer.
+ if (CaretEnd < SourceLine.size())
+ SourceLine.replace(CaretEnd, std::string::npos, "...");
+ if (CaretEnd < CaretLine.size())
+ CaretLine.erase(CaretEnd, std::string::npos);
+ if (FixItInsertionLine.size() > CaretEnd)
+ FixItInsertionLine.erase(CaretEnd, std::string::npos);
+
+ if (CaretStart > 2) {
+ SourceLine.replace(0, CaretStart, " ...");
+ CaretLine.replace(0, CaretStart, " ");
+ if (FixItInsertionLine.size() >= CaretStart)
+ FixItInsertionLine.replace(0, CaretStart, " ");
+ }
+}
+
+void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc,
+ CharSourceRange *Ranges,
+ unsigned NumRanges,
+ const SourceManager &SM,
+ const FixItHint *Hints,
+ unsigned NumHints,
+ unsigned Columns,
+ unsigned OnMacroInst,
+ unsigned MacroSkipStart,
+ unsigned MacroSkipEnd) {
+ assert(LangOpts && "Unexpected diagnostic outside source file processing");
+ assert(!Loc.isInvalid() && "must have a valid source location here");
+
+ // If this is a macro ID, first emit information about where this was
+ // instantiated (recursively) then emit information about where the token was
+ // spelled from.
+ if (!Loc.isFileID()) {
+ // Whether to suppress printing this macro instantiation.
+ bool Suppressed
+ = OnMacroInst >= MacroSkipStart && OnMacroInst < MacroSkipEnd;
+
+
+ SourceLocation OneLevelUp = SM.getImmediateInstantiationRange(Loc).first;
+ // FIXME: Map ranges?
+ EmitCaretDiagnostic(OneLevelUp, Ranges, NumRanges, SM, 0, 0, Columns,
+ OnMacroInst + 1, MacroSkipStart, MacroSkipEnd);
+
+ // Map the location.
+ Loc = SM.getImmediateSpellingLoc(Loc);
+
+ // Map the ranges.
+ for (unsigned i = 0; i != NumRanges; ++i) {
+ CharSourceRange &R = Ranges[i];
+ SourceLocation S = R.getBegin(), E = R.getEnd();
+ if (S.isMacroID())
+ R.setBegin(SM.getImmediateSpellingLoc(S));
+ if (E.isMacroID())
+ R.setEnd(SM.getImmediateSpellingLoc(E));
+ }
+
+ if (!Suppressed) {
+ // Get the pretty name, according to #line directives etc.
+ PresumedLoc PLoc = SM.getPresumedLoc(Loc);
+
+ // If this diagnostic is not in the main file, print out the
+ // "included from" lines.
+ if (LastWarningLoc != PLoc.getIncludeLoc()) {
+ LastWarningLoc = PLoc.getIncludeLoc();
+ PrintIncludeStack(LastWarningLoc, SM);
+ }
+
+ if (DiagOpts->ShowLocation) {
+ // Emit the file/line/column that this expansion came from.
+ OS << PLoc.getFilename() << ':' << PLoc.getLine() << ':';
+ if (DiagOpts->ShowColumn)
+ OS << PLoc.getColumn() << ':';
+ OS << ' ';
+ }
+ OS << "note: instantiated from:\n";
+
+ EmitCaretDiagnostic(Loc, Ranges, NumRanges, SM, Hints, NumHints, Columns,
+ OnMacroInst + 1, MacroSkipStart, MacroSkipEnd);
+ return;
+ }
+
+ if (OnMacroInst == MacroSkipStart) {
+ // Tell the user that we've skipped contexts.
+ OS << "note: (skipping " << (MacroSkipEnd - MacroSkipStart)
+ << " contexts in backtrace; use -fmacro-backtrace-limit=0 to see "
+ "all)\n";
+ }
+
+ return;
+ }
+
+ // Decompose the location into a FID/Offset pair.
+ std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
+ FileID FID = LocInfo.first;
+ unsigned FileOffset = LocInfo.second;
+
+ // Get information about the buffer it points into.
+ bool Invalid = false;
+ const char *BufStart = SM.getBufferData(FID, &Invalid).data();
+ if (Invalid)
+ return;
+
+ unsigned ColNo = SM.getColumnNumber(FID, FileOffset);
+ unsigned CaretEndColNo
+ = ColNo + Lexer::MeasureTokenLength(Loc, SM, *LangOpts);
+
+ // Rewind from the current position to the start of the line.
+ const char *TokPtr = BufStart+FileOffset;
+ const char *LineStart = TokPtr-ColNo+1; // Column # is 1-based.
+
+
+ // Compute the line end. Scan forward from the error position to the end of
+ // the line.
+ const char *LineEnd = TokPtr;
+ while (*LineEnd != '\n' && *LineEnd != '\r' && *LineEnd != '\0')
+ ++LineEnd;
+
+ // FIXME: This shouldn't be necessary, but the CaretEndColNo can extend past
+ // the source line length as currently being computed. See
+ // test/Misc/message-length.c.
+ CaretEndColNo = std::min(CaretEndColNo, unsigned(LineEnd - LineStart));
+
+ // Copy the line of code into an std::string for ease of manipulation.
+ std::string SourceLine(LineStart, LineEnd);
+
+ // Create a line for the caret that is filled with spaces that is the same
+ // length as the line of source code.
+ std::string CaretLine(LineEnd-LineStart, ' ');
+
+ // Highlight all of the characters covered by Ranges with ~ characters.
+ if (NumRanges) {
+ unsigned LineNo = SM.getLineNumber(FID, FileOffset);
+
+ for (unsigned i = 0, e = NumRanges; i != e; ++i)
+ HighlightRange(Ranges[i], SM, LineNo, FID, CaretLine, SourceLine);
+ }
+
+ // Next, insert the caret itself.
+ if (ColNo-1 < CaretLine.size())
+ CaretLine[ColNo-1] = '^';
+ else
+ CaretLine.push_back('^');
+
+ // Scan the source line, looking for tabs. If we find any, manually expand
+ // them to spaces and update the CaretLine to match.
+ for (unsigned i = 0; i != SourceLine.size(); ++i) {
+ if (SourceLine[i] != '\t') continue;
+
+ // Replace this tab with at least one space.
+ SourceLine[i] = ' ';
+
+ // Compute the number of spaces we need to insert.
+ unsigned TabStop = DiagOpts->TabStop;
+ assert(0 < TabStop && TabStop <= DiagnosticOptions::MaxTabStop &&
+ "Invalid -ftabstop value");
+ unsigned NumSpaces = ((i+TabStop)/TabStop * TabStop) - (i+1);
+ assert(NumSpaces < TabStop && "Invalid computation of space amt");
+
+ // Insert spaces into the SourceLine.
+ SourceLine.insert(i+1, NumSpaces, ' ');
+
+ // Insert spaces or ~'s into CaretLine.
+ CaretLine.insert(i+1, NumSpaces, CaretLine[i] == '~' ? '~' : ' ');
+ }
+
+ // If we are in -fdiagnostics-print-source-range-info mode, we are trying to
+ // produce easily machine parsable output. Add a space before the source line
+ // and the caret to make it trivial to tell the main diagnostic line from what
+ // the user is intended to see.
+ if (DiagOpts->ShowSourceRanges) {
+ SourceLine = ' ' + SourceLine;
+ CaretLine = ' ' + CaretLine;
+ }
+
+ std::string FixItInsertionLine;
+ if (NumHints && DiagOpts->ShowFixits) {
+ for (const FixItHint *Hint = Hints, *LastHint = Hints + NumHints;
+ Hint != LastHint; ++Hint) {
+ if (Hint->InsertionLoc.isValid()) {
+ // We have an insertion hint. Determine whether the inserted
+ // code is on the same line as the caret.
+ std::pair<FileID, unsigned> HintLocInfo
+ = SM.getDecomposedInstantiationLoc(Hint->InsertionLoc);
+ if (SM.getLineNumber(HintLocInfo.first, HintLocInfo.second) ==
+ SM.getLineNumber(FID, FileOffset)) {
+ // Insert the new code into the line just below the code
+ // that the user wrote.
+ unsigned HintColNo
+ = SM.getColumnNumber(HintLocInfo.first, HintLocInfo.second);
+ unsigned LastColumnModified
+ = HintColNo - 1 + Hint->CodeToInsert.size();
+ if (LastColumnModified > FixItInsertionLine.size())
+ FixItInsertionLine.resize(LastColumnModified, ' ');
+ std::copy(Hint->CodeToInsert.begin(), Hint->CodeToInsert.end(),
+ FixItInsertionLine.begin() + HintColNo - 1);
+ } else {
+ FixItInsertionLine.clear();
+ break;
+ }
+ }
+ }
+ // Now that we have the entire fixit line, expand the tabs in it.
+ // Since we don't want to insert spaces in the middle of a word,
+ // find each word and the column it should line up with and insert
+ // spaces until they match.
+ if (!FixItInsertionLine.empty()) {
+ unsigned FixItPos = 0;
+ unsigned LinePos = 0;
+ unsigned TabExpandedCol = 0;
+ unsigned LineLength = LineEnd - LineStart;
+
+ while (FixItPos < FixItInsertionLine.size() && LinePos < LineLength) {
+ // Find the next word in the FixIt line.
+ while (FixItPos < FixItInsertionLine.size() &&
+ FixItInsertionLine[FixItPos] == ' ')
+ ++FixItPos;
+ unsigned CharDistance = FixItPos - TabExpandedCol;
+
+ // Walk forward in the source line, keeping track of
+ // the tab-expanded column.
+ for (unsigned I = 0; I < CharDistance; ++I, ++LinePos)
+ if (LinePos >= LineLength || LineStart[LinePos] != '\t')
+ ++TabExpandedCol;
+ else
+ TabExpandedCol =
+ (TabExpandedCol/DiagOpts->TabStop + 1) * DiagOpts->TabStop;
+
+ // Adjust the fixit line to match this column.
+ FixItInsertionLine.insert(FixItPos, TabExpandedCol-FixItPos, ' ');
+ FixItPos = TabExpandedCol;
+
+ // Walk to the end of the word.
+ while (FixItPos < FixItInsertionLine.size() &&
+ FixItInsertionLine[FixItPos] != ' ')
+ ++FixItPos;
+ }
+ }
+ }
+
+ // If the source line is too long for our terminal, select only the
+ // "interesting" source region within that line.
+ if (Columns && SourceLine.size() > Columns)
+ SelectInterestingSourceRegion(SourceLine, CaretLine, FixItInsertionLine,
+ CaretEndColNo, Columns);
+
+ // Finally, remove any blank spaces from the end of CaretLine.
+ while (CaretLine[CaretLine.size()-1] == ' ')
+ CaretLine.erase(CaretLine.end()-1);
+
+ // Emit what we have computed.
+ OS << SourceLine << '\n';
+
+ if (DiagOpts->ShowColors)
+ OS.changeColor(caretColor, true);
+ OS << CaretLine << '\n';
+ if (DiagOpts->ShowColors)
+ OS.resetColor();
+
+ if (!FixItInsertionLine.empty()) {
+ if (DiagOpts->ShowColors)
+ // Print fixit line in color
+ OS.changeColor(fixitColor, false);
+ if (DiagOpts->ShowSourceRanges)
+ OS << ' ';
+ OS << FixItInsertionLine << '\n';
+ if (DiagOpts->ShowColors)
+ OS.resetColor();
+ }
+}
+
+/// \brief Skip over whitespace in the string, starting at the given
+/// index.
+///
+/// \returns The index of the first non-whitespace character that is
+/// greater than or equal to Idx or, if no such character exists,
+/// returns the end of the string.
+static unsigned skipWhitespace(unsigned Idx,
+ const llvm::SmallVectorImpl<char> &Str,
+ unsigned Length) {
+ while (Idx < Length && isspace(Str[Idx]))
+ ++Idx;
+ return Idx;
+}
+
+/// \brief If the given character is the start of some kind of
+/// balanced punctuation (e.g., quotes or parentheses), return the
+/// character that will terminate the punctuation.
+///
+/// \returns The ending punctuation character, if any, or the NULL
+/// character if the input character does not start any punctuation.
+static inline char findMatchingPunctuation(char c) {
+ switch (c) {
+ case '\'': return '\'';
+ case '`': return '\'';
+ case '"': return '"';
+ case '(': return ')';
+ case '[': return ']';
+ case '{': return '}';
+ default: break;
+ }
+
+ return 0;
+}
+
+/// \brief Find the end of the word starting at the given offset
+/// within a string.
+///
+/// \returns the index pointing one character past the end of the
+/// word.
+static unsigned findEndOfWord(unsigned Start,
+ const llvm::SmallVectorImpl<char> &Str,
+ unsigned Length, unsigned Column,
+ unsigned Columns) {
+ assert(Start < Str.size() && "Invalid start position!");
+ unsigned End = Start + 1;
+
+ // If we are already at the end of the string, take that as the word.
+ if (End == Str.size())
+ return End;
+
+ // Determine if the start of the string is actually opening
+ // punctuation, e.g., a quote or parentheses.
+ char EndPunct = findMatchingPunctuation(Str[Start]);
+ if (!EndPunct) {
+ // This is a normal word. Just find the first space character.
+ while (End < Length && !isspace(Str[End]))
+ ++End;
+ return End;
+ }
+
+ // We have the start of a balanced punctuation sequence (quotes,
+ // parentheses, etc.). Determine the full sequence is.
+ llvm::SmallString<16> PunctuationEndStack;
+ PunctuationEndStack.push_back(EndPunct);
+ while (End < Length && !PunctuationEndStack.empty()) {
+ if (Str[End] == PunctuationEndStack.back())
+ PunctuationEndStack.pop_back();
+ else if (char SubEndPunct = findMatchingPunctuation(Str[End]))
+ PunctuationEndStack.push_back(SubEndPunct);
+
+ ++End;
+ }
+
+ // Find the first space character after the punctuation ended.
+ while (End < Length && !isspace(Str[End]))
+ ++End;
+
+ unsigned PunctWordLength = End - Start;
+ if (// If the word fits on this line
+ Column + PunctWordLength <= Columns ||
+ // ... or the word is "short enough" to take up the next line
+ // without too much ugly white space
+ PunctWordLength < Columns/3)
+ return End; // Take the whole thing as a single "word".
+
+ // The whole quoted/parenthesized string is too long to print as a
+ // single "word". Instead, find the "word" that starts just after
+ // the punctuation and use that end-point instead. This will recurse
+ // until it finds something small enough to consider a word.
+ return findEndOfWord(Start + 1, Str, Length, Column + 1, Columns);
+}
+
+/// \brief Print the given string to a stream, word-wrapping it to
+/// some number of columns in the process.
+///
+/// \brief OS the stream to which the word-wrapping string will be
+/// emitted.
+///
+/// \brief Str the string to word-wrap and output.
+///
+/// \brief Columns the number of columns to word-wrap to.
+///
+/// \brief Column the column number at which the first character of \p
+/// Str will be printed. This will be non-zero when part of the first
+/// line has already been printed.
+///
+/// \brief Indentation the number of spaces to indent any lines beyond
+/// the first line.
+///
+/// \returns true if word-wrapping was required, or false if the
+/// string fit on the first line.
+static bool PrintWordWrapped(llvm::raw_ostream &OS,
+ const llvm::SmallVectorImpl<char> &Str,
+ unsigned Columns,
+ unsigned Column = 0,
+ unsigned Indentation = WordWrapIndentation) {
+ unsigned Length = Str.size();
+
+ // If there is a newline in this message somewhere, find that
+ // newline and split the message into the part before the newline
+ // (which will be word-wrapped) and the part from the newline one
+ // (which will be emitted unchanged).
+ for (unsigned I = 0; I != Length; ++I)
+ if (Str[I] == '\n') {
+ Length = I;
+ break;
+ }
+
+ // The string used to indent each line.
+ llvm::SmallString<16> IndentStr;
+ IndentStr.assign(Indentation, ' ');
+ bool Wrapped = false;
+ for (unsigned WordStart = 0, WordEnd; WordStart < Length;
+ WordStart = WordEnd) {
+ // Find the beginning of the next word.
+ WordStart = skipWhitespace(WordStart, Str, Length);
+ if (WordStart == Length)
+ break;
+
+ // Find the end of this word.
+ WordEnd = findEndOfWord(WordStart, Str, Length, Column, Columns);
+
+ // Does this word fit on the current line?
+ unsigned WordLength = WordEnd - WordStart;
+ if (Column + WordLength < Columns) {
+ // This word fits on the current line; print it there.
+ if (WordStart) {
+ OS << ' ';
+ Column += 1;
+ }
+ OS.write(&Str[WordStart], WordLength);
+ Column += WordLength;
+ continue;
+ }
+
+ // This word does not fit on the current line, so wrap to the next
+ // line.
+ OS << '\n';
+ OS.write(&IndentStr[0], Indentation);
+ OS.write(&Str[WordStart], WordLength);
+ Column = Indentation + WordLength;
+ Wrapped = true;
+ }
+
+ if (Length == Str.size())
+ return Wrapped; // We're done.
+
+ // There is a newline in the message, followed by something that
+ // will not be word-wrapped. Print that.
+ OS.write(&Str[Length], Str.size() - Length);
+ return true;
+}
+
+void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level,
+ const DiagnosticInfo &Info) {
+ // Keeps track of the the starting position of the location
+ // information (e.g., "foo.c:10:4:") that precedes the error
+ // message. We use this information to determine how long the
+ // file+line+column number prefix is.
+ uint64_t StartOfLocationInfo = OS.tell();
+
+ if (!Prefix.empty())
+ OS << Prefix << ": ";
+
+ // If the location is specified, print out a file/line/col and include trace
+ // if enabled.
+ if (Info.getLocation().isValid()) {
+ const SourceManager &SM = Info.getLocation().getManager();
+ PresumedLoc PLoc = SM.getPresumedLoc(Info.getLocation());
+ unsigned LineNo = PLoc.getLine();
+
+ // First, if this diagnostic is not in the main file, print out the
+ // "included from" lines.
+ if (LastWarningLoc != PLoc.getIncludeLoc()) {
+ LastWarningLoc = PLoc.getIncludeLoc();
+ PrintIncludeStack(LastWarningLoc, SM);
+ StartOfLocationInfo = OS.tell();
+ }
+
+ // Compute the column number.
+ if (DiagOpts->ShowLocation) {
+ if (DiagOpts->ShowColors)
+ OS.changeColor(savedColor, true);
+
+ // Emit a Visual Studio compatible line number syntax.
+ if (LangOpts && LangOpts->Microsoft) {
+ OS << PLoc.getFilename() << '(' << LineNo << ')';
+ OS << " : ";
+ } else {
+ OS << PLoc.getFilename() << ':' << LineNo << ':';
+ if (DiagOpts->ShowColumn)
+ if (unsigned ColNo = PLoc.getColumn())
+ OS << ColNo << ':';
+ }
+ if (DiagOpts->ShowSourceRanges && Info.getNumRanges()) {
+ FileID CaretFileID =
+ SM.getFileID(SM.getInstantiationLoc(Info.getLocation()));
+ bool PrintedRange = false;
+
+ for (unsigned i = 0, e = Info.getNumRanges(); i != e; ++i) {
+ // Ignore invalid ranges.
+ if (!Info.getRange(i).isValid()) continue;
+
+ SourceLocation B = Info.getRange(i).getBegin();
+ SourceLocation E = Info.getRange(i).getEnd();
+ B = SM.getInstantiationLoc(B);
+ E = SM.getInstantiationLoc(E);
+
+ // If the End location and the start location are the same and are a
+ // macro location, then the range was something that came from a macro
+ // expansion or _Pragma. If this is an object-like macro, the best we
+ // can do is to highlight the range. If this is a function-like
+ // macro, we'd also like to highlight the arguments.
+ if (B == E && Info.getRange(i).getEnd().isMacroID())
+ E = SM.getInstantiationRange(Info.getRange(i).getEnd()).second;
+
+ std::pair<FileID, unsigned> BInfo = SM.getDecomposedLoc(B);
+ std::pair<FileID, unsigned> EInfo = SM.getDecomposedLoc(E);
+
+ // If the start or end of the range is in another file, just discard
+ // it.
+ if (BInfo.first != CaretFileID || EInfo.first != CaretFileID)
+ continue;
+
+ // Add in the length of the token, so that we cover multi-char tokens.
+ unsigned TokSize = 0;
+ if (Info.getRange(i).isTokenRange())
+ TokSize = Lexer::MeasureTokenLength(E, SM, *LangOpts);
+
+ OS << '{' << SM.getLineNumber(BInfo.first, BInfo.second) << ':'
+ << SM.getColumnNumber(BInfo.first, BInfo.second) << '-'
+ << SM.getLineNumber(EInfo.first, EInfo.second) << ':'
+ << (SM.getColumnNumber(EInfo.first, EInfo.second)+TokSize) << '}';
+ PrintedRange = true;
+ }
+
+ if (PrintedRange)
+ OS << ':';
+ }
+ OS << ' ';
+ if (DiagOpts->ShowColors)
+ OS.resetColor();
+ }
+ }
+
+ if (DiagOpts->ShowColors) {
+ // Print diagnostic category in bold and color
+ switch (Level) {
+ case Diagnostic::Ignored: assert(0 && "Invalid diagnostic type");
+ case Diagnostic::Note: OS.changeColor(noteColor, true); break;
+ case Diagnostic::Warning: OS.changeColor(warningColor, true); break;
+ case Diagnostic::Error: OS.changeColor(errorColor, true); break;
+ case Diagnostic::Fatal: OS.changeColor(fatalColor, true); break;
+ }
+ }
+
+ switch (Level) {
+ case Diagnostic::Ignored: assert(0 && "Invalid diagnostic type");
+ case Diagnostic::Note: OS << "note: "; break;
+ case Diagnostic::Warning: OS << "warning: "; break;
+ case Diagnostic::Error: OS << "error: "; break;
+ case Diagnostic::Fatal: OS << "fatal error: "; break;
+ }
+
+ if (DiagOpts->ShowColors)
+ OS.resetColor();
+
+ llvm::SmallString<100> OutStr;
+ Info.FormatDiagnostic(OutStr);
+
+ std::string OptionName;
+ if (DiagOpts->ShowOptionNames) {
+ if (const char *Opt = Diagnostic::getWarningOptionForDiag(Info.getID())) {
+ OptionName = "-W";
+ OptionName += Opt;
+ } else if (Info.getID() == diag::fatal_too_many_errors) {
+ OptionName = "-ferror-limit=";
+ } else {
+ // If the diagnostic is an extension diagnostic and not enabled by default
+ // then it must have been turned on with -pedantic.
+ bool EnabledByDefault;
+ if (Diagnostic::isBuiltinExtensionDiag(Info.getID(), EnabledByDefault) &&
+ !EnabledByDefault)
+ OptionName = "-pedantic";
+ }
+ }
+
+ // If the user wants to see category information, include it too.
+ unsigned DiagCategory = 0;
+ if (DiagOpts->ShowCategories)
+ DiagCategory = Diagnostic::getCategoryNumberForDiag(Info.getID());
+
+ // If there is any categorization information, include it.
+ if (!OptionName.empty() || DiagCategory != 0) {
+ bool NeedsComma = false;
+ OutStr += " [";
+
+ if (!OptionName.empty()) {
+ OutStr += OptionName;
+ NeedsComma = true;
+ }
+
+ if (DiagCategory) {
+ if (NeedsComma) OutStr += ',';
+ if (DiagOpts->ShowCategories == 1)
+ OutStr += llvm::utostr(DiagCategory);
+ else {
+ assert(DiagOpts->ShowCategories == 2 && "Invalid ShowCategories value");
+ OutStr += Diagnostic::getCategoryNameFromID(DiagCategory);
+ }
+ }
+
+ OutStr += "]";
+ }
+
+
+ if (DiagOpts->ShowColors) {
+ // Print warnings, errors and fatal errors in bold, no color
+ switch (Level) {
+ case Diagnostic::Warning: OS.changeColor(savedColor, true); break;
+ case Diagnostic::Error: OS.changeColor(savedColor, true); break;
+ case Diagnostic::Fatal: OS.changeColor(savedColor, true); break;
+ default: break; //don't bold notes
+ }
+ }
+
+ if (DiagOpts->MessageLength) {
+ // We will be word-wrapping the error message, so compute the
+ // column number where we currently are (after printing the
+ // location information).
+ unsigned Column = OS.tell() - StartOfLocationInfo;
+ PrintWordWrapped(OS, OutStr, DiagOpts->MessageLength, Column);
+ } else {
+ OS.write(OutStr.begin(), OutStr.size());
+ }
+ OS << '\n';
+ if (DiagOpts->ShowColors)
+ OS.resetColor();
+
+ // If caret diagnostics are enabled and we have location, we want to
+ // emit the caret. However, we only do this if the location moved
+ // from the last diagnostic, if the last diagnostic was a note that
+ // was part of a different warning or error diagnostic, or if the
+ // diagnostic has ranges. We don't want to emit the same caret
+ // multiple times if one loc has multiple diagnostics.
+ if (DiagOpts->ShowCarets && Info.getLocation().isValid() &&
+ ((LastLoc != Info.getLocation()) || Info.getNumRanges() ||
+ (LastCaretDiagnosticWasNote && Level != Diagnostic::Note) ||
+ Info.getNumFixItHints())) {
+ // Cache the LastLoc, it allows us to omit duplicate source/caret spewage.
+ LastLoc = Info.getLocation();
+ LastCaretDiagnosticWasNote = (Level == Diagnostic::Note);
+
+ // Get the ranges into a local array we can hack on.
+ CharSourceRange Ranges[20];
+ unsigned NumRanges = Info.getNumRanges();
+ assert(NumRanges < 20 && "Out of space");
+ for (unsigned i = 0; i != NumRanges; ++i)
+ Ranges[i] = Info.getRange(i);
+
+ unsigned NumHints = Info.getNumFixItHints();
+ for (unsigned i = 0; i != NumHints; ++i) {
+ const FixItHint &Hint = Info.getFixItHint(i);
+ if (Hint.RemoveRange.isValid()) {
+ assert(NumRanges < 20 && "Out of space");
+ Ranges[NumRanges++] = Hint.RemoveRange;
+ }
+ }
+
+ unsigned MacroInstSkipStart = 0, MacroInstSkipEnd = 0;
+ if (DiagOpts && DiagOpts->MacroBacktraceLimit && !LastLoc.isFileID()) {
+ // Compute the length of the macro-instantiation backtrace, so that we
+ // can establish which steps in the macro backtrace we'll skip.
+ SourceLocation Loc = LastLoc;
+ unsigned Depth = 0;
+ do {
+ ++Depth;
+ Loc = LastLoc.getManager().getImmediateInstantiationRange(Loc).first;
+ } while (!Loc.isFileID());
+
+ if (Depth > DiagOpts->MacroBacktraceLimit) {
+ MacroInstSkipStart = DiagOpts->MacroBacktraceLimit / 2 +
+ DiagOpts->MacroBacktraceLimit % 2;
+ MacroInstSkipEnd = Depth - DiagOpts->MacroBacktraceLimit / 2;
+ }
+ }
+
+ EmitCaretDiagnostic(LastLoc, Ranges, NumRanges, LastLoc.getManager(),
+ Info.getFixItHints(),
+ Info.getNumFixItHints(),
+ DiagOpts->MessageLength,
+ 0, MacroInstSkipStart, MacroInstSkipEnd);
+ }
+
+ OS.flush();
+}
diff --git a/contrib/llvm/tools/clang/lib/Frontend/TypeXML.cpp b/contrib/llvm/tools/clang/lib/Frontend/TypeXML.cpp
new file mode 100644
index 0000000..be9db42
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Frontend/TypeXML.cpp
@@ -0,0 +1,119 @@
+//===--- DocumentXML.cpp - XML document for ASTs --------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the XML document class, which provides the means to
+// dump out the AST in a XML form that exposes type details and other fields.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/DocumentXML.h"
+#include "clang/AST/TypeVisitor.h"
+#include "clang/AST/Type.h"
+#include "clang/AST/Decl.h"
+
+namespace clang {
+ namespace XML {
+ namespace {
+
+//---------------------------------------------------------
+class TypeWriter : public TypeVisitor<TypeWriter> {
+ DocumentXML& Doc;
+
+public:
+ TypeWriter(DocumentXML& doc) : Doc(doc) {}
+
+#define NODE_XML( CLASS, NAME ) \
+ void Visit##CLASS(CLASS* T) { \
+ Doc.addSubNode(NAME);
+
+#define ID_ATTRIBUTE_XML // done by the Document class itself
+#define ATTRIBUTE_XML( FN, NAME ) Doc.addAttribute(NAME, T->FN);
+#define TYPE_ATTRIBUTE_XML( FN ) ATTRIBUTE_XML(FN, "type")
+#define CONTEXT_ATTRIBUTE_XML( FN ) ATTRIBUTE_XML(FN, "context")
+#define ATTRIBUTE_OPT_XML( FN, NAME ) Doc.addAttributeOptional(NAME, T->FN);
+
+#define ATTRIBUTE_ENUM_XML( FN, NAME ) \
+ { \
+ const char* pAttributeName = NAME; \
+ const bool optional = false; \
+ switch (T->FN) { \
+ default: assert(0 && "unknown enum value");
+
+#define ATTRIBUTE_ENUM_OPT_XML( FN, NAME ) \
+ { \
+ const char* pAttributeName = NAME; \
+ const bool optional = true; \
+ switch (T->FN) { \
+ default: assert(0 && "unknown enum value");
+
+#define ENUM_XML( VALUE, NAME ) case VALUE: if ((!optional) || NAME[0]) Doc.addAttribute(pAttributeName, NAME); break;
+#define END_ENUM_XML } }
+#define END_NODE_XML }
+
+#include "clang/Frontend/TypeXML.def"
+
+};
+
+//---------------------------------------------------------
+ } // anon clang
+ } // NS XML
+
+//---------------------------------------------------------
+class DocumentXML::TypeAdder : public TypeVisitor<DocumentXML::TypeAdder> {
+ DocumentXML& Doc;
+
+ void addIfType(const Type* pType) {
+ Doc.addTypeRecursively(pType);
+ }
+
+ void addIfType(const QualType& pType) {
+ Doc.addTypeRecursively(pType);
+ }
+
+ template<class T> void addIfType(T) {}
+
+public:
+ TypeAdder(DocumentXML& doc) : Doc(doc) {}
+
+#define NODE_XML( CLASS, NAME ) \
+ void Visit##CLASS(CLASS* T) \
+ {
+
+#define ID_ATTRIBUTE_XML
+#define TYPE_ATTRIBUTE_XML( FN ) Doc.addTypeRecursively(T->FN);
+#define CONTEXT_ATTRIBUTE_XML( FN )
+#define ATTRIBUTE_XML( FN, NAME ) addIfType(T->FN);
+#define ATTRIBUTE_OPT_XML( FN, NAME )
+#define ATTRIBUTE_ENUM_XML( FN, NAME )
+#define ATTRIBUTE_ENUM_OPT_XML( FN, NAME )
+#define ENUM_XML( VALUE, NAME )
+#define END_ENUM_XML
+#define END_NODE_XML }
+
+#include "clang/Frontend/TypeXML.def"
+};
+
+//---------------------------------------------------------
+void DocumentXML::addParentTypes(const Type* pType) {
+ TypeAdder(*this).Visit(const_cast<Type*>(pType));
+}
+
+//---------------------------------------------------------
+void DocumentXML::writeTypeToXML(const Type* pType) {
+ XML::TypeWriter(*this).Visit(const_cast<Type*>(pType));
+}
+
+//---------------------------------------------------------
+void DocumentXML::writeTypeToXML(const QualType& pType) {
+ XML::TypeWriter(*this).VisitQualType(const_cast<QualType*>(&pType));
+}
+
+//---------------------------------------------------------
+} // NS clang
+
diff --git a/contrib/llvm/tools/clang/lib/Frontend/VerifyDiagnosticsClient.cpp b/contrib/llvm/tools/clang/lib/Frontend/VerifyDiagnosticsClient.cpp
new file mode 100644
index 0000000..ae36481
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Frontend/VerifyDiagnosticsClient.cpp
@@ -0,0 +1,521 @@
+//===--- VerifyDiagnosticsClient.cpp - Verifying Diagnostic Client --------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This is a concrete diagnostic client, which buffers the diagnostic messages.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/VerifyDiagnosticsClient.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
+#include "clang/Frontend/TextDiagnosticBuffer.h"
+#include "clang/Lex/Preprocessor.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/Regex.h"
+#include "llvm/Support/raw_ostream.h"
+using namespace clang;
+
+VerifyDiagnosticsClient::VerifyDiagnosticsClient(Diagnostic &_Diags,
+ DiagnosticClient *_Primary)
+ : Diags(_Diags), PrimaryClient(_Primary),
+ Buffer(new TextDiagnosticBuffer()), CurrentPreprocessor(0), NumErrors(0) {
+}
+
+VerifyDiagnosticsClient::~VerifyDiagnosticsClient() {
+ CheckDiagnostics();
+}
+
+// DiagnosticClient interface.
+
+void VerifyDiagnosticsClient::BeginSourceFile(const LangOptions &LangOpts,
+ const Preprocessor *PP) {
+ // FIXME: Const hack, we screw up the preprocessor but in practice its ok
+ // because it doesn't get reused. It would be better if we could make a copy
+ // though.
+ CurrentPreprocessor = const_cast<Preprocessor*>(PP);
+
+ PrimaryClient->BeginSourceFile(LangOpts, PP);
+}
+
+void VerifyDiagnosticsClient::EndSourceFile() {
+ CheckDiagnostics();
+
+ PrimaryClient->EndSourceFile();
+
+ CurrentPreprocessor = 0;
+}
+
+void VerifyDiagnosticsClient::HandleDiagnostic(Diagnostic::Level DiagLevel,
+ const DiagnosticInfo &Info) {
+ // Send the diagnostic to the buffer, we will check it once we reach the end
+ // of the source file (or are destructed).
+ Buffer->HandleDiagnostic(DiagLevel, Info);
+}
+
+// FIXME: It would be nice to just get this from the primary diagnostic client
+// or something.
+bool VerifyDiagnosticsClient::HadErrors() {
+ CheckDiagnostics();
+
+ return NumErrors != 0;
+}
+
+//===----------------------------------------------------------------------===//
+// Checking diagnostics implementation.
+//===----------------------------------------------------------------------===//
+
+typedef TextDiagnosticBuffer::DiagList DiagList;
+typedef TextDiagnosticBuffer::const_iterator const_diag_iterator;
+
+namespace {
+
+/// Directive - Abstract class representing a parsed verify directive.
+///
+class Directive {
+public:
+ static Directive* Create(bool RegexKind, const SourceLocation &Location,
+ const std::string &Text, unsigned Count);
+public:
+ SourceLocation Location;
+ const std::string Text;
+ unsigned Count;
+
+ virtual ~Directive() { }
+
+ // Returns true if directive text is valid.
+ // Otherwise returns false and populates E.
+ virtual bool isValid(std::string &Error) = 0;
+
+ // Returns true on match.
+ virtual bool Match(const std::string &S) = 0;
+
+protected:
+ Directive(const SourceLocation &Location, const std::string &Text,
+ unsigned Count)
+ : Location(Location), Text(Text), Count(Count) { }
+
+private:
+ Directive(const Directive&); // DO NOT IMPLEMENT
+ void operator=(const Directive&); // DO NOT IMPLEMENT
+};
+
+/// StandardDirective - Directive with string matching.
+///
+class StandardDirective : public Directive {
+public:
+ StandardDirective(const SourceLocation &Location, const std::string &Text,
+ unsigned Count)
+ : Directive(Location, Text, Count) { }
+
+ virtual bool isValid(std::string &Error) {
+ // all strings are considered valid; even empty ones
+ return true;
+ }
+
+ virtual bool Match(const std::string &S) {
+ return S.find(Text) != std::string::npos ||
+ Text.find(S) != std::string::npos;
+ }
+};
+
+/// RegexDirective - Directive with regular-expression matching.
+///
+class RegexDirective : public Directive {
+public:
+ RegexDirective(const SourceLocation &Location, const std::string &Text,
+ unsigned Count)
+ : Directive(Location, Text, Count), Regex(Text) { }
+
+ virtual bool isValid(std::string &Error) {
+ if (Regex.isValid(Error))
+ return true;
+ return false;
+ }
+
+ virtual bool Match(const std::string &S) {
+ return Regex.match(S);
+ }
+
+private:
+ llvm::Regex Regex;
+};
+
+typedef std::vector<Directive*> DirectiveList;
+
+/// ExpectedData - owns directive objects and deletes on destructor.
+///
+struct ExpectedData {
+ DirectiveList Errors;
+ DirectiveList Warnings;
+ DirectiveList Notes;
+
+ ~ExpectedData() {
+ DirectiveList* Lists[] = { &Errors, &Warnings, &Notes, 0 };
+ for (DirectiveList **PL = Lists; *PL; ++PL) {
+ DirectiveList * const L = *PL;
+ for (DirectiveList::iterator I = L->begin(), E = L->end(); I != E; ++I)
+ delete *I;
+ }
+ }
+};
+
+class ParseHelper
+{
+public:
+ ParseHelper(const char *Begin, const char *End)
+ : Begin(Begin), End(End), C(Begin), P(Begin), PEnd(NULL) { }
+
+ // Return true if string literal is next.
+ bool Next(const std::string &S) {
+ std::string::size_type LEN = S.length();
+ P = C;
+ PEnd = C + LEN;
+ if (PEnd > End)
+ return false;
+ return !memcmp(P, S.c_str(), LEN);
+ }
+
+ // Return true if number is next.
+ // Output N only if number is next.
+ bool Next(unsigned &N) {
+ unsigned TMP = 0;
+ P = C;
+ for (; P < End && P[0] >= '0' && P[0] <= '9'; ++P) {
+ TMP *= 10;
+ TMP += P[0] - '0';
+ }
+ if (P == C)
+ return false;
+ PEnd = P;
+ N = TMP;
+ return true;
+ }
+
+ // Return true if string literal is found.
+ // When true, P marks begin-position of S in content.
+ bool Search(const std::string &S) {
+ P = std::search(C, End, S.begin(), S.end());
+ PEnd = P + S.length();
+ return P != End;
+ }
+
+ // Advance 1-past previous next/search.
+ // Behavior is undefined if previous next/search failed.
+ bool Advance() {
+ C = PEnd;
+ return C < End;
+ }
+
+ // Skip zero or more whitespace.
+ void SkipWhitespace() {
+ for (; C < End && isspace(*C); ++C)
+ ;
+ }
+
+ // Return true if EOF reached.
+ bool Done() {
+ return !(C < End);
+ }
+
+ const char * const Begin; // beginning of expected content
+ const char * const End; // end of expected content (1-past)
+ const char *C; // position of next char in content
+ const char *P;
+
+private:
+ const char *PEnd; // previous next/search subject end (1-past)
+};
+
+} // namespace anonymous
+
+/// ParseDirective - Go through the comment and see if it indicates expected
+/// diagnostics. If so, then put them in the appropriate directive list.
+///
+static void ParseDirective(const char *CommentStart, unsigned CommentLen,
+ ExpectedData &ED, Preprocessor &PP,
+ SourceLocation Pos) {
+ // A single comment may contain multiple directives.
+ for (ParseHelper PH(CommentStart, CommentStart+CommentLen); !PH.Done();) {
+ // search for token: expected
+ if (!PH.Search("expected"))
+ break;
+ PH.Advance();
+
+ // next token: -
+ if (!PH.Next("-"))
+ continue;
+ PH.Advance();
+
+ // next token: { error | warning | note }
+ DirectiveList* DL = NULL;
+ if (PH.Next("error"))
+ DL = &ED.Errors;
+ else if (PH.Next("warning"))
+ DL = &ED.Warnings;
+ else if (PH.Next("note"))
+ DL = &ED.Notes;
+ else
+ continue;
+ PH.Advance();
+
+ // default directive kind
+ bool RegexKind = false;
+ const char* KindStr = "string";
+
+ // next optional token: -
+ if (PH.Next("-re")) {
+ PH.Advance();
+ RegexKind = true;
+ KindStr = "regex";
+ }
+
+ // skip optional whitespace
+ PH.SkipWhitespace();
+
+ // next optional token: positive integer
+ unsigned Count = 1;
+ if (PH.Next(Count))
+ PH.Advance();
+
+ // skip optional whitespace
+ PH.SkipWhitespace();
+
+ // next token: {{
+ if (!PH.Next("{{")) {
+ PP.Diag(Pos.getFileLocWithOffset(PH.C-PH.Begin),
+ diag::err_verify_missing_start) << KindStr;
+ continue;
+ }
+ PH.Advance();
+ const char* const ContentBegin = PH.C; // mark content begin
+
+ // search for token: }}
+ if (!PH.Search("}}")) {
+ PP.Diag(Pos.getFileLocWithOffset(PH.C-PH.Begin),
+ diag::err_verify_missing_end) << KindStr;
+ continue;
+ }
+ const char* const ContentEnd = PH.P; // mark content end
+ PH.Advance();
+
+ // build directive text; convert \n to newlines
+ std::string Text;
+ llvm::StringRef NewlineStr = "\\n";
+ llvm::StringRef Content(ContentBegin, ContentEnd-ContentBegin);
+ size_t CPos = 0;
+ size_t FPos;
+ while ((FPos = Content.find(NewlineStr, CPos)) != llvm::StringRef::npos) {
+ Text += Content.substr(CPos, FPos-CPos);
+ Text += '\n';
+ CPos = FPos + NewlineStr.size();
+ }
+ if (Text.empty())
+ Text.assign(ContentBegin, ContentEnd);
+
+ // construct new directive
+ Directive *D = Directive::Create(RegexKind, Pos, Text, Count);
+ std::string Error;
+ if (D->isValid(Error))
+ DL->push_back(D);
+ else {
+ PP.Diag(Pos.getFileLocWithOffset(ContentBegin-PH.Begin),
+ diag::err_verify_invalid_content)
+ << KindStr << Error;
+ }
+ }
+}
+
+/// FindExpectedDiags - Lex the main source file to find all of the
+// expected errors and warnings.
+static void FindExpectedDiags(Preprocessor &PP, ExpectedData &ED) {
+ // Create a raw lexer to pull all the comments out of the main file. We don't
+ // want to look in #include'd headers for expected-error strings.
+ SourceManager &SM = PP.getSourceManager();
+ FileID FID = SM.getMainFileID();
+ if (SM.getMainFileID().isInvalid())
+ return;
+
+ // Create a lexer to lex all the tokens of the main file in raw mode.
+ const llvm::MemoryBuffer *FromFile = SM.getBuffer(FID);
+ Lexer RawLex(FID, FromFile, SM, PP.getLangOptions());
+
+ // Return comments as tokens, this is how we find expected diagnostics.
+ RawLex.SetCommentRetentionState(true);
+
+ Token Tok;
+ Tok.setKind(tok::comment);
+ while (Tok.isNot(tok::eof)) {
+ RawLex.Lex(Tok);
+ if (!Tok.is(tok::comment)) continue;
+
+ std::string Comment = PP.getSpelling(Tok);
+ if (Comment.empty()) continue;
+
+ // Find all expected errors/warnings/notes.
+ ParseDirective(&Comment[0], Comment.size(), ED, PP, Tok.getLocation());
+ };
+}
+
+/// PrintProblem - This takes a diagnostic map of the delta between expected and
+/// seen diagnostics. If there's anything in it, then something unexpected
+/// happened. Print the map out in a nice format and return "true". If the map
+/// is empty and we're not going to print things, then return "false".
+///
+static unsigned PrintProblem(Diagnostic &Diags, SourceManager *SourceMgr,
+ const_diag_iterator diag_begin,
+ const_diag_iterator diag_end,
+ const char *Kind, bool Expected) {
+ if (diag_begin == diag_end) return 0;
+
+ llvm::SmallString<256> Fmt;
+ llvm::raw_svector_ostream OS(Fmt);
+ for (const_diag_iterator I = diag_begin, E = diag_end; I != E; ++I) {
+ if (I->first.isInvalid() || !SourceMgr)
+ OS << "\n (frontend)";
+ else
+ OS << "\n Line " << SourceMgr->getInstantiationLineNumber(I->first);
+ OS << ": " << I->second;
+ }
+
+ Diags.Report(diag::err_verify_inconsistent_diags)
+ << Kind << !Expected << OS.str();
+ return std::distance(diag_begin, diag_end);
+}
+
+static unsigned PrintProblem(Diagnostic &Diags, SourceManager *SourceMgr,
+ DirectiveList &DL, const char *Kind,
+ bool Expected) {
+ if (DL.empty())
+ return 0;
+
+ llvm::SmallString<256> Fmt;
+ llvm::raw_svector_ostream OS(Fmt);
+ for (DirectiveList::iterator I = DL.begin(), E = DL.end(); I != E; ++I) {
+ Directive& D = **I;
+ if (D.Location.isInvalid() || !SourceMgr)
+ OS << "\n (frontend)";
+ else
+ OS << "\n Line " << SourceMgr->getInstantiationLineNumber(D.Location);
+ OS << ": " << D.Text;
+ }
+
+ Diags.Report(diag::err_verify_inconsistent_diags)
+ << Kind << !Expected << OS.str();
+ return DL.size();
+}
+
+/// CheckLists - Compare expected to seen diagnostic lists and return the
+/// the difference between them.
+///
+static unsigned CheckLists(Diagnostic &Diags, SourceManager &SourceMgr,
+ const char *Label,
+ DirectiveList &Left,
+ const_diag_iterator d2_begin,
+ const_diag_iterator d2_end) {
+ DirectiveList LeftOnly;
+ DiagList Right(d2_begin, d2_end);
+
+ for (DirectiveList::iterator I = Left.begin(), E = Left.end(); I != E; ++I) {
+ Directive& D = **I;
+ unsigned LineNo1 = SourceMgr.getInstantiationLineNumber(D.Location);
+
+ for (unsigned i = 0; i < D.Count; ++i) {
+ DiagList::iterator II, IE;
+ for (II = Right.begin(), IE = Right.end(); II != IE; ++II) {
+ unsigned LineNo2 = SourceMgr.getInstantiationLineNumber(II->first);
+ if (LineNo1 != LineNo2)
+ continue;
+
+ const std::string &RightText = II->second;
+ if (D.Match(RightText))
+ break;
+ }
+ if (II == IE) {
+ // Not found.
+ LeftOnly.push_back(*I);
+ } else {
+ // Found. The same cannot be found twice.
+ Right.erase(II);
+ }
+ }
+ }
+ // Now all that's left in Right are those that were not matched.
+
+ return (PrintProblem(Diags, &SourceMgr, LeftOnly, Label, true) +
+ PrintProblem(Diags, &SourceMgr, Right.begin(), Right.end(),
+ Label, false));
+}
+
+/// CheckResults - This compares the expected results to those that
+/// were actually reported. It emits any discrepencies. Return "true" if there
+/// were problems. Return "false" otherwise.
+///
+static unsigned CheckResults(Diagnostic &Diags, SourceManager &SourceMgr,
+ const TextDiagnosticBuffer &Buffer,
+ ExpectedData &ED) {
+ // We want to capture the delta between what was expected and what was
+ // seen.
+ //
+ // Expected \ Seen - set expected but not seen
+ // Seen \ Expected - set seen but not expected
+ unsigned NumProblems = 0;
+
+ // See if there are error mismatches.
+ NumProblems += CheckLists(Diags, SourceMgr, "error", ED.Errors,
+ Buffer.err_begin(), Buffer.err_end());
+
+ // See if there are warning mismatches.
+ NumProblems += CheckLists(Diags, SourceMgr, "warning", ED.Warnings,
+ Buffer.warn_begin(), Buffer.warn_end());
+
+ // See if there are note mismatches.
+ NumProblems += CheckLists(Diags, SourceMgr, "note", ED.Notes,
+ Buffer.note_begin(), Buffer.note_end());
+
+ return NumProblems;
+}
+
+void VerifyDiagnosticsClient::CheckDiagnostics() {
+ ExpectedData ED;
+
+ // Ensure any diagnostics go to the primary client.
+ DiagnosticClient *CurClient = Diags.getClient();
+ Diags.setClient(PrimaryClient.get());
+
+ // If we have a preprocessor, scan the source for expected diagnostic
+ // markers. If not then any diagnostics are unexpected.
+ if (CurrentPreprocessor) {
+ FindExpectedDiags(*CurrentPreprocessor, ED);
+
+ // Check that the expected diagnostics occurred.
+ NumErrors += CheckResults(Diags, CurrentPreprocessor->getSourceManager(),
+ *Buffer, ED);
+ } else {
+ NumErrors += (PrintProblem(Diags, 0,
+ Buffer->err_begin(), Buffer->err_end(),
+ "error", false) +
+ PrintProblem(Diags, 0,
+ Buffer->warn_begin(), Buffer->warn_end(),
+ "warn", false) +
+ PrintProblem(Diags, 0,
+ Buffer->note_begin(), Buffer->note_end(),
+ "note", false));
+ }
+
+ Diags.setClient(CurClient);
+
+ // Reset the buffer, we have processed all the diagnostics in it.
+ Buffer.reset(new TextDiagnosticBuffer());
+}
+
+Directive* Directive::Create(bool RegexKind, const SourceLocation &Location,
+ const std::string &Text, unsigned Count) {
+ if (RegexKind)
+ return new RegexDirective(Location, Text, Count);
+ return new StandardDirective(Location, Text, Count);
+}
diff --git a/contrib/llvm/tools/clang/lib/Frontend/Warnings.cpp b/contrib/llvm/tools/clang/lib/Frontend/Warnings.cpp
new file mode 100644
index 0000000..8cc5616
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Frontend/Warnings.cpp
@@ -0,0 +1,133 @@
+//===--- Warnings.cpp - C-Language Front-end ------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Command line warning options handler.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is responsible for handling all warning options. This includes
+// a number of -Wfoo options and their variants, which are driven by TableGen-
+// generated data, and the special cases -pedantic, -pedantic-errors, -w,
+// -Werror and -Wfatal-errors.
+//
+// Each warning option controls any number of actual warnings.
+// Given a warning option 'foo', the following are valid:
+// -Wfoo, -Wno-foo, -Werror=foo, -Wfatal-errors=foo
+//
+#include "clang/Frontend/Utils.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Sema/SemaDiagnostic.h"
+#include "clang/Lex/LexDiagnostic.h"
+#include "clang/Frontend/DiagnosticOptions.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
+#include <cstring>
+#include <utility>
+#include <algorithm>
+using namespace clang;
+
+void clang::ProcessWarningOptions(Diagnostic &Diags,
+ const DiagnosticOptions &Opts) {
+ Diags.setSuppressSystemWarnings(true); // Default to -Wno-system-headers
+ Diags.setIgnoreAllWarnings(Opts.IgnoreWarnings);
+ Diags.setShowOverloads(
+ static_cast<Diagnostic::OverloadsShown>(Opts.ShowOverloads));
+
+ // Handle -ferror-limit
+ if (Opts.ErrorLimit)
+ Diags.setErrorLimit(Opts.ErrorLimit);
+ if (Opts.TemplateBacktraceLimit)
+ Diags.setTemplateBacktraceLimit(Opts.TemplateBacktraceLimit);
+
+ // If -pedantic or -pedantic-errors was specified, then we want to map all
+ // extension diagnostics onto WARNING or ERROR unless the user has futz'd
+ // around with them explicitly.
+ if (Opts.PedanticErrors)
+ Diags.setExtensionHandlingBehavior(Diagnostic::Ext_Error);
+ else if (Opts.Pedantic)
+ Diags.setExtensionHandlingBehavior(Diagnostic::Ext_Warn);
+ else
+ Diags.setExtensionHandlingBehavior(Diagnostic::Ext_Ignore);
+
+ for (unsigned i = 0, e = Opts.Warnings.size(); i != e; ++i) {
+ const std::string &Opt = Opts.Warnings[i];
+ const char *OptStart = &Opt[0];
+ const char *OptEnd = OptStart+Opt.size();
+ assert(*OptEnd == 0 && "Expect null termination for lower-bound search");
+
+ // Check to see if this warning starts with "no-", if so, this is a negative
+ // form of the option.
+ bool isPositive = true;
+ if (OptEnd-OptStart > 3 && memcmp(OptStart, "no-", 3) == 0) {
+ isPositive = false;
+ OptStart += 3;
+ }
+
+ // Figure out how this option affects the warning. If -Wfoo, map the
+ // diagnostic to a warning, if -Wno-foo, map it to ignore.
+ diag::Mapping Mapping = isPositive ? diag::MAP_WARNING : diag::MAP_IGNORE;
+
+ // -Wsystem-headers is a special case, not driven by the option table. It
+ // cannot be controlled with -Werror.
+ if (OptEnd-OptStart == 14 && memcmp(OptStart, "system-headers", 14) == 0) {
+ Diags.setSuppressSystemWarnings(!isPositive);
+ continue;
+ }
+
+ // -Werror/-Wno-error is a special case, not controlled by the option table.
+ // It also has the "specifier" form of -Werror=foo and -Werror-foo.
+ if (OptEnd-OptStart >= 5 && memcmp(OptStart, "error", 5) == 0) {
+ const char *Specifier = 0;
+ if (OptEnd-OptStart != 5) { // Specifier must be present.
+ if ((OptStart[5] != '=' && OptStart[5] != '-') ||
+ OptEnd-OptStart == 6) {
+ Diags.Report(diag::warn_unknown_warning_specifier)
+ << "-Werror" << ("-W" + Opt);
+ continue;
+ }
+ Specifier = OptStart+6;
+ }
+
+ if (Specifier == 0) {
+ Diags.setWarningsAsErrors(isPositive);
+ continue;
+ }
+
+ // -Werror=foo maps foo to Error, -Wno-error=foo maps it to Warning.
+ Mapping = isPositive ? diag::MAP_ERROR : diag::MAP_WARNING_NO_WERROR;
+ OptStart = Specifier;
+ }
+
+ // -Wfatal-errors is yet another special case.
+ if (OptEnd-OptStart >= 12 && memcmp(OptStart, "fatal-errors", 12) == 0) {
+ const char* Specifier = 0;
+ if (OptEnd-OptStart != 12) {
+ if ((OptStart[12] != '=' && OptStart[12] != '-') ||
+ OptEnd-OptStart == 13) {
+ Diags.Report(diag::warn_unknown_warning_specifier)
+ << "-Wfatal-errors" << ("-W" + Opt);
+ continue;
+ }
+ Specifier = OptStart + 13;
+ }
+
+ if (Specifier == 0) {
+ Diags.setErrorsAsFatal(isPositive);
+ continue;
+ }
+
+ // -Wfatal-errors=foo maps foo to Fatal, -Wno-fatal-errors=foo
+ // maps it to Error.
+ Mapping = isPositive ? diag::MAP_FATAL : diag::MAP_ERROR_NO_WFATAL;
+ OptStart = Specifier;
+ }
+
+ if (Diags.setDiagnosticGroupMapping(OptStart, Mapping))
+ Diags.Report(diag::warn_unknown_warning_option) << ("-W" + Opt);
+ }
+}
OpenPOWER on IntegriCloud