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/include/clang/AST/Stmt.h b/include/clang/AST/Stmt.h
index c20d602..2c88ff4 100644
--- a/include/clang/AST/Stmt.h
+++ b/include/clang/AST/Stmt.h
@@ -136,11 +136,22 @@
void operator delete(void*, std::size_t) throw() { }
void operator delete(void*, void*) throw() { }
+public:
+ /// \brief A placeholder type used to construct an empty shell of a
+ /// type, that will be filled in later (e.g., by some
+ /// de-serialization).
+ struct EmptyShell { };
+
protected:
/// DestroyChildren - Invoked by destructors of subclasses of Stmt to
/// recursively release child AST nodes.
void DestroyChildren(ASTContext& Ctx);
+ /// \brief Construct an empty statement.
+ explicit Stmt(StmtClass SC, EmptyShell) : sClass(SC) {
+ if (Stmt::CollectingStats()) Stmt::addStmtClass(SC);
+ }
+
public:
Stmt(StmtClass SC) : sClass(SC) {
if (Stmt::CollectingStats()) Stmt::addStmtClass(SC);
@@ -211,11 +222,6 @@
return const_child_iterator(const_cast<Stmt*>(this)->child_end());
}
- /// \brief A placeholder type used to construct an empty shell of a
- /// type, that will be filled in later (e.g., by some
- /// de-serialization).
- struct EmptyShell { };
-
void Emit(llvm::Serializer& S) const;
static Stmt* Create(llvm::Deserializer& D, ASTContext& C);
@@ -288,7 +294,11 @@
public:
NullStmt(SourceLocation L) : Stmt(NullStmtClass), SemiLoc(L) {}
+ /// \brief Build an empty null statement.
+ explicit NullStmt(EmptyShell Empty) : Stmt(NullStmtClass, Empty) { }
+
SourceLocation getSemiLoc() const { return SemiLoc; }
+ void setSemiLoc(SourceLocation L) { SemiLoc = L; }
virtual SourceRange getSourceRange() const { return SourceRange(SemiLoc); }
@@ -323,9 +333,16 @@
Body = new (C) Stmt*[NumStmts];
memcpy(Body, StmtStart, numStmts * sizeof(*Body));
}
+
+ // \brief Build an empty compound statement.
+ explicit CompoundStmt(EmptyShell Empty)
+ : Stmt(CompoundStmtClass, Empty), Body(0), NumStmts(0) { }
+
+ void setStmts(ASTContext &C, Stmt **Stmts, unsigned NumStmts);
bool body_empty() const { return NumStmts == 0; }
-
+ unsigned size() const { return NumStmts; }
+
typedef Stmt** body_iterator;
body_iterator body_begin() { return Body; }
body_iterator body_end() { return Body + NumStmts; }
@@ -360,7 +377,9 @@
}
SourceLocation getLBracLoc() const { return LBracLoc; }
+ void setLBracLoc(SourceLocation L) { LBracLoc = L; }
SourceLocation getRBracLoc() const { return RBracLoc; }
+ void setRBracLoc(SourceLocation L) { RBracLoc = L; }
static bool classof(const Stmt *T) {
return T->getStmtClass() == CompoundStmtClass;
@@ -418,12 +437,17 @@
SubExprs[RHS] = reinterpret_cast<Stmt*>(rhs);
CaseLoc = caseLoc;
}
-
+
+ /// \brief Build an empty switch case statement.
+ explicit CaseStmt(EmptyShell Empty) : SwitchCase(CaseStmtClass) { }
+
SourceLocation getCaseLoc() const { return CaseLoc; }
-
+ void setCaseLoc(SourceLocation L) { CaseLoc = L; }
+
Expr *getLHS() { return reinterpret_cast<Expr*>(SubExprs[LHS]); }
Expr *getRHS() { return reinterpret_cast<Expr*>(SubExprs[RHS]); }
Stmt *getSubStmt() { return SubExprs[SUBSTMT]; }
+
const Expr *getLHS() const {
return reinterpret_cast<const Expr*>(SubExprs[LHS]);
}
@@ -465,11 +489,16 @@
public:
DefaultStmt(SourceLocation DL, Stmt *substmt) :
SwitchCase(DefaultStmtClass), SubStmt(substmt), DefaultLoc(DL) {}
-
+
+ /// \brief Build an empty default statement.
+ explicit DefaultStmt(EmptyShell) : SwitchCase(DefaultStmtClass) { }
+
Stmt *getSubStmt() { return SubStmt; }
const Stmt *getSubStmt() const { return SubStmt; }
-
+ void setSubStmt(Stmt *S) { SubStmt = S; }
+
SourceLocation getDefaultLoc() const { return DefaultLoc; }
+ void setDefaultLoc(SourceLocation L) { DefaultLoc = L; }
virtual SourceRange getSourceRange() const {
return SourceRange(DefaultLoc, SubStmt->getLocEnd());
@@ -537,14 +566,23 @@
IfLoc = IL;
}
+ /// \brief Build an empty if/then/else statement
+ explicit IfStmt(EmptyShell Empty) : Stmt(IfStmtClass, Empty) { }
+
const Expr *getCond() const { return reinterpret_cast<Expr*>(SubExprs[COND]);}
+ void setCond(Expr *E) { SubExprs[COND] = reinterpret_cast<Stmt *>(E); }
const Stmt *getThen() const { return SubExprs[THEN]; }
+ void setThen(Stmt *S) { SubExprs[THEN] = S; }
const Stmt *getElse() const { return SubExprs[ELSE]; }
+ void setElse(Stmt *S) { SubExprs[ELSE] = S; }
Expr *getCond() { return reinterpret_cast<Expr*>(SubExprs[COND]); }
Stmt *getThen() { return SubExprs[THEN]; }
Stmt *getElse() { return SubExprs[ELSE]; }
+ SourceLocation getIfLoc() const { return IfLoc; }
+ void setIfLoc(SourceLocation L) { IfLoc = L; }
+
virtual SourceRange getSourceRange() const {
if (SubExprs[ELSE])
return SourceRange(IfLoc, SubExprs[ELSE]->getLocEnd());
@@ -579,13 +617,22 @@
SubExprs[BODY] = NULL;
}
+ /// \brief Build a empty switch statement.
+ explicit SwitchStmt(EmptyShell Empty) : Stmt(SwitchStmtClass, Empty) { }
+
const Expr *getCond() const { return reinterpret_cast<Expr*>(SubExprs[COND]);}
const Stmt *getBody() const { return SubExprs[BODY]; }
const SwitchCase *getSwitchCaseList() const { return FirstCase; }
Expr *getCond() { return reinterpret_cast<Expr*>(SubExprs[COND]);}
+ void setCond(Expr *E) { SubExprs[COND] = reinterpret_cast<Stmt *>(E); }
Stmt *getBody() { return SubExprs[BODY]; }
+ void setBody(Stmt *S) { SubExprs[BODY] = S; }
SwitchCase *getSwitchCaseList() { return FirstCase; }
+ void setSwitchCaseList(SwitchCase *SC) { FirstCase = SC; }
+
+ SourceLocation getSwitchLoc() const { return SwitchLoc; }
+ void setSwitchLoc(SourceLocation L) { SwitchLoc = L; }
void setBody(Stmt *S, SourceLocation SL) {
SubExprs[BODY] = S;
@@ -814,6 +861,12 @@
public:
BreakStmt(SourceLocation BL) : Stmt(BreakStmtClass), BreakLoc(BL) {}
+ /// \brief Build an empty break statement.
+ explicit BreakStmt(EmptyShell Empty) : Stmt(BreakStmtClass, Empty) { }
+
+ SourceLocation getBreakLoc() const { return BreakLoc; }
+ void setBreakLoc(SourceLocation L) { BreakLoc = L; }
+
virtual SourceRange getSourceRange() const { return SourceRange(BreakLoc); }
static bool classof(const Stmt *T) {
diff --git a/include/clang/Frontend/PCHBitCodes.h b/include/clang/Frontend/PCHBitCodes.h
index a218a5f..98d27a0 100644
--- a/include/clang/Frontend/PCHBitCodes.h
+++ b/include/clang/Frontend/PCHBitCodes.h
@@ -375,6 +375,20 @@
STMT_STOP,
/// \brief A NULL expression.
STMT_NULL_PTR,
+ /// \brief A NullStmt record.
+ STMT_NULL,
+ /// \brief A CompoundStmt record.
+ STMT_COMPOUND,
+ /// \brief A CaseStmt record.
+ STMT_CASE,
+ /// \brief A DefaultStmt record.
+ STMT_DEFAULT,
+ /// \brief An IfStmt record.
+ STMT_IF,
+ /// \brief A SwitchStmt record.
+ STMT_SWITCH,
+ /// \brief A BreakStmt record.
+ STMT_BREAK,
/// \brief A PredefinedExpr record.
EXPR_PREDEFINED,
/// \brief A DeclRefExpr record.
diff --git a/include/clang/Frontend/PCHReader.h b/include/clang/Frontend/PCHReader.h
index 995a1d5..07531df 100644
--- a/include/clang/Frontend/PCHReader.h
+++ b/include/clang/Frontend/PCHReader.h
@@ -26,6 +26,7 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/Bitcode/BitstreamReader.h"
#include "llvm/Support/DataTypes.h"
+#include <map>
#include <string>
#include <utility>
#include <vector>
@@ -41,6 +42,7 @@
class Decl;
class DeclContext;
class Preprocessor;
+class SwitchCase;
/// \brief Reads a precompiled head containing the contents of a
/// translation unit.
@@ -126,6 +128,10 @@
/// file.
llvm::SmallVector<uint64_t, 16> ExternalDefinitions;
+ /// \brief Mapping from switch-case IDs in the PCH file to
+ /// switch-case statements.
+ std::map<unsigned, SwitchCase *> SwitchCaseStmts;
+
PCHReadResult ReadPCHBlock();
bool CheckPredefinesBuffer(const char *PCHPredef,
unsigned PCHPredefLen,
@@ -241,6 +247,13 @@
/// \brief Retrieve the AST context that this PCH reader
/// supplements.
ASTContext &getContext() { return Context; }
+
+ /// \brief Record that the given ID maps to the given switch-case
+ /// statement.
+ void RecordSwitchCaseID(SwitchCase *SC, unsigned ID);
+
+ /// \brief Retrieve the switch-case statement with the given ID.
+ SwitchCase *getSwitchCaseWithID(unsigned ID);
};
} // end namespace clang
diff --git a/include/clang/Frontend/PCHWriter.h b/include/clang/Frontend/PCHWriter.h
index 4af64e6..5828637 100644
--- a/include/clang/Frontend/PCHWriter.h
+++ b/include/clang/Frontend/PCHWriter.h
@@ -20,6 +20,7 @@
#include "clang/Frontend/PCHBitCodes.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
+#include <map>
#include <queue>
namespace llvm {
@@ -33,6 +34,7 @@
class ASTContext;
class Preprocessor;
class SourceManager;
+class SwitchCase;
class TargetInfo;
/// \brief Writes a precompiled header containing the contents of a
@@ -108,6 +110,9 @@
/// declaration or type.
llvm::SmallVector<Stmt *, 8> StmtsToEmit;
+ /// \brief Mapping from SwitchCase statements to IDs.
+ std::map<SwitchCase *, unsigned> SwitchCaseIDs;
+
void WriteTargetTriple(const TargetInfo &Target);
void WriteLanguageOptions(const LangOptions &LangOpts);
void WriteSourceManagerBlock(SourceManager &SourceMgr);
@@ -170,6 +175,13 @@
/// \brief Flush all of the statements and expressions that have
/// been added to the queue via AddStmt().
void FlushStmts();
+
+ /// \brief Record an ID for the given switch-case statement.
+ unsigned RecordSwitchCaseID(SwitchCase *S);
+
+ /// \brief Retrieve the ID for the given switch-case statement.
+ unsigned getSwitchCaseID(SwitchCase *S);
+
};
} // end namespace clang
diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp
index ce55fae..8e2cf86 100644
--- a/lib/AST/Stmt.cpp
+++ b/lib/AST/Stmt.cpp
@@ -96,6 +96,14 @@
return StatSwitch;
}
+void CompoundStmt::setStmts(ASTContext &C, Stmt **Stmts, unsigned NumStmts) {
+ if (this->Body)
+ C.Deallocate(Body);
+ this->NumStmts = NumStmts;
+
+ Body = new (C) Stmt*[NumStmts];
+ memcpy(Body, Stmts, sizeof(Stmt *) * NumStmts);
+}
const char *LabelStmt::getName() const {
return getID()->getName();
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];
+}
diff --git a/test/PCH/stmts.c b/test/PCH/stmts.c
new file mode 100644
index 0000000..b71db63
--- /dev/null
+++ b/test/PCH/stmts.c
@@ -0,0 +1,8 @@
+// Test this without pch.
+// RUN: clang-cc -fblocks -include %S/stmts.h -fsyntax-only -emit-llvm -o - %s
+
+// Test with pch.
+// RUN: clang-cc -emit-pch -fblocks -o %t %S/stmts.h &&
+// RUN: clang-cc -fblocks -include-pch %t -fsyntax-only -emit-llvm -o - %s
+
+void g0(void) { f0(5); }
diff --git a/test/PCH/stmts.h b/test/PCH/stmts.h
new file mode 100644
index 0000000..ab71c50
--- /dev/null
+++ b/test/PCH/stmts.h
@@ -0,0 +1,22 @@
+// Header for PCH test stmts.c
+
+void f0(int x) {
+ // NullStmt
+ ;
+ // IfStmt
+ if (x) {
+ } else if (x + 1) {
+ }
+
+ switch (x) {
+ case 0:
+ x = 17;
+ break;
+
+ case 1:
+ break;
+
+ default:
+ break;
+ }
+}