PCH support for the first batch of statements, including null,
compound, case, default, if, switch, and break statements.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@69329 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp
index 0f208fb..e39f3e5 100644
--- a/lib/Frontend/PCHReader.cpp
+++ b/lib/Frontend/PCHReader.cpp
@@ -139,7 +139,8 @@
 
 void PCHDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
   VisitValueDecl(FD);
-  // FIXME: function body
+  if (Record[Idx++])
+    FD->setBody(cast<CompoundStmt>(Reader.ReadStmt()));
   FD->setPreviousDeclaration(
                    cast_or_null<FunctionDecl>(Reader.GetDecl(Record[Idx++])));
   FD->setStorageClass((FunctionDecl::StorageClass)Record[Idx++]);
@@ -229,15 +230,28 @@
                   unsigned &Idx, llvm::SmallVectorImpl<Stmt *> &StmtStack)
       : Reader(Reader), Record(Record), Idx(Idx), StmtStack(StmtStack) { }
 
+    /// \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 = 3;
+    static const unsigned NumExprFields = NumStmtFields + 3;
 
     // Each of the Visit* functions reads in part of the expression
     // from the given record and the current expression stack, then
     // return the total number of operands that it read from the
     // expression stack.
 
+    unsigned VisitStmt(Stmt *S);
+    unsigned VisitNullStmt(NullStmt *S);
+    unsigned VisitCompoundStmt(CompoundStmt *S);
+    unsigned VisitSwitchCase(SwitchCase *S);
+    unsigned VisitCaseStmt(CaseStmt *S);
+    unsigned VisitDefaultStmt(DefaultStmt *S);
+    unsigned VisitIfStmt(IfStmt *S);
+    unsigned VisitSwitchStmt(SwitchStmt *S);
+    unsigned VisitBreakStmt(BreakStmt *S);
     unsigned VisitExpr(Expr *E);
     unsigned VisitPredefinedExpr(PredefinedExpr *E);
     unsigned VisitDeclRefExpr(DeclRefExpr *E);
@@ -273,7 +287,83 @@
   };
 }
 
+unsigned PCHStmtReader::VisitStmt(Stmt *S) {
+  assert(Idx == NumStmtFields && "Incorrect statement field count");
+  return 0;
+}
+
+unsigned PCHStmtReader::VisitNullStmt(NullStmt *S) {
+  VisitStmt(S);
+  S->setSemiLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+  return 0;
+}
+
+unsigned PCHStmtReader::VisitCompoundStmt(CompoundStmt *S) {
+  VisitStmt(S);
+  unsigned NumStmts = Record[Idx++];
+  S->setStmts(Reader.getContext(), 
+              &StmtStack[StmtStack.size() - NumStmts], NumStmts);
+  S->setLBracLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+  S->setRBracLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+  return NumStmts;
+}
+
+unsigned PCHStmtReader::VisitSwitchCase(SwitchCase *S) {
+  VisitStmt(S);
+  Reader.RecordSwitchCaseID(S, Record[Idx++]);
+  return 0;
+}
+
+unsigned PCHStmtReader::VisitCaseStmt(CaseStmt *S) {
+  VisitSwitchCase(S);
+  S->setLHS(cast<Expr>(StmtStack[StmtStack.size() - 3]));
+  S->setRHS(cast_or_null<Expr>(StmtStack[StmtStack.size() - 2]));
+  S->setSubStmt(StmtStack.back());
+  S->setCaseLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+  return 3;
+}
+
+unsigned PCHStmtReader::VisitDefaultStmt(DefaultStmt *S) {
+  VisitSwitchCase(S);
+  S->setSubStmt(StmtStack.back());
+  S->setDefaultLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+  return 1;
+}
+
+unsigned PCHStmtReader::VisitIfStmt(IfStmt *S) {
+  VisitStmt(S);
+  S->setCond(cast<Expr>(StmtStack[StmtStack.size() - 3]));
+  S->setThen(StmtStack[StmtStack.size() - 2]);
+  S->setElse(StmtStack[StmtStack.size() - 1]);
+  S->setIfLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+  return 3;
+}
+
+unsigned PCHStmtReader::VisitSwitchStmt(SwitchStmt *S) {
+  VisitStmt(S);
+  S->setCond(cast<Expr>(StmtStack[StmtStack.size() - 2]));
+  S->setBody(StmtStack.back());
+  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);
+    PrevSC = SC;
+  }
+  return 2;
+}
+
+unsigned PCHStmtReader::VisitBreakStmt(BreakStmt *S) {
+  VisitStmt(S);
+  S->setBreakLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+  return 0;
+}
+
 unsigned PCHStmtReader::VisitExpr(Expr *E) {
+  VisitStmt(E);
   E->setType(Reader.GetType(Record[Idx++]));
   E->setTypeDependent(Record[Idx++]);
   E->setValueDependent(Record[Idx++]);
@@ -2002,6 +2092,34 @@
       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_IF:
+      S = new (Context) IfStmt(Empty);
+      break;
+
+    case pch::STMT_SWITCH:
+      S = new (Context) SwitchStmt(Empty);
+      break;
+
+    case pch::STMT_BREAK:
+      S = new (Context) BreakStmt(Empty);
+      break;
+
     case pch::EXPR_PREDEFINED:
       // FIXME: untested (until we can serialize function bodies).
       S = new (Context) PredefinedExpr(Empty);
@@ -2157,3 +2275,16 @@
                                                   Context.getSourceManager()),
                                     DiagID);
 }
+
+/// \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];
+}
diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp
index 056aeec..8f09030 100644
--- a/lib/Frontend/PCHWriter.cpp
+++ b/lib/Frontend/PCHWriter.cpp
@@ -338,7 +338,9 @@
 
 void PCHDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
   VisitValueDecl(D);
-  // FIXME: function body
+  Record.push_back(D->isThisDeclarationADefinition());
+  if (D->isThisDeclarationADefinition())
+    Writer.AddStmt(D->getBody());
   Writer.AddDeclRef(D->getPreviousDeclaration(), Record);
   Record.push_back(D->getStorageClass()); // FIXME: stable encoding
   Record.push_back(D->isInline());
@@ -443,6 +445,15 @@
     PCHStmtWriter(PCHWriter &Writer, PCHWriter::RecordData &Record)
       : Writer(Writer), Record(Record) { }
 
+    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 VisitIfStmt(IfStmt *S);
+    void VisitSwitchStmt(SwitchStmt *S);
+    void VisitBreakStmt(BreakStmt *S);
     void VisitExpr(Expr *E);
     void VisitPredefinedExpr(PredefinedExpr *E);
     void VisitDeclRefExpr(DeclRefExpr *E);
@@ -478,7 +489,75 @@
   };
 }
 
+void PCHStmtWriter::VisitStmt(Stmt *S) { 
+}
+
+void PCHStmtWriter::VisitNullStmt(NullStmt *S) {
+  VisitStmt(S);
+  Writer.AddSourceLocation(S->getSemiLoc(), Record);
+  Code = pch::STMT_NULL;
+}
+
+void PCHStmtWriter::VisitCompoundStmt(CompoundStmt *S) {
+  VisitStmt(S);
+  Record.push_back(S->size());
+  for (CompoundStmt::body_iterator CS = S->body_begin(), CSEnd = S->body_end();
+       CS != CSEnd; ++CS)
+    Writer.WriteSubStmt(*CS);
+  Writer.AddSourceLocation(S->getLBracLoc(), Record);
+  Writer.AddSourceLocation(S->getRBracLoc(), Record);
+  Code = pch::STMT_COMPOUND;
+}
+
+void PCHStmtWriter::VisitSwitchCase(SwitchCase *S) {
+  VisitStmt(S);
+  Record.push_back(Writer.RecordSwitchCaseID(S));
+}
+
+void PCHStmtWriter::VisitCaseStmt(CaseStmt *S) {
+  VisitSwitchCase(S);
+  Writer.WriteSubStmt(S->getLHS());
+  Writer.WriteSubStmt(S->getRHS());
+  Writer.WriteSubStmt(S->getSubStmt());
+  Writer.AddSourceLocation(S->getCaseLoc(), Record);
+  Code = pch::STMT_CASE;
+}
+
+void PCHStmtWriter::VisitDefaultStmt(DefaultStmt *S) {
+  VisitSwitchCase(S);
+  Writer.WriteSubStmt(S->getSubStmt());
+  Writer.AddSourceLocation(S->getDefaultLoc(), Record);
+  Code = pch::STMT_DEFAULT;
+}
+
+void PCHStmtWriter::VisitIfStmt(IfStmt *S) {
+  VisitStmt(S);
+  Writer.WriteSubStmt(S->getCond());
+  Writer.WriteSubStmt(S->getThen());
+  Writer.WriteSubStmt(S->getElse());
+  Writer.AddSourceLocation(S->getIfLoc(), Record);
+  Code = pch::STMT_IF;
+}
+
+void PCHStmtWriter::VisitSwitchStmt(SwitchStmt *S) {
+  VisitStmt(S);
+  Writer.WriteSubStmt(S->getCond());
+  Writer.WriteSubStmt(S->getBody());
+  Writer.AddSourceLocation(S->getSwitchLoc(), Record);
+  for (SwitchCase *SC = S->getSwitchCaseList(); SC; 
+       SC = SC->getNextSwitchCase())
+    Record.push_back(Writer.getSwitchCaseID(SC));
+  Code = pch::STMT_SWITCH;
+}
+
+void PCHStmtWriter::VisitBreakStmt(BreakStmt *S) {
+  VisitStmt(S);
+  Writer.AddSourceLocation(S->getBreakLoc(), Record);
+  Code = pch::STMT_BREAK;
+}
+
 void PCHStmtWriter::VisitExpr(Expr *E) {
+  VisitStmt(E);
   Writer.AddTypeRef(E->getType(), Record);
   Record.push_back(E->isTypeDependent());
   Record.push_back(E->isValueDependent());
@@ -1708,3 +1787,17 @@
 
   StmtsToEmit.clear();
 }
+
+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];
+}